summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/fud_assert.cpp32
-rw-r--r--source/fud_file.cpp201
-rw-r--r--source/fud_string.cpp30
3 files changed, 259 insertions, 4 deletions
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 <climits>
#include <cstdio>
-#include <exception>
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<const char*>(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<void>(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 <cerrno>
+#include <fcntl.h>
+#include <linux/openat2.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+namespace fud {
+
+FileResult RegularFile::open(
+ StringView filename,
+ FileAccessMode mode,
+ OpenFlags flags,
+ Option<int> 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<decltype(file.m_fd)>::max());
+ file.m_fd = static_cast<decltype(file.m_fd)>(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<int> dirFdOption,
+ Allocator* allocator = &globalFudAllocator);
+{
+}
+*/
+
+RegularFile::~RegularFile()
+{
+ static_cast<void>(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<void>(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<utf8*>(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;