mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-13 13:02:28 +00:00
Libraries: Remove some Serenity-only interface implementations
This commit is contained in:
parent
126cbce632
commit
edb527e04d
Notes:
sideshowbarker
2024-07-17 07:20:57 +09:00
Author: https://github.com/trflynn89
Commit: edb527e04d
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/35
5 changed files with 11 additions and 527 deletions
|
@ -16,13 +16,6 @@ set(SOURCES
|
||||||
|
|
||||||
serenity_lib(LibCoreMinimal coreminimal)
|
serenity_lib(LibCoreMinimal coreminimal)
|
||||||
|
|
||||||
if (SERENITYOS)
|
|
||||||
add_library(DynamicLoader_LibCoreArgsParser
|
|
||||||
ArgsParser.cpp
|
|
||||||
Version.cpp)
|
|
||||||
target_link_libraries(DynamicLoader_LibCoreArgsParser PUBLIC DynamicLoader_CompileOptions)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
AnonymousBuffer.cpp
|
AnonymousBuffer.cpp
|
||||||
Command.cpp
|
Command.cpp
|
||||||
|
@ -65,12 +58,7 @@ if (NOT WIN32 AND NOT EMSCRIPTEN)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# FIXME: Implement Core::FileWatcher for *BSD and Windows.
|
# FIXME: Implement Core::FileWatcher for *BSD and Windows.
|
||||||
if (SERENITYOS)
|
if (LINUX AND NOT EMSCRIPTEN)
|
||||||
list(APPEND SOURCES
|
|
||||||
FileWatcherSerenity.cpp
|
|
||||||
Platform/ProcessStatisticsSerenity.cpp
|
|
||||||
)
|
|
||||||
elseif (LINUX AND NOT EMSCRIPTEN)
|
|
||||||
list(APPEND SOURCES
|
list(APPEND SOURCES
|
||||||
FileWatcherLinux.cpp
|
FileWatcherLinux.cpp
|
||||||
Platform/ProcessStatisticsLinux.cpp
|
Platform/ProcessStatisticsLinux.cpp
|
||||||
|
|
|
@ -1,222 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
|
|
||||||
* Copyright (c) 2021, the SerenityOS developers.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "FileWatcher.h"
|
|
||||||
#include <AK/ByteString.h>
|
|
||||||
#include <AK/Debug.h>
|
|
||||||
#include <AK/LexicalPath.h>
|
|
||||||
#include <AK/NonnullRefPtr.h>
|
|
||||||
#include <Kernel/API/InodeWatcherEvent.h>
|
|
||||||
#include <Kernel/API/InodeWatcherFlags.h>
|
|
||||||
#include <LibCore/Notifier.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#if !defined(AK_OS_SERENITY)
|
|
||||||
static_assert(false, "This file must only be used for SerenityOS");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
|
|
||||||
static constexpr unsigned file_watcher_flags_to_inode_watcher_flags(FileWatcherFlags flags)
|
|
||||||
{
|
|
||||||
auto result = InodeWatcherFlags::None;
|
|
||||||
|
|
||||||
if (has_flag(flags, FileWatcherFlags::Nonblock))
|
|
||||||
result |= InodeWatcherFlags::Nonblock;
|
|
||||||
if (has_flag(flags, FileWatcherFlags::CloseOnExec))
|
|
||||||
result |= InodeWatcherFlags::CloseOnExec;
|
|
||||||
|
|
||||||
return static_cast<unsigned>(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Optional<FileWatcherEvent> get_event_from_fd(int fd, HashMap<unsigned, ByteString> const& wd_to_path)
|
|
||||||
{
|
|
||||||
u8 buffer[MAXIMUM_EVENT_SIZE];
|
|
||||||
int rc = read(fd, &buffer, MAXIMUM_EVENT_SIZE);
|
|
||||||
if (rc == 0) {
|
|
||||||
return {};
|
|
||||||
} else if (rc < 0) {
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "get_event_from_fd: Reading from wd {} failed: {}", fd, strerror(errno));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
InodeWatcherEvent* event = reinterpret_cast<InodeWatcherEvent*>(buffer);
|
|
||||||
FileWatcherEvent result;
|
|
||||||
|
|
||||||
auto it = wd_to_path.find(event->watch_descriptor);
|
|
||||||
if (it == wd_to_path.end()) {
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "get_event_from_fd: Got an event for a non-existent wd {}?!", event->watch_descriptor);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
ByteString const& path = it->value;
|
|
||||||
|
|
||||||
switch (event->type) {
|
|
||||||
case InodeWatcherEvent::Type::ChildCreated:
|
|
||||||
result.type = FileWatcherEvent::Type::ChildCreated;
|
|
||||||
break;
|
|
||||||
case InodeWatcherEvent::Type::ChildDeleted:
|
|
||||||
result.type = FileWatcherEvent::Type::ChildDeleted;
|
|
||||||
break;
|
|
||||||
case InodeWatcherEvent::Type::Deleted:
|
|
||||||
result.type = FileWatcherEvent::Type::Deleted;
|
|
||||||
break;
|
|
||||||
case InodeWatcherEvent::Type::ContentModified:
|
|
||||||
result.type = FileWatcherEvent::Type::ContentModified;
|
|
||||||
break;
|
|
||||||
case InodeWatcherEvent::Type::MetadataModified:
|
|
||||||
result.type = FileWatcherEvent::Type::MetadataModified;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
warnln("Unknown event type {} returned by the watch_file descriptor for {}", static_cast<unsigned>(event->type), path);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// We trust that the kernel only sends the name when appropriate.
|
|
||||||
if (event->name_length > 0) {
|
|
||||||
ByteString child_name { event->name, event->name_length - 1 };
|
|
||||||
result.event_path = LexicalPath::join(path, child_name).string();
|
|
||||||
} else {
|
|
||||||
result.event_path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "get_event_from_fd: got event from wd {} on '{}' type {}", fd, result.event_path, result.type);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ByteString canonicalize_path(ByteString path)
|
|
||||||
{
|
|
||||||
if (!path.is_empty() && path[0] == '/')
|
|
||||||
return LexicalPath::canonicalized_path(move(path));
|
|
||||||
char* cwd = getcwd(nullptr, 0);
|
|
||||||
VERIFY(cwd);
|
|
||||||
return LexicalPath::join({ cwd, strlen(cwd) }, move(path)).string();
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<bool> FileWatcherBase::add_watch(ByteString path, FileWatcherEvent::Type event_mask)
|
|
||||||
{
|
|
||||||
ByteString canonical_path = canonicalize_path(move(path));
|
|
||||||
|
|
||||||
if (m_path_to_wd.find(canonical_path) != m_path_to_wd.end()) {
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "add_watch: path '{}' is already being watched", canonical_path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto kernel_mask = InodeWatcherEvent::Type::Invalid;
|
|
||||||
if (has_flag(event_mask, FileWatcherEvent::Type::ChildCreated))
|
|
||||||
kernel_mask |= InodeWatcherEvent::Type::ChildCreated;
|
|
||||||
if (has_flag(event_mask, FileWatcherEvent::Type::ChildDeleted))
|
|
||||||
kernel_mask |= InodeWatcherEvent::Type::ChildDeleted;
|
|
||||||
if (has_flag(event_mask, FileWatcherEvent::Type::Deleted))
|
|
||||||
kernel_mask |= InodeWatcherEvent::Type::Deleted;
|
|
||||||
if (has_flag(event_mask, FileWatcherEvent::Type::ContentModified))
|
|
||||||
kernel_mask |= InodeWatcherEvent::Type::ContentModified;
|
|
||||||
if (has_flag(event_mask, FileWatcherEvent::Type::MetadataModified))
|
|
||||||
kernel_mask |= InodeWatcherEvent::Type::MetadataModified;
|
|
||||||
|
|
||||||
int wd = inode_watcher_add_watch(m_watcher_fd, canonical_path.characters(), canonical_path.length(), static_cast<unsigned>(kernel_mask));
|
|
||||||
if (wd < 0)
|
|
||||||
return Error::from_errno(errno);
|
|
||||||
|
|
||||||
m_path_to_wd.set(canonical_path, wd);
|
|
||||||
m_wd_to_path.set(wd, canonical_path);
|
|
||||||
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "add_watch: watching path '{}' on InodeWatcher {} wd {}", canonical_path, m_watcher_fd, wd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<bool> FileWatcherBase::remove_watch(ByteString path)
|
|
||||||
{
|
|
||||||
ByteString canonical_path = canonicalize_path(move(path));
|
|
||||||
|
|
||||||
auto it = m_path_to_wd.find(canonical_path);
|
|
||||||
if (it == m_path_to_wd.end()) {
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "remove_watch: path '{}' is not being watched", canonical_path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inode_watcher_remove_watch(m_watcher_fd, it->value) < 0)
|
|
||||||
return Error::from_errno(errno);
|
|
||||||
|
|
||||||
m_path_to_wd.remove(it);
|
|
||||||
m_wd_to_path.remove(it->value);
|
|
||||||
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "remove_watch: stopped watching path '{}' on InodeWatcher {}", canonical_path, m_watcher_fd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockingFileWatcher::BlockingFileWatcher(FileWatcherFlags flags)
|
|
||||||
: FileWatcherBase(create_inode_watcher(file_watcher_flags_to_inode_watcher_flags(flags)))
|
|
||||||
{
|
|
||||||
VERIFY(m_watcher_fd != -1);
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "BlockingFileWatcher created with InodeWatcher {}", m_watcher_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockingFileWatcher::~BlockingFileWatcher()
|
|
||||||
{
|
|
||||||
close(m_watcher_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<FileWatcherEvent> BlockingFileWatcher::wait_for_event()
|
|
||||||
{
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "BlockingFileWatcher::wait_for_event()");
|
|
||||||
|
|
||||||
auto maybe_event = get_event_from_fd(m_watcher_fd, m_wd_to_path);
|
|
||||||
if (!maybe_event.has_value())
|
|
||||||
return maybe_event;
|
|
||||||
|
|
||||||
auto event = maybe_event.release_value();
|
|
||||||
if (event.type == FileWatcherEvent::Type::Deleted) {
|
|
||||||
auto result = remove_watch(event.event_path);
|
|
||||||
if (result.is_error()) {
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "wait_for_event: {}", result.error());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<FileWatcher>> FileWatcher::create(FileWatcherFlags flags)
|
|
||||||
{
|
|
||||||
auto watcher_fd = create_inode_watcher(file_watcher_flags_to_inode_watcher_flags(flags | FileWatcherFlags::CloseOnExec));
|
|
||||||
if (watcher_fd < 0)
|
|
||||||
return Error::from_errno(errno);
|
|
||||||
|
|
||||||
auto notifier = Notifier::construct(watcher_fd, Notifier::Type::Read);
|
|
||||||
return adopt_ref(*new FileWatcher(watcher_fd, move(notifier)));
|
|
||||||
}
|
|
||||||
|
|
||||||
FileWatcher::FileWatcher(int watcher_fd, NonnullRefPtr<Notifier> notifier)
|
|
||||||
: FileWatcherBase(watcher_fd)
|
|
||||||
, m_notifier(move(notifier))
|
|
||||||
{
|
|
||||||
m_notifier->on_activation = [this] {
|
|
||||||
auto maybe_event = get_event_from_fd(m_notifier->fd(), m_wd_to_path);
|
|
||||||
if (maybe_event.has_value()) {
|
|
||||||
auto event = maybe_event.value();
|
|
||||||
on_change(event);
|
|
||||||
|
|
||||||
if (event.type == FileWatcherEvent::Type::Deleted) {
|
|
||||||
auto result = remove_watch(event.event_path);
|
|
||||||
if (result.is_error()) {
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "on_ready_to_read: {}", result.error());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
FileWatcher::~FileWatcher()
|
|
||||||
{
|
|
||||||
m_notifier->on_activation = nullptr;
|
|
||||||
close(m_notifier->fd());
|
|
||||||
dbgln_if(FILE_WATCHER_DEBUG, "Stopped watcher at fd {}", m_notifier->fd());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <AK/Platform.h>
|
|
||||||
|
|
||||||
#if !defined(AK_OS_SERENITY)
|
|
||||||
# error "This file is for Serenity OS only"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <LibCore/File.h>
|
|
||||||
#include <LibCore/Platform/ProcessStatistics.h>
|
|
||||||
#include <LibCore/ProcessStatisticsReader.h>
|
|
||||||
|
|
||||||
namespace Core::Platform {
|
|
||||||
|
|
||||||
ErrorOr<void> update_process_statistics(ProcessStatistics& statistics)
|
|
||||||
{
|
|
||||||
static auto proc_all_file = TRY(Core::File::open("/sys/kernel/processes"sv, Core::File::OpenMode::Read));
|
|
||||||
|
|
||||||
auto const all_processes = TRY(Core::ProcessStatisticsReader::get_all(*proc_all_file, false));
|
|
||||||
|
|
||||||
auto const total_time_scheduled = all_processes.total_time_scheduled;
|
|
||||||
auto const total_time_scheduled_diff = total_time_scheduled - statistics.total_time_scheduled;
|
|
||||||
statistics.total_time_scheduled = total_time_scheduled;
|
|
||||||
|
|
||||||
for (auto& process : statistics.processes) {
|
|
||||||
auto it = all_processes.processes.find_if([&](auto& entry) { return entry.pid == process->pid; });
|
|
||||||
if (!it.is_end()) {
|
|
||||||
process->memory_usage_bytes = it->amount_resident;
|
|
||||||
|
|
||||||
u64 time_process = 0;
|
|
||||||
for (auto& thread : it->threads) {
|
|
||||||
time_process += thread.time_user + thread.time_kernel;
|
|
||||||
}
|
|
||||||
u64 time_scheduled_diff = time_process - process->time_spent_in_process;
|
|
||||||
|
|
||||||
process->time_spent_in_process = time_process;
|
|
||||||
process->cpu_percent = 0.0;
|
|
||||||
if (total_time_scheduled_diff > 0) {
|
|
||||||
process->cpu_percent = static_cast<float>((time_scheduled_diff * 1000) / total_time_scheduled_diff) / 10.0f;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
process->memory_usage_bytes = 0;
|
|
||||||
process->cpu_percent = 0.0;
|
|
||||||
process->time_spent_in_process = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,221 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
|
||||||
#include <AK/StringBuilder.h>
|
|
||||||
#include <AK/Variant.h>
|
|
||||||
#include <LibRegex/Regex.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef AK_OS_SERENITY
|
|
||||||
# error "This file is intended for use on Serenity only to implement POSIX regex.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct internal_regex_t {
|
|
||||||
u8 cflags;
|
|
||||||
u8 eflags;
|
|
||||||
Optional<Variant<NonnullOwnPtr<Regex<PosixExtended>>, NonnullOwnPtr<Regex<PosixBasic>>>> re;
|
|
||||||
size_t re_pat_errpos;
|
|
||||||
ReError re_pat_err;
|
|
||||||
ByteString re_pat;
|
|
||||||
};
|
|
||||||
|
|
||||||
static internal_regex_t* impl_from(regex_t* re)
|
|
||||||
{
|
|
||||||
if (!re)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return reinterpret_cast<internal_regex_t*>(re->__data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static internal_regex_t const* impl_from(regex_t const* re)
|
|
||||||
{
|
|
||||||
return impl_from(const_cast<regex_t*>(re));
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
int regcomp(regex_t* reg, char const* pattern, int cflags)
|
|
||||||
{
|
|
||||||
if (!reg)
|
|
||||||
return REG_ESPACE;
|
|
||||||
|
|
||||||
// Note that subsequent uses of regcomp() without regfree() _will_ leak memory
|
|
||||||
// This could've been prevented if libc provided a reginit() or similar, but it does not.
|
|
||||||
reg->__data = new internal_regex_t { 0, 0, {}, 0, ReError::REG_NOERR, {} };
|
|
||||||
|
|
||||||
auto* preg = impl_from(reg);
|
|
||||||
bool is_extended = cflags & REG_EXTENDED;
|
|
||||||
|
|
||||||
preg->cflags = cflags;
|
|
||||||
|
|
||||||
ByteString pattern_str(pattern);
|
|
||||||
if (is_extended)
|
|
||||||
preg->re = make<Regex<PosixExtended>>(pattern_str, PosixOptions {} | (PosixFlags)cflags | PosixFlags::SkipTrimEmptyMatches);
|
|
||||||
else
|
|
||||||
preg->re = make<Regex<PosixBasic>>(pattern_str, PosixOptions {} | (PosixFlags)cflags | PosixFlags::SkipTrimEmptyMatches);
|
|
||||||
|
|
||||||
auto parser_result = preg->re->visit([](auto& re) { return re->parser_result; });
|
|
||||||
|
|
||||||
if (parser_result.error != regex::Error::NoError) {
|
|
||||||
preg->re_pat_errpos = parser_result.error_token.position();
|
|
||||||
preg->re_pat_err = (ReError)parser_result.error;
|
|
||||||
preg->re_pat = pattern;
|
|
||||||
|
|
||||||
dbgln("Have Error: {}", (int)parser_result.error);
|
|
||||||
|
|
||||||
return (ReError)parser_result.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
reg->re_nsub = parser_result.capture_groups_count;
|
|
||||||
|
|
||||||
return REG_NOERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
int regexec(regex_t const* reg, char const* string, size_t nmatch, regmatch_t pmatch[], int eflags)
|
|
||||||
{
|
|
||||||
auto const* preg = impl_from(reg);
|
|
||||||
|
|
||||||
if (!preg->re.has_value() || preg->re_pat_err) {
|
|
||||||
if (preg->re_pat_err)
|
|
||||||
return preg->re_pat_err;
|
|
||||||
return REG_BADPAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegexResult result;
|
|
||||||
StringView string_view { string, strlen(string) };
|
|
||||||
if (eflags & REG_SEARCH)
|
|
||||||
result = preg->re->visit([&](auto& re) { return re->search(string_view, PosixOptions {} | (PosixFlags)eflags); });
|
|
||||||
else
|
|
||||||
result = preg->re->visit([&](auto& re) { return re->match(string_view, PosixOptions {} | (PosixFlags)eflags); });
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
auto capture_groups_count = preg->re->visit([](auto& re) { return re->parser_result.capture_groups_count; });
|
|
||||||
auto size = result.matches.size();
|
|
||||||
if (size && nmatch && pmatch) {
|
|
||||||
pmatch[0].rm_cnt = size;
|
|
||||||
|
|
||||||
size_t match_index { 0 };
|
|
||||||
for (size_t i = 0; i < size; ++i) {
|
|
||||||
pmatch[match_index].rm_so = result.matches.at(i).global_offset;
|
|
||||||
pmatch[match_index].rm_eo = pmatch[match_index].rm_so + result.matches.at(i).view.length();
|
|
||||||
if (match_index > 0)
|
|
||||||
pmatch[match_index].rm_cnt = result.capture_group_matches.size();
|
|
||||||
|
|
||||||
++match_index;
|
|
||||||
if (match_index >= nmatch)
|
|
||||||
return REG_NOERR;
|
|
||||||
|
|
||||||
if (i < result.capture_group_matches.size()) {
|
|
||||||
auto capture_groups_size = result.capture_group_matches.at(i).size();
|
|
||||||
for (size_t j = 0; j < capture_groups_count; ++j) {
|
|
||||||
if (j >= capture_groups_size || !result.capture_group_matches.at(i).at(j).view.length()) {
|
|
||||||
pmatch[match_index].rm_so = -1;
|
|
||||||
pmatch[match_index].rm_eo = -1;
|
|
||||||
pmatch[match_index].rm_cnt = 0;
|
|
||||||
} else {
|
|
||||||
pmatch[match_index].rm_so = result.capture_group_matches.at(i).at(j).global_offset;
|
|
||||||
pmatch[match_index].rm_eo = pmatch[match_index].rm_so + result.capture_group_matches.at(i).at(j).view.length();
|
|
||||||
pmatch[match_index].rm_cnt = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
++match_index;
|
|
||||||
if (match_index >= nmatch)
|
|
||||||
return REG_NOERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match_index < nmatch) {
|
|
||||||
for (size_t i = match_index; i < nmatch; ++i) {
|
|
||||||
pmatch[i].rm_so = -1;
|
|
||||||
pmatch[i].rm_eo = -1;
|
|
||||||
pmatch[i].rm_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return REG_NOERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nmatch && pmatch) {
|
|
||||||
pmatch[0].rm_so = -1;
|
|
||||||
pmatch[0].rm_eo = -1;
|
|
||||||
pmatch[0].rm_cnt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return REG_NOMATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
static StringView get_error(ReError errcode)
|
|
||||||
{
|
|
||||||
switch (errcode) {
|
|
||||||
case REG_NOERR:
|
|
||||||
return "No error"sv;
|
|
||||||
case REG_NOMATCH:
|
|
||||||
return "regexec() failed to match."sv;
|
|
||||||
case REG_BADPAT:
|
|
||||||
return "Invalid regular expression."sv;
|
|
||||||
case REG_ECOLLATE:
|
|
||||||
return "Invalid collating element referenced."sv;
|
|
||||||
case REG_ECTYPE:
|
|
||||||
return "Invalid character class type referenced."sv;
|
|
||||||
case REG_EESCAPE:
|
|
||||||
return "Trailing \\ in pattern."sv;
|
|
||||||
case REG_ESUBREG:
|
|
||||||
return "Number in \\digit invalid or in error."sv;
|
|
||||||
case REG_EBRACK:
|
|
||||||
return "[ ] imbalance."sv;
|
|
||||||
case REG_EPAREN:
|
|
||||||
return "\\( \\) or ( ) imbalance."sv;
|
|
||||||
case REG_EBRACE:
|
|
||||||
return "\\{ \\} imbalance."sv;
|
|
||||||
case REG_BADBR:
|
|
||||||
return "Content of \\{ \\} invalid: not a number, number too large, more than two numbers, first larger than second."sv;
|
|
||||||
case REG_ERANGE:
|
|
||||||
return "Invalid endpoint in range expression."sv;
|
|
||||||
case REG_ESPACE:
|
|
||||||
return "Out of memory."sv;
|
|
||||||
case REG_BADRPT:
|
|
||||||
return "?, * or + not preceded by valid regular expression."sv;
|
|
||||||
case REG_ENOSYS:
|
|
||||||
return "The implementation does not support the function."sv;
|
|
||||||
case REG_EMPTY_EXPR:
|
|
||||||
return "Empty expression provided"sv;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t regerror(int errcode, regex_t const* reg, char* errbuf, size_t errbuf_size)
|
|
||||||
{
|
|
||||||
ByteString error;
|
|
||||||
auto const* preg = impl_from(reg);
|
|
||||||
|
|
||||||
if (!preg)
|
|
||||||
error = get_error((ReError)errcode);
|
|
||||||
else
|
|
||||||
error = preg->re->visit([&](auto& re) { return re->error_string(get_error(preg->re_pat_err)); });
|
|
||||||
|
|
||||||
if (!errbuf_size)
|
|
||||||
return error.length();
|
|
||||||
|
|
||||||
if (!error.copy_characters_to_buffer(errbuf, errbuf_size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return error.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
void regfree(regex_t* reg)
|
|
||||||
{
|
|
||||||
auto* preg = impl_from(reg);
|
|
||||||
if (preg) {
|
|
||||||
delete preg;
|
|
||||||
reg->__data = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,10 +21,6 @@ set(SOURCES
|
||||||
|
|
||||||
set(GENERATED_SOURCES ${CURRENT_LIB_GENERATED})
|
set(GENERATED_SOURCES ${CURRENT_LIB_GENERATED})
|
||||||
|
|
||||||
if (SERENITYOS)
|
|
||||||
list(APPEND SOURCES OutOfProcessWebView.cpp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
embed_as_string_view(
|
embed_as_string_view(
|
||||||
"NativeStyleSheetSource.cpp"
|
"NativeStyleSheetSource.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Native.css"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Native.css"
|
||||||
|
@ -53,18 +49,16 @@ serenity_lib(LibWebView webview)
|
||||||
target_link_libraries(LibWebView PRIVATE LibCore LibFileSystem LibGfx LibIPC LibProtocol LibJS LibWeb LibSQL LibUnicode LibURL)
|
target_link_libraries(LibWebView PRIVATE LibCore LibFileSystem LibGfx LibIPC LibProtocol LibJS LibWeb LibSQL LibUnicode LibURL)
|
||||||
target_compile_definitions(LibWebView PRIVATE ENABLE_PUBLIC_SUFFIX=$<BOOL:${ENABLE_PUBLIC_SUFFIX_DOWNLOAD}>)
|
target_compile_definitions(LibWebView PRIVATE ENABLE_PUBLIC_SUFFIX=$<BOOL:${ENABLE_PUBLIC_SUFFIX_DOWNLOAD}>)
|
||||||
|
|
||||||
if (NOT SERENITYOS)
|
foreach(header ${GENERATED_SOURCES})
|
||||||
foreach(header ${GENERATED_SOURCES})
|
get_filename_component(extension ${header} EXT)
|
||||||
get_filename_component(extension ${header} EXT)
|
if (NOT "${extension}" STREQUAL ".h")
|
||||||
if (NOT "${extension}" STREQUAL ".h")
|
continue()
|
||||||
continue()
|
endif()
|
||||||
endif()
|
|
||||||
|
|
||||||
get_filename_component(subdirectory ${header} DIRECTORY)
|
get_filename_component(subdirectory ${header} DIRECTORY)
|
||||||
string(REGEX REPLACE "^\\.\\./\\.\\./" "" subdirectory "${subdirectory}")
|
string(REGEX REPLACE "^\\.\\./\\.\\./" "" subdirectory "${subdirectory}")
|
||||||
|
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${header}" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${subdirectory}")
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${header}" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${subdirectory}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
install(FILES "${SERENITY_PROJECT_ROOT}/Userland/Services/RequestServer/ConnectionCache.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/RequestServer")
|
install(FILES "${SERENITY_PROJECT_ROOT}/Userland/Services/RequestServer/ConnectionCache.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/RequestServer")
|
||||||
endif()
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue