mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 06:04:57 +00:00
LibC: Implement ungetwc()
This commit is contained in:
parent
14b91a3fe9
commit
e717ca32d1
7 changed files with 63 additions and 18 deletions
|
@ -4,9 +4,11 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibC/bits/FILE.h>
|
||||
#include <LibC/bits/pthread_integration.h>
|
||||
#include <LibC/bits/wchar.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#pragma once
|
||||
|
@ -85,6 +87,9 @@ private:
|
|||
bool enqueue_front(u8 byte);
|
||||
|
||||
private:
|
||||
constexpr static auto unget_buffer_size = MB_CUR_MAX;
|
||||
constexpr static u32 ungotten_mask = ((u32)0xffffffff) >> (sizeof(u32) * 8 - unget_buffer_size);
|
||||
|
||||
// Note: the fields here are arranged this way
|
||||
// to make sizeof(Buffer) smaller.
|
||||
u8* m_data { nullptr };
|
||||
|
@ -93,8 +98,8 @@ private:
|
|||
size_t m_end { 0 };
|
||||
|
||||
int m_mode { -1 };
|
||||
u8 m_unget_buffer { 0 };
|
||||
bool m_ungotten : 1 { false };
|
||||
Array<u8, unget_buffer_size> m_unget_buffer { 0 };
|
||||
u32 m_ungotten : unget_buffer_size { 0 };
|
||||
bool m_data_is_malloced : 1 { false };
|
||||
// When m_begin == m_end, we want to distinguish whether
|
||||
// the buffer is full or empty.
|
||||
|
|
10
Userland/Libraries/LibC/bits/wchar.h
Normal file
10
Userland/Libraries/LibC/bits/wchar.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MB_CUR_MAX 4
|
||||
#define MB_LEN_MAX 16
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <bits/stdint.h>
|
||||
#include <bits/wchar.h>
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
# define PAGE_SIZE 4096
|
||||
|
@ -73,8 +74,6 @@
|
|||
#define LLONG_WIDTH 64
|
||||
#define ULLONG_WIDTH 64
|
||||
|
||||
#define MB_LEN_MAX 16
|
||||
|
||||
#define ARG_MAX 65536
|
||||
|
||||
#define PTHREAD_STACK_MIN 65536
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/BuiltinWrappers.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/PrintfImplementation.h>
|
||||
#include <AK/ScopedValueRollback.h>
|
||||
|
@ -351,7 +352,7 @@ FILE::Buffer::~Buffer()
|
|||
|
||||
bool FILE::Buffer::may_use() const
|
||||
{
|
||||
return m_ungotten || m_mode != _IONBF;
|
||||
return m_ungotten != 0u || m_mode != _IONBF;
|
||||
}
|
||||
|
||||
void FILE::Buffer::realize(int fd)
|
||||
|
@ -384,7 +385,7 @@ void FILE::Buffer::drop()
|
|||
}
|
||||
m_begin = m_end = 0;
|
||||
m_empty = true;
|
||||
m_ungotten = false;
|
||||
m_ungotten = 0u;
|
||||
}
|
||||
|
||||
size_t FILE::Buffer::buffered_size() const
|
||||
|
@ -402,9 +403,10 @@ size_t FILE::Buffer::buffered_size() const
|
|||
|
||||
const u8* FILE::Buffer::begin_dequeue(size_t& available_size) const
|
||||
{
|
||||
if (m_ungotten) {
|
||||
available_size = 1;
|
||||
return &m_unget_buffer;
|
||||
if (m_ungotten != 0u) {
|
||||
auto available_bytes = count_trailing_zeroes(m_ungotten) + 1;
|
||||
available_size = available_bytes;
|
||||
return &m_unget_buffer[unget_buffer_size - available_bytes];
|
||||
}
|
||||
|
||||
if (m_empty) {
|
||||
|
@ -424,9 +426,10 @@ void FILE::Buffer::did_dequeue(size_t actual_size)
|
|||
{
|
||||
VERIFY(actual_size > 0);
|
||||
|
||||
if (m_ungotten) {
|
||||
VERIFY(actual_size == 1);
|
||||
m_ungotten = false;
|
||||
if (m_ungotten != 0u) {
|
||||
VERIFY(actual_size <= static_cast<size_t>(popcount(m_ungotten & ungotten_mask)));
|
||||
auto available_bytes = count_trailing_zeroes(m_ungotten);
|
||||
m_ungotten &= (0xffffffffu << (actual_size + available_bytes));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -476,13 +479,21 @@ void FILE::Buffer::did_enqueue(size_t actual_size)
|
|||
|
||||
bool FILE::Buffer::enqueue_front(u8 byte)
|
||||
{
|
||||
if (m_ungotten) {
|
||||
// Sorry, the place is already taken!
|
||||
return false;
|
||||
size_t placement_index;
|
||||
if (m_ungotten == 0u) {
|
||||
placement_index = 3u;
|
||||
m_ungotten = 1u;
|
||||
} else {
|
||||
auto first_zero_index = count_trailing_zeroes(bit_cast<u32>(~m_ungotten)); // Thanks C.
|
||||
if (first_zero_index >= unget_buffer_size) {
|
||||
// Sorry, the place is already taken!
|
||||
return false;
|
||||
}
|
||||
placement_index = unget_buffer_size - first_zero_index - 1;
|
||||
m_ungotten |= (1 << first_zero_index);
|
||||
}
|
||||
|
||||
m_ungotten = true;
|
||||
m_unget_buffer = byte;
|
||||
m_unget_buffer[placement_index] = byte;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <bits/wchar.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -14,7 +15,6 @@ __BEGIN_DECLS
|
|||
|
||||
#define EXIT_SUCCESS 0
|
||||
#define EXIT_FAILURE 1
|
||||
#define MB_CUR_MAX 4
|
||||
|
||||
__attribute__((noreturn)) void _abort();
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ wint_t putwc(wchar_t wc, FILE* stream);
|
|||
wint_t putwchar(wchar_t wc);
|
||||
wchar_t* fgetws(wchar_t* __restrict ws, int n, FILE* __restrict stream);
|
||||
int fputws(const wchar_t* __restrict ws, FILE* __restrict stream);
|
||||
wint_t ungetwc(wint_t wc, FILE* stream);
|
||||
int fwide(FILE* stream, int mode);
|
||||
|
||||
int wprintf(const wchar_t* __restrict format, ...);
|
||||
|
|
|
@ -120,6 +120,25 @@ int fputws(wchar_t const* __restrict ws, FILE* __restrict stream)
|
|||
return size;
|
||||
}
|
||||
|
||||
wint_t ungetwc(wint_t wc, FILE* stream)
|
||||
{
|
||||
VERIFY(stream);
|
||||
ScopedFileLock lock(stream);
|
||||
StringBuilder sb;
|
||||
sb.append_code_point(static_cast<u32>(wc));
|
||||
auto bytes = sb.string_view().bytes();
|
||||
size_t ok_bytes = 0;
|
||||
for (auto byte : bytes) {
|
||||
if (!stream->ungetc(byte)) {
|
||||
// Discard the half-ungotten bytes.
|
||||
stream->read(const_cast<u8*>(bytes.data()), ok_bytes);
|
||||
return WEOF;
|
||||
}
|
||||
++ok_bytes;
|
||||
}
|
||||
return wc;
|
||||
}
|
||||
|
||||
int wprintf(wchar_t const* __restrict format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue