From b8345246dcc2121bcb6d1515a9341789de20199f Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Sun, 27 Oct 2024 09:04:05 -0500 Subject: First crack at file objects. --- source/fud_assert.cpp | 32 +++++++- source/fud_file.cpp | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++ source/fud_string.cpp | 30 ++++++++ 3 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 source/fud_file.cpp (limited to 'source') diff --git a/source/fud_assert.cpp b/source/fud_assert.cpp index 0c4d7cf..a7c9d76 100644 --- a/source/fud_assert.cpp +++ b/source/fud_assert.cpp @@ -1,11 +1,27 @@ +/* + * libfud + * Copyright 2024 Dominick Allen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "fud_assert.hpp" #include "fud_format.hpp" -#include "fud_string.hpp" +#include "fud_string.hpp" // DrainResult +#include "fud_string_view.hpp" -#include #include -#include namespace fud { @@ -24,6 +40,7 @@ DrainResult BufferSink::drain(StringView source) result.status = FudStatus::Success; return result; } + /* TODO: give users control over this functionality */ result.bytesWritten = fwrite(reinterpret_cast(source.m_data), 1, source.m_length, stderr); if (result.bytesWritten != source.m_length) { result.status = FudStatus::Full; @@ -43,7 +60,14 @@ void assertFailMessage(const char* assertion, const std::source_location sourceL if (functionName == nullptr) { functionName = "Unknown Function"; } - format(sink, FormatCharMode::Unchecked, "{}:{}:{}: {}\n", fileName, functionName, sourceLocation.line(), assertion); + static_cast(format( + sink, + FormatCharMode::Unchecked, + "{}:{}:{}: {}\n", + fileName, + functionName, + sourceLocation.line(), + assertion)); } } // namespace impl diff --git a/source/fud_file.cpp b/source/fud_file.cpp new file mode 100644 index 0000000..e27a46d --- /dev/null +++ b/source/fud_file.cpp @@ -0,0 +1,201 @@ +/* + * libfud + * Copyright 2024 Dominick Allen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fud_file.hpp" + +#include +#include +#include +#include +#include +#include + +namespace fud { + +FileResult RegularFile::open( + StringView filename, + FileAccessMode mode, + OpenFlags flags, + Option dirFdOption, + Allocator* allocator) +{ + if (allocator == nullptr) { + return FudStatus::NullPointer; + } + + if (!filename.nullTerminated()) { + return FudStatus::ArgumentInvalid; + } + + int dirFd = dirFdOption.valueOr(AT_FDCWD); + + RegularFile file{}; + + uint32_t openFlags = 0; + switch (mode) { + case FileAccessMode::Read: + openFlags = O_RDONLY; + break; + case FileAccessMode::Write: + openFlags = O_WRONLY; + break; + case FileAccessMode::ReadWrite: + openFlags = O_RDWR; + break; + default: + return FudStatus::ArgumentInvalid; + } + + if (flags.hasFlag(OpenFlagEnum::Append) && flags.hasFlag(OpenFlagEnum::Truncate)) { + return FudStatus::OperationInvalid; + } + + openFlags |= flags.flags(); + + open_how openHow{}; + zeroObject(openHow); + openHow.flags = openFlags; + openHow.resolve = RESOLVE_NO_SYMLINKS; + + auto status = syscall(SYS_openat2, dirFd, filename.data(), &openHow, sizeof(openHow)); + if (status == -1) { + if constexpr (EAGAIN != EWOULDBLOCK && status == EWOULDBLOCK) { + return FudStatus::Partial; + } + switch (errno) { + case ETXTBSY: + case EAGAIN: + return FudStatus::Partial; + case ENOENT: + return FudStatus::NotFound; + case EFBIG: + case EOVERFLOW: + case EINVAL: + case EISDIR: + case ENAMETOOLONG: + return FudStatus::ArgumentInvalid; + case EROFS: + case EACCES: + case EPERM: + return FudStatus::PermissionDenied; + case ELOOP: + case EXDEV: + case ENFILE: + case E2BIG: + default: + return FudStatus::Failure; + } + } + fudAssert(status <= std::numeric_limits::max()); + file.m_fd = static_cast(status); + + using Stat = struct stat; + Stat sBuffer{}; + auto fStatus = fstat(file.m_fd, &sBuffer); + if (fStatus == -1) { + return FudStatus::Failure; + } + + if ((sBuffer.st_mode & S_IFMT) != S_IFREG) { + return FudStatus::ObjectInvalid; + } + + return file; +} + +/* + static FileResult RegularFile::create( + StringView filename, + FileAccessMode mode, + OpenFlags flags, + bool exclusive, + Option dirFdOption, + Allocator* allocator = &globalFudAllocator); +{ +} +*/ + +RegularFile::~RegularFile() +{ + static_cast(this->close()); +} + +RegularFile::RegularFile(RegularFile&& rhs) noexcept : m_fd{rhs.m_fd}, m_modeFlags{rhs.m_modeFlags} +{ + rhs.m_fd = -1; +} + +RegularFile& RegularFile::operator=(RegularFile&& rhs) noexcept +{ + if (&rhs == this) { + return *this; + } + + static_cast(this->close()); + + m_fd = rhs.m_fd; + m_modeFlags = rhs.m_modeFlags; + + rhs.m_fd = -1; + return *this; +} + +FudStatus RegularFile::take(RegularFile& rhs) +{ + if (&rhs == this) { + return FudStatus::Success; + } + + auto status = this->close(); + if (status != FudStatus::Success) { + return status; + } + + m_fd = rhs.m_fd; + m_modeFlags = rhs.m_modeFlags; + + rhs.m_fd = -1; + return status; +} + +FudStatus RegularFile::close() +{ + FudStatus status = FudStatus::Success; + if (m_fd != -1) { + auto closeStatus = ::close(m_fd); + if (closeStatus == -1) { + switch (errno) { + case EBADF: + status = FudStatus::HandleInvalid; + break; + case EINTR: + case EIO: + case ENOSPC: + case EDQUOT: + status = FudStatus::Partial; + break; + default: + status = FudStatus::Failure; + break; + } + } + m_fd = -1; + } + return status; +} + +} // namespace fud diff --git a/source/fud_string.cpp b/source/fud_string.cpp index 048cc94..c444a74 100644 --- a/source/fud_string.cpp +++ b/source/fud_string.cpp @@ -84,6 +84,32 @@ StringResult String::from(const String& rhs) return StringResult::okay(std::move(output)); } +StringResult String::from(StringView view, Allocator* allocator) +{ + if (allocator == nullptr || view.m_data == nullptr) { + return StringResult::error(FudStatus::NullPointer); + } + + String output{}; + output.m_allocator = allocator; + output.m_length = view.m_length; + + if (output.m_length >= output.m_capacity) { + output.m_capacity = output.m_length + 1; + + output.m_data = static_cast(M_TakeOrReturn(output.m_allocator->allocate(output.m_capacity))); + fudAssert(output.m_data != nullptr); + } + + auto copyStatus = copyMem(output.data(), output.m_capacity, view.m_data, output.m_length); + fudAssert(copyStatus == FudStatus::Success); + + auto terminateStatus = output.nullTerminate(); + fudAssert(terminateStatus == FudStatus::Success); + + return StringResult::okay(std::move(output)); +} + String::String(String&& rhs) noexcept : m_length{rhs.m_length}, m_capacity{rhs.m_capacity}, m_allocator{rhs.m_allocator} { if (rhs.isLarge()) { @@ -131,6 +157,10 @@ FudStatus String::copy(const String& rhs) String& String::operator=(String&& rhs) noexcept { + if (&rhs == this) { + return *this; + } + cleanup(); m_length = rhs.m_length; -- cgit v1.2.3