Compare commits
7 Commits
e77de1804f
...
cc2cc2849e
Author | SHA1 | Date |
---|---|---|
Bananymous | cc2cc2849e | |
Bananymous | 06f4b0b29a | |
Bananymous | e22821799b | |
Bananymous | 14dd9294aa | |
Bananymous | 83e3409bd8 | |
Bananymous | 7630170ed6 | |
Bananymous | 0af74fccda |
|
@ -1,280 +0,0 @@
|
||||||
#include <BAN/String.h>
|
|
||||||
#include <BAN/New.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
String::String()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(const String& other)
|
|
||||||
{
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(String&& other)
|
|
||||||
{
|
|
||||||
*this = move(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(StringView other)
|
|
||||||
{
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::~String()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
String& String::operator=(const String& other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
MUST(ensure_capacity(other.size()));
|
|
||||||
memcpy(data(), other.data(), other.size() + 1);
|
|
||||||
m_size = other.size();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String& String::operator=(String&& other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
if (other.has_sso())
|
|
||||||
memcpy(data(), other.data(), other.size() + 1);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_storage.general_storage = other.m_storage.general_storage;
|
|
||||||
m_has_sso = false;
|
|
||||||
}
|
|
||||||
m_size = other.m_size;
|
|
||||||
|
|
||||||
other.m_size = 0;
|
|
||||||
other.m_storage.sso_storage = SSOStorage();
|
|
||||||
other.m_has_sso = true;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String& String::operator=(StringView other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
MUST(ensure_capacity(other.size()));
|
|
||||||
memcpy(data(), other.data(), other.size());
|
|
||||||
m_size = other.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::push_back(char c)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(m_size + 1));
|
|
||||||
data()[m_size] = c;
|
|
||||||
m_size++;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::insert(char c, size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index <= m_size);
|
|
||||||
TRY(ensure_capacity(m_size + 1));
|
|
||||||
memmove(data() + index + 1, data() + index, m_size - index);
|
|
||||||
data()[index] = c;
|
|
||||||
m_size++;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::insert(StringView str, size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index <= m_size);
|
|
||||||
TRY(ensure_capacity(m_size + str.size()));
|
|
||||||
memmove(data() + index + str.size(), data() + index, m_size - index);
|
|
||||||
memcpy(data() + index, str.data(), str.size());
|
|
||||||
m_size += str.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::append(StringView str)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(m_size + str.size()));
|
|
||||||
memcpy(data() + m_size, str.data(), str.size());
|
|
||||||
m_size += str.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::pop_back()
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
m_size--;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::remove(size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
memcpy(data() + index, data() + index + 1, m_size - index);
|
|
||||||
m_size--;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::clear()
|
|
||||||
{
|
|
||||||
if (!has_sso())
|
|
||||||
{
|
|
||||||
deallocator(m_storage.general_storage.data);
|
|
||||||
m_storage.sso_storage = SSOStorage();
|
|
||||||
m_has_sso = true;
|
|
||||||
}
|
|
||||||
m_size = 0;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool String::operator==(const String& str) const
|
|
||||||
{
|
|
||||||
if (size() != str.size())
|
|
||||||
return false;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != str.data()[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool String::operator==(StringView str) const
|
|
||||||
{
|
|
||||||
if (size() != str.size())
|
|
||||||
return false;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != str.data()[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool String::operator==(const char* cstr) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != cstr[i])
|
|
||||||
return false;
|
|
||||||
if (cstr[size()] != '\0')
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::resize(size_type new_size, char init_c)
|
|
||||||
{
|
|
||||||
if (m_size == new_size)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
// expanding
|
|
||||||
if (m_size < new_size)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(new_size));
|
|
||||||
memset(data() + m_size, init_c, new_size - m_size);
|
|
||||||
m_size = new_size;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
m_size = new_size;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::reserve(size_type new_size)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(new_size));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::shrink_to_fit()
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (fits_in_sso())
|
|
||||||
{
|
|
||||||
char* data = m_storage.general_storage.data;
|
|
||||||
m_storage.sso_storage = SSOStorage();
|
|
||||||
m_has_sso = true;
|
|
||||||
memcpy(this->data(), data, m_size + 1);
|
|
||||||
deallocator(data);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
GeneralStorage& storage = m_storage.general_storage;
|
|
||||||
if (storage.capacity == m_size)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
char* new_data = (char*)allocator(m_size + 1);
|
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
memcpy(new_data, storage.data, m_size);
|
|
||||||
deallocator(storage.data);
|
|
||||||
|
|
||||||
storage.capacity = m_size;
|
|
||||||
storage.data = new_data;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
String::size_type String::capacity() const
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return sso_capacity;
|
|
||||||
return m_storage.general_storage.capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* String::data()
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return m_storage.sso_storage.data;
|
|
||||||
return m_storage.general_storage.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* String::data() const
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return m_storage.sso_storage.data;
|
|
||||||
return m_storage.general_storage.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::ensure_capacity(size_type new_size)
|
|
||||||
{
|
|
||||||
if (m_size >= new_size)
|
|
||||||
return {};
|
|
||||||
if (has_sso() && fits_in_sso(new_size))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
char* new_data = (char*)allocator(new_size + 1);
|
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
if (m_size)
|
|
||||||
memcpy(new_data, data(), m_size + 1);
|
|
||||||
|
|
||||||
if (has_sso())
|
|
||||||
{
|
|
||||||
m_storage.general_storage = GeneralStorage();
|
|
||||||
m_has_sso = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
deallocator(m_storage.general_storage.data);
|
|
||||||
|
|
||||||
auto& storage = m_storage.general_storage;
|
|
||||||
storage.capacity = new_size;
|
|
||||||
storage.data = new_data;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool String::has_sso() const
|
|
||||||
{
|
|
||||||
return m_has_sso;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,196 +1,11 @@
|
||||||
#include <BAN/String.h>
|
#include <BAN/String.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
StringView::StringView()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
StringView::StringView(const String& other)
|
StringView::StringView(const String& other)
|
||||||
: StringView(other.data(), other.size())
|
: StringView(other.data(), other.size())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
StringView::StringView(const char* string, size_type len)
|
|
||||||
{
|
|
||||||
if (len == size_type(-1))
|
|
||||||
len = strlen(string);
|
|
||||||
m_data = string;
|
|
||||||
m_size = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
char StringView::operator[](size_type index) const
|
|
||||||
{
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::operator==(const String& other) const
|
|
||||||
{
|
|
||||||
if (m_size != other.size())
|
|
||||||
return false;
|
|
||||||
return memcmp(m_data, other.data(), m_size) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::operator==(StringView other) const
|
|
||||||
{
|
|
||||||
if (m_size != other.m_size)
|
|
||||||
return false;
|
|
||||||
return memcmp(m_data, other.m_data, m_size) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::operator==(const char* other) const
|
|
||||||
{
|
|
||||||
if (memcmp(m_data, other, m_size))
|
|
||||||
return false;
|
|
||||||
return other[m_size] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView StringView::substring(size_type index, size_type len) const
|
|
||||||
{
|
|
||||||
ASSERT(index <= m_size);
|
|
||||||
if (len == size_type(-1))
|
|
||||||
len = m_size - index;
|
|
||||||
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
|
||||||
StringView result;
|
|
||||||
result.m_data = m_data + index;
|
|
||||||
result.m_size = len;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> StringView::split(char delim, bool allow_empties) const
|
|
||||||
{
|
|
||||||
size_type count = 0;
|
|
||||||
{
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (m_data[i] == delim)
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
count++;
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start != m_size)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<StringView> result;
|
|
||||||
TRY(result.reserve(count));
|
|
||||||
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (m_data[i] == delim)
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
TRY(result.push_back(this->substring(start, i - start)));
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start < m_size || (start == m_size && allow_empties))
|
|
||||||
TRY(result.push_back(this->substring(start)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> StringView::split(bool(*comp)(char), bool allow_empties) const
|
|
||||||
{
|
|
||||||
size_type count = 0;
|
|
||||||
{
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
count++;
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start != m_size)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<StringView> result;
|
|
||||||
TRY(result.reserve(count));
|
|
||||||
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
TRY(result.push_back(this->substring(start, i - start)));
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start < m_size || (start == m_size && allow_empties))
|
|
||||||
TRY(result.push_back(this->substring(start)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
char StringView::back() const
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
return m_data[m_size - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
char StringView::front() const
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
return m_data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<StringView::size_type> StringView::find(char ch) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
return i;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<StringView::size_type> StringView::find(bool(*comp)(char)) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
return i;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::contains(char ch) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView::size_type StringView::count(char ch) const
|
|
||||||
{
|
|
||||||
size_type result = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
result++;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::empty() const
|
|
||||||
{
|
|
||||||
return m_size == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView::size_type StringView::size() const
|
|
||||||
{
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* StringView::data() const
|
|
||||||
{
|
|
||||||
return m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ project(BAN CXX)
|
||||||
set(BAN_SOURCES
|
set(BAN_SOURCES
|
||||||
BAN/Assert.cpp
|
BAN/Assert.cpp
|
||||||
BAN/New.cpp
|
BAN/New.cpp
|
||||||
BAN/String.cpp
|
|
||||||
BAN/StringView.cpp
|
BAN/StringView.cpp
|
||||||
BAN/Time.cpp
|
BAN/Time.cpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/StringView.h>
|
|
||||||
#include <BAN/Variant.h>
|
#include <BAN/Variant.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -56,7 +55,7 @@ namespace BAN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint64_t get_error_code() const { return m_error_code; }
|
uint64_t get_error_code() const { return m_error_code; }
|
||||||
BAN::StringView get_message() const
|
const char* get_message() const
|
||||||
{
|
{
|
||||||
#ifdef __is_kernel
|
#ifdef __is_kernel
|
||||||
if (m_error_code & kernel_error_mask)
|
if (m_error_code & kernel_error_mask)
|
||||||
|
@ -64,7 +63,7 @@ namespace BAN
|
||||||
#endif
|
#endif
|
||||||
if (auto* desc = strerrordesc_np(m_error_code))
|
if (auto* desc = strerrordesc_np(m_error_code))
|
||||||
return desc;
|
return desc;
|
||||||
return "Unknown error"sv;
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/ForwardList.h>
|
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/Hash.h>
|
||||||
#include <BAN/Iterators.h>
|
#include <BAN/Iterators.h>
|
||||||
|
#include <BAN/New.h>
|
||||||
|
#include <BAN/StringView.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
@ -18,28 +19,125 @@ namespace BAN
|
||||||
static constexpr size_type sso_capacity = 15;
|
static constexpr size_type sso_capacity = 15;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
String();
|
String() {}
|
||||||
String(const String&);
|
String(const String& other) { *this = other; }
|
||||||
String(String&&);
|
String(String&& other) { *this = move(other); }
|
||||||
String(StringView);
|
String(StringView other) { *this = other; }
|
||||||
~String();
|
~String() { clear(); }
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static String formatted(const char* format, const Args&... args);
|
static String formatted(const char* format, const Args&... args)
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
String& operator=(const String&);
|
String& operator=(const String& other)
|
||||||
String& operator=(String&&);
|
{
|
||||||
String& operator=(StringView);
|
clear();
|
||||||
|
MUST(ensure_capacity(other.size()));
|
||||||
|
memcpy(data(), other.data(), other.size() + 1);
|
||||||
|
m_size = other.size();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> push_back(char);
|
String& operator=(String&& other)
|
||||||
ErrorOr<void> insert(char, size_type);
|
{
|
||||||
ErrorOr<void> insert(StringView, size_type);
|
clear();
|
||||||
ErrorOr<void> append(StringView);
|
|
||||||
|
|
||||||
void pop_back();
|
if (other.has_sso())
|
||||||
void remove(size_type);
|
memcpy(data(), other.data(), other.size() + 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_storage.general_storage = other.m_storage.general_storage;
|
||||||
|
m_has_sso = false;
|
||||||
|
}
|
||||||
|
m_size = other.m_size;
|
||||||
|
|
||||||
void clear();
|
other.m_size = 0;
|
||||||
|
other.m_storage.sso_storage = SSOStorage();
|
||||||
|
other.m_has_sso = true;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String& operator=(StringView other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
MUST(ensure_capacity(other.size()));
|
||||||
|
memcpy(data(), other.data(), other.size());
|
||||||
|
m_size = other.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> push_back(char c)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(m_size + 1));
|
||||||
|
data()[m_size] = c;
|
||||||
|
m_size++;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> insert(char c, size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
TRY(ensure_capacity(m_size + 1));
|
||||||
|
memmove(data() + index + 1, data() + index, m_size - index);
|
||||||
|
data()[index] = c;
|
||||||
|
m_size++;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> insert(StringView str, size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
TRY(ensure_capacity(m_size + str.size()));
|
||||||
|
memmove(data() + index + str.size(), data() + index, m_size - index);
|
||||||
|
memcpy(data() + index, str.data(), str.size());
|
||||||
|
m_size += str.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> append(StringView str)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(m_size + str.size()));
|
||||||
|
memcpy(data() + m_size, str.data(), str.size());
|
||||||
|
m_size += str.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
m_size--;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
memcpy(data() + index, data() + index + 1, m_size - index);
|
||||||
|
m_size--;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (!has_sso())
|
||||||
|
{
|
||||||
|
deallocator(m_storage.general_storage.data);
|
||||||
|
m_storage.sso_storage = SSOStorage();
|
||||||
|
m_has_sso = true;
|
||||||
|
}
|
||||||
|
m_size = 0;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
const_iterator begin() const { return const_iterator(data()); }
|
const_iterator begin() const { return const_iterator(data()); }
|
||||||
iterator begin() { return iterator(data()); }
|
iterator begin() { return iterator(data()); }
|
||||||
|
@ -55,27 +153,151 @@ namespace BAN
|
||||||
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
||||||
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
||||||
|
|
||||||
bool operator==(const String&) const;
|
bool operator==(const String& str) const
|
||||||
bool operator==(StringView) const;
|
{
|
||||||
bool operator==(const char*) const;
|
if (size() != str.size())
|
||||||
|
return false;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (data()[i] != str.data()[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> resize(size_type, char = '\0');
|
bool operator==(StringView str) const
|
||||||
ErrorOr<void> reserve(size_type);
|
{
|
||||||
ErrorOr<void> shrink_to_fit();
|
if (size() != str.size())
|
||||||
|
return false;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (data()[i] != str.data()[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const char* cstr) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (data()[i] != cstr[i])
|
||||||
|
return false;
|
||||||
|
if (cstr[size()] != '\0')
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> resize(size_type new_size, char init_c = '\0')
|
||||||
|
{
|
||||||
|
if (m_size == new_size)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// expanding
|
||||||
|
if (m_size < new_size)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(new_size));
|
||||||
|
memset(data() + m_size, init_c, new_size - m_size);
|
||||||
|
m_size = new_size;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m_size = new_size;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> reserve(size_type new_size)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(new_size));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> shrink_to_fit()
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (fits_in_sso())
|
||||||
|
{
|
||||||
|
char* data = m_storage.general_storage.data;
|
||||||
|
m_storage.sso_storage = SSOStorage();
|
||||||
|
m_has_sso = true;
|
||||||
|
memcpy(this->data(), data, m_size + 1);
|
||||||
|
deallocator(data);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
GeneralStorage& storage = m_storage.general_storage;
|
||||||
|
if (storage.capacity == m_size)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
char* new_data = (char*)allocator(m_size + 1);
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
memcpy(new_data, storage.data, m_size);
|
||||||
|
deallocator(storage.data);
|
||||||
|
|
||||||
|
storage.capacity = m_size;
|
||||||
|
storage.data = new_data;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
StringView sv() const { return StringView(data(), size()); }
|
StringView sv() const { return StringView(data(), size()); }
|
||||||
|
|
||||||
bool empty() const { return m_size == 0; }
|
bool empty() const { return m_size == 0; }
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
size_type capacity() const;
|
|
||||||
|
|
||||||
char* data();
|
size_type capacity() const
|
||||||
const char* data() const;
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return sso_capacity;
|
||||||
|
return m_storage.general_storage.capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data()
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return m_storage.sso_storage.data;
|
||||||
|
return m_storage.general_storage.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* data() const
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return m_storage.sso_storage.data;
|
||||||
|
return m_storage.general_storage.data;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorOr<void> ensure_capacity(size_type);
|
ErrorOr<void> ensure_capacity(size_type new_size)
|
||||||
|
{
|
||||||
|
if (m_size >= new_size)
|
||||||
|
return {};
|
||||||
|
if (has_sso() && fits_in_sso(new_size))
|
||||||
|
return {};
|
||||||
|
|
||||||
bool has_sso() const;
|
char* new_data = (char*)allocator(new_size + 1);
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
if (m_size)
|
||||||
|
memcpy(new_data, data(), m_size + 1);
|
||||||
|
|
||||||
|
if (has_sso())
|
||||||
|
{
|
||||||
|
m_storage.general_storage = GeneralStorage();
|
||||||
|
m_has_sso = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
deallocator(m_storage.general_storage.data);
|
||||||
|
|
||||||
|
auto& storage = m_storage.general_storage;
|
||||||
|
storage.capacity = new_size;
|
||||||
|
storage.data = new_data;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_sso() const { return m_has_sso; }
|
||||||
|
|
||||||
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
||||||
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
||||||
|
@ -100,14 +322,6 @@ namespace BAN
|
||||||
size_type m_has_sso : 1 { true };
|
size_type m_has_sso : 1 { true };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
String String::formatted(const char* format, const Args&... args)
|
|
||||||
{
|
|
||||||
String result;
|
|
||||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct hash<String>
|
struct hash<String>
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <BAN/ForwardList.h>
|
#include <BAN/ForwardList.h>
|
||||||
#include <BAN/Iterators.h>
|
#include <BAN/Iterators.h>
|
||||||
#include <BAN/Optional.h>
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
@ -15,37 +16,171 @@ namespace BAN
|
||||||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringView();
|
StringView() {}
|
||||||
StringView(const String&);
|
StringView(const String&);
|
||||||
StringView(const char*, size_type = -1);
|
StringView(const char* string, size_type len = -1)
|
||||||
|
{
|
||||||
|
if (len == size_type(-1))
|
||||||
|
len = strlen(string);
|
||||||
|
m_data = string;
|
||||||
|
m_size = len;
|
||||||
|
}
|
||||||
|
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||||
|
|
||||||
char operator[](size_type) const;
|
char operator[](size_type index) const
|
||||||
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const String&) const;
|
bool operator==(StringView other) const
|
||||||
bool operator==(StringView) const;
|
{
|
||||||
bool operator==(const char*) const;
|
if (m_size != other.m_size)
|
||||||
|
return false;
|
||||||
|
return memcmp(m_data, other.m_data, m_size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
StringView substring(size_type, size_type = -1) const;
|
bool operator==(const char* other) const
|
||||||
|
{
|
||||||
|
if (memcmp(m_data, other, m_size))
|
||||||
|
return false;
|
||||||
|
return other[m_size] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> split(char, bool = false) const;
|
StringView substring(size_type index, size_type len = -1) const
|
||||||
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool = false) const;
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
if (len == size_type(-1))
|
||||||
|
len = m_size - index;
|
||||||
|
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
||||||
|
StringView result;
|
||||||
|
result.m_data = m_data + index;
|
||||||
|
result.m_size = len;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
char back() const;
|
ErrorOr<Vector<StringView>> split(char delim, bool allow_empties = false) const
|
||||||
char front() const;
|
{
|
||||||
|
size_type count = 0;
|
||||||
|
{
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (m_data[i] == delim)
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
count++;
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != m_size)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::Optional<size_type> find(char) const;
|
Vector<StringView> result;
|
||||||
BAN::Optional<size_type> find(bool(*comp)(char)) const;
|
TRY(result.reserve(count));
|
||||||
|
|
||||||
bool contains(char) const;
|
size_type start = 0;
|
||||||
size_type count(char) const;
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (m_data[i] == delim)
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
TRY(result.push_back(this->substring(start, i - start)));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start < m_size || (start == m_size && allow_empties))
|
||||||
|
TRY(result.push_back(this->substring(start)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool empty() const;
|
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool allow_empties = false) const
|
||||||
size_type size() const;
|
{
|
||||||
|
size_type count = 0;
|
||||||
|
{
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (comp(m_data[i]))
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
count++;
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != m_size)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
const char* data() const;
|
Vector<StringView> result;
|
||||||
|
TRY(result.reserve(count));
|
||||||
|
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (comp(m_data[i]))
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
TRY(result.push_back(this->substring(start, i - start)));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start < m_size || (start == m_size && allow_empties))
|
||||||
|
TRY(result.push_back(this->substring(start)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char back() const
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
return m_data[m_size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
char front() const
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
return m_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<size_type> find(char ch) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] == ch)
|
||||||
|
return i;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<size_type> find(bool(*comp)(char)) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (comp(m_data[i]))
|
||||||
|
return i;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(char ch) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] == ch)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type count(char ch) const
|
||||||
|
{
|
||||||
|
size_type result = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] == ch)
|
||||||
|
result++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return m_size == 0; }
|
||||||
|
size_type size() const { return m_size; }
|
||||||
|
const char* data() const { return m_data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* m_data = nullptr;
|
const char* m_data = nullptr;
|
||||||
|
|
|
@ -137,7 +137,6 @@ endif()
|
||||||
set(BAN_SOURCES
|
set(BAN_SOURCES
|
||||||
../BAN/BAN/Assert.cpp
|
../BAN/BAN/Assert.cpp
|
||||||
../BAN/BAN/New.cpp
|
../BAN/BAN/New.cpp
|
||||||
../BAN/BAN/String.cpp
|
|
||||||
../BAN/BAN/StringView.cpp
|
../BAN/BAN/StringView.cpp
|
||||||
../BAN/BAN/Time.cpp
|
../BAN/BAN/Time.cpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
namespace Kernel::API
|
|
||||||
{
|
|
||||||
|
|
||||||
struct DirectoryEntry
|
|
||||||
{
|
|
||||||
size_t rec_len { 0 };
|
|
||||||
struct dirent dirent;
|
|
||||||
DirectoryEntry* next() const { return (DirectoryEntry*)((uintptr_t)this + rec_len); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DirectoryEntryList
|
|
||||||
{
|
|
||||||
size_t entry_count { 0 };
|
|
||||||
DirectoryEntry array[];
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/StringView.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
enum class ErrorCode : uint32_t
|
enum class ErrorCode
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
ACPI_NoRootSDT,
|
ACPI_NoRootSDT,
|
||||||
|
@ -31,6 +29,6 @@ namespace Kernel
|
||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
BAN::StringView error_string(ErrorCode);
|
const char* error_string(ErrorCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace Kernel
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
|
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
|
||||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override;
|
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override;
|
||||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
||||||
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
||||||
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <BAN/WeakPtr.h>
|
#include <BAN/WeakPtr.h>
|
||||||
|
|
||||||
#include <kernel/API/DirectoryEntry.h>
|
|
||||||
#include <kernel/Credentials.h>
|
#include <kernel/Credentials.h>
|
||||||
#include <kernel/Debug.h>
|
#include <kernel/Debug.h>
|
||||||
#include <kernel/Lock/Mutex.h>
|
#include <kernel/Lock/Mutex.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -19,8 +19,6 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
using namespace API;
|
|
||||||
|
|
||||||
class FileBackedRegion;
|
class FileBackedRegion;
|
||||||
class SharedFileData;
|
class SharedFileData;
|
||||||
|
|
||||||
|
@ -92,7 +90,7 @@ namespace Kernel
|
||||||
|
|
||||||
// Directory API
|
// Directory API
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
|
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
|
||||||
BAN::ErrorOr<void> list_next_inodes(off_t, DirectoryEntryList*, size_t);
|
BAN::ErrorOr<size_t> list_next_inodes(off_t, struct dirent* list, size_t list_size);
|
||||||
BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t);
|
BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t);
|
||||||
BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t);
|
BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t);
|
||||||
BAN::ErrorOr<void> unlink(BAN::StringView);
|
BAN::ErrorOr<void> unlink(BAN::StringView);
|
||||||
|
@ -127,7 +125,7 @@ namespace Kernel
|
||||||
|
|
||||||
// Directory API
|
// Directory API
|
||||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
|
|
|
@ -141,7 +141,7 @@ namespace Kernel
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final;
|
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final;
|
||||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override final;
|
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override final;
|
||||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
|
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
|
||||||
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
|
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
|
||||||
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<int> fcntl(int fd, int cmd, int extra);
|
BAN::ErrorOr<int> fcntl(int fd, int cmd, int extra);
|
||||||
|
|
||||||
BAN::ErrorOr<void> seek(int fd, off_t offset, int whence);
|
BAN::ErrorOr<off_t> seek(int fd, off_t offset, int whence);
|
||||||
BAN::ErrorOr<off_t> tell(int) const;
|
BAN::ErrorOr<off_t> tell(int) const;
|
||||||
|
|
||||||
BAN::ErrorOr<void> fstat(int fd, struct stat*) const;
|
BAN::ErrorOr<void> fstat(int fd, struct stat*) const;
|
||||||
|
@ -47,7 +47,7 @@ namespace Kernel
|
||||||
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
|
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
|
||||||
BAN::ErrorOr<size_t> write(int fd, BAN::ConstByteSpan);
|
BAN::ErrorOr<size_t> write(int fd, BAN::ConstByteSpan);
|
||||||
|
|
||||||
BAN::ErrorOr<void> read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size);
|
BAN::ErrorOr<size_t> read_dir_entries(int fd, struct dirent* list, size_t list_len);
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::StringView> path_of(int) const;
|
BAN::ErrorOr<BAN::StringView> path_of(int) const;
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
|
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
|
||||||
|
|
|
@ -149,7 +149,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> mount(BAN::StringView source, BAN::StringView target);
|
BAN::ErrorOr<void> mount(BAN::StringView source, BAN::StringView target);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_readdir(int fd, DirectoryEntryList* buffer, size_t buffer_size);
|
BAN::ErrorOr<long> sys_readdir(int fd, struct dirent* list, size_t list_len);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
|
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
|
||||||
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
|
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
|
||||||
|
|
|
@ -1,34 +1,38 @@
|
||||||
|
#include <BAN/Assert.h>
|
||||||
#include <kernel/Errors.h>
|
#include <kernel/Errors.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
static BAN::StringView s_error_strings[] {
|
static const char* s_error_strings[] {
|
||||||
"No Error"sv,
|
"No Error",
|
||||||
"ACPI could not find root SDT header"sv,
|
"ACPI could not find root SDT header",
|
||||||
"ACPI no such header"sv,
|
"ACPI no such header",
|
||||||
"ACPI root invalid",
|
"ACPI root invalid",
|
||||||
"Invalid ext2 filesystem"sv,
|
"Invalid ext2 filesystem",
|
||||||
"Ext2 filesystem corrupted"sv,
|
"Ext2 filesystem corrupted",
|
||||||
"Ext2 filesystem out of inodes"sv,
|
"Ext2 filesystem out of inodes",
|
||||||
"Attempted to access outside of device boundaries"sv,
|
"Attempted to access outside of device boundaries",
|
||||||
"Device has invalid GPT header"sv,
|
"Device has invalid GPT header",
|
||||||
"Device does not support LBA addressing"sv,
|
"Device does not support LBA addressing",
|
||||||
"Address mark not found"sv,
|
"Address mark not found",
|
||||||
"Track zero not found"sv,
|
"Track zero not found",
|
||||||
"Aborted command"sv,
|
"Aborted command",
|
||||||
"Media change request"sv,
|
"Media change request",
|
||||||
"ID not found"sv,
|
"ID not found",
|
||||||
"Media changed"sv,
|
"Media changed",
|
||||||
"Uncorrectable data error"sv,
|
"Uncorrectable data error",
|
||||||
"Bad Block detected"sv,
|
"Bad Block detected",
|
||||||
"Unsupported ata device"sv,
|
"Unsupported ata device",
|
||||||
"Font file too small"sv,
|
"Font file too small",
|
||||||
"Unsupported font format"sv,
|
"Unsupported font format",
|
||||||
};
|
};
|
||||||
static_assert(sizeof(s_error_strings) / sizeof(*s_error_strings) == (size_t)ErrorCode::Count);
|
static_assert(sizeof(s_error_strings) / sizeof(*s_error_strings) == (size_t)ErrorCode::Count);
|
||||||
|
|
||||||
BAN::StringView error_string(ErrorCode error)
|
const char* error_string(ErrorCode error)
|
||||||
{
|
{
|
||||||
ASSERT((uint32_t)error < (uint32_t)ErrorCode::Count);
|
ASSERT((uint32_t)error < (uint32_t)ErrorCode::Count);
|
||||||
return s_error_strings[(uint32_t)error];
|
return s_error_strings[(uint32_t)error];
|
||||||
|
|
|
@ -299,16 +299,13 @@ done:
|
||||||
m_fs.delete_inode(ino());
|
m_fs.delete_inode(ino());
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Ext2Inode::list_next_inodes_impl(off_t offset, DirectoryEntryList* list, size_t list_size)
|
BAN::ErrorOr<size_t> Ext2Inode::list_next_inodes_impl(off_t offset, struct dirent* list, size_t list_size)
|
||||||
{
|
{
|
||||||
ASSERT(mode().ifdir());
|
ASSERT(mode().ifdir());
|
||||||
ASSERT(offset >= 0);
|
ASSERT(offset >= 0);
|
||||||
|
|
||||||
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= max_used_data_block_count())
|
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= max_used_data_block_count())
|
||||||
{
|
return 0;
|
||||||
list->entry_count = 0;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: can we actually assume directories have all their blocks allocated
|
// FIXME: can we actually assume directories have all their blocks allocated
|
||||||
const uint32_t block_index = fs_block_of_data_block_index(offset).value();
|
const uint32_t block_index = fs_block_of_data_block_index(offset).value();
|
||||||
|
@ -318,26 +315,25 @@ done:
|
||||||
m_fs.read_block(block_index, block_buffer);
|
m_fs.read_block(block_index, block_buffer);
|
||||||
|
|
||||||
// First determine if we have big enough list
|
// First determine if we have big enough list
|
||||||
|
size_t entry_count = 0;
|
||||||
{
|
{
|
||||||
BAN::ConstByteSpan entry_span = block_buffer.span();
|
BAN::ConstByteSpan entry_span = block_buffer.span();
|
||||||
|
|
||||||
size_t needed_size = sizeof(DirectoryEntryList);
|
|
||||||
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))
|
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))
|
||||||
{
|
{
|
||||||
auto& entry = entry_span.as<const Ext2::LinkedDirectoryEntry>();
|
auto& entry = entry_span.as<const Ext2::LinkedDirectoryEntry>();
|
||||||
if (entry.inode)
|
if (entry.inode)
|
||||||
needed_size += sizeof(DirectoryEntry) + entry.name_len + 1;
|
entry_count++;
|
||||||
entry_span = entry_span.slice(entry.rec_len);
|
entry_span = entry_span.slice(entry.rec_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needed_size > list_size)
|
if (entry_count > list_size)
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second fill the list
|
// Second fill the list
|
||||||
{
|
{
|
||||||
DirectoryEntry* ptr = list->array;
|
dirent* dirp = list;
|
||||||
list->entry_count = 0;
|
|
||||||
|
|
||||||
BAN::ConstByteSpan entry_span = block_buffer.span();
|
BAN::ConstByteSpan entry_span = block_buffer.span();
|
||||||
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))
|
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))
|
||||||
|
@ -345,20 +341,16 @@ done:
|
||||||
auto& entry = entry_span.as<const Ext2::LinkedDirectoryEntry>();
|
auto& entry = entry_span.as<const Ext2::LinkedDirectoryEntry>();
|
||||||
if (entry.inode)
|
if (entry.inode)
|
||||||
{
|
{
|
||||||
ptr->dirent.d_ino = entry.inode;
|
dirp->d_ino = entry.inode;
|
||||||
ptr->dirent.d_type = entry.file_type;
|
dirp->d_type = entry.file_type;
|
||||||
ptr->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1;
|
strncpy(dirp->d_name, entry.name, entry.name_len);
|
||||||
memcpy(ptr->dirent.d_name, entry.name, entry.name_len);
|
dirp++;
|
||||||
ptr->dirent.d_name[entry.name_len] = '\0';
|
|
||||||
|
|
||||||
ptr = ptr->next();
|
|
||||||
list->entry_count++;
|
|
||||||
}
|
}
|
||||||
entry_span = entry_span.slice(entry.rec_len);
|
entry_span = entry_span.slice(entry.rec_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return entry_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mode_has_valid_type(mode_t mode)
|
static bool mode_has_valid_type(mode_t mode)
|
||||||
|
|
|
@ -70,7 +70,7 @@ namespace Kernel
|
||||||
return find_inode_impl(name);
|
return find_inode_impl(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Inode::list_next_inodes(off_t offset, DirectoryEntryList* list, size_t list_len)
|
BAN::ErrorOr<size_t> Inode::list_next_inodes(off_t offset, struct dirent* list, size_t list_len)
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
if (!mode().ifdir())
|
if (!mode().ifdir())
|
||||||
|
|
|
@ -432,9 +432,9 @@ namespace Kernel
|
||||||
return BAN::RefPtr<Inode>(inode);
|
return BAN::RefPtr<Inode>(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> TmpDirectoryInode::list_next_inodes_impl(off_t data_block_index, DirectoryEntryList* list, size_t list_len)
|
BAN::ErrorOr<size_t> TmpDirectoryInode::list_next_inodes_impl(off_t data_block_index, struct dirent* list, size_t list_len)
|
||||||
{
|
{
|
||||||
if (list_len < (size_t)blksize())
|
if (list_len == 0)
|
||||||
{
|
{
|
||||||
dprintln("buffer is too small");
|
dprintln("buffer is too small");
|
||||||
return BAN::Error::from_errno(ENOBUFS);
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
|
@ -442,13 +442,12 @@ namespace Kernel
|
||||||
|
|
||||||
auto block_index = this->block_index(data_block_index);
|
auto block_index = this->block_index(data_block_index);
|
||||||
|
|
||||||
list->entry_count = 0;
|
|
||||||
|
|
||||||
// if we reach a non-allocated block, it marks the end
|
// if we reach a non-allocated block, it marks the end
|
||||||
if (!block_index.has_value())
|
if (!block_index.has_value())
|
||||||
return {};
|
return 0;
|
||||||
|
|
||||||
auto* dirp = list->array;
|
dirent* dirp = list;
|
||||||
|
size_t entry_count = 0;
|
||||||
|
|
||||||
const size_t byte_count = BAN::Math::min<size_t>(size() - data_block_index * blksize(), blksize());
|
const size_t byte_count = BAN::Math::min<size_t>(size() - data_block_index * blksize(), blksize());
|
||||||
m_fs.with_block_buffer(block_index.value(), [&](BAN::ByteSpan bytespan) {
|
m_fs.with_block_buffer(block_index.value(), [&](BAN::ByteSpan bytespan) {
|
||||||
|
@ -462,21 +461,21 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
// TODO: dirents should be aligned
|
// TODO: dirents should be aligned
|
||||||
|
|
||||||
dirp->dirent.d_ino = entry.ino;
|
entry_count++;
|
||||||
dirp->dirent.d_type = entry.type;
|
if (entry_count > list_len)
|
||||||
strncpy(dirp->dirent.d_name, entry.name, entry.name_len);
|
return;
|
||||||
dirp->dirent.d_name[entry.name_len] = '\0';
|
|
||||||
dirp->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1;
|
|
||||||
dirp = dirp->next();
|
|
||||||
|
|
||||||
list->entry_count++;
|
dirp->d_ino = entry.ino;
|
||||||
|
dirp->d_type = entry.type;
|
||||||
|
strncpy(dirp->d_name, entry.name, entry.name_len);
|
||||||
|
dirp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytespan = bytespan.slice(entry.rec_len);
|
bytespan = bytespan.slice(entry.rec_len);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {};
|
return entry_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> TmpDirectoryInode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
BAN::ErrorOr<void> TmpDirectoryInode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
|
|
@ -207,7 +207,7 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
|
BAN::ErrorOr<off_t> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ namespace Kernel
|
||||||
|
|
||||||
m_open_files[fd]->offset = new_offset;
|
m_open_files[fd]->offset = new_offset;
|
||||||
|
|
||||||
return {};
|
return new_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<off_t> OpenFileDescriptorSet::tell(int fd) const
|
BAN::ErrorOr<off_t> OpenFileDescriptorSet::tell(int fd) const
|
||||||
|
@ -351,15 +351,13 @@ namespace Kernel
|
||||||
return nwrite;
|
return nwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size)
|
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read_dir_entries(int fd, struct dirent* list, size_t list_len)
|
||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
auto& open_file = m_open_files[fd];
|
auto& open_file = m_open_files[fd];
|
||||||
if (!(open_file->flags & O_RDONLY))
|
if (!(open_file->flags & O_RDONLY))
|
||||||
return BAN::Error::from_errno(EACCES);
|
return BAN::Error::from_errno(EACCES);
|
||||||
TRY(open_file->inode->list_next_inodes(open_file->offset, list, list_size));
|
return TRY(open_file->inode->list_next_inodes(open_file->offset++, list, list_len));
|
||||||
open_file->offset++;
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::StringView> OpenFileDescriptorSet::path_of(int fd) const
|
BAN::ErrorOr<BAN::StringView> OpenFileDescriptorSet::path_of(int fd) const
|
||||||
|
|
|
@ -1136,8 +1136,7 @@ namespace Kernel
|
||||||
BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence)
|
BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
TRY(m_open_file_descriptors.seek(fd, offset, whence));
|
return TRY(m_open_file_descriptors.seek(fd, offset, whence));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_tell(int fd)
|
BAN::ErrorOr<long> Process::sys_tell(int fd)
|
||||||
|
@ -1220,12 +1219,11 @@ namespace Kernel
|
||||||
return clean_poweroff(command);
|
return clean_poweroff(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_readdir(int fd, DirectoryEntryList* list, size_t list_size)
|
BAN::ErrorOr<long> Process::sys_readdir(int fd, struct dirent* list, size_t list_len)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
TRY(validate_pointer_access(list, list_size));
|
TRY(validate_pointer_access(list, sizeof(dirent) * list_len));
|
||||||
TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size));
|
return TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_len));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_setpwd(const char* path)
|
BAN::ErrorOr<long> Process::sys_setpwd(const char* path)
|
||||||
|
|
|
@ -5,16 +5,14 @@
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <kernel/API/DirectoryEntry.h>
|
|
||||||
|
|
||||||
struct __DIR
|
struct __DIR
|
||||||
{
|
{
|
||||||
int fd { -1 };
|
int fd { -1 };
|
||||||
|
size_t entry_count { 0 };
|
||||||
size_t entry_index { 0 };
|
size_t entry_index { 0 };
|
||||||
Kernel::API::DirectoryEntry* current { nullptr };
|
// FIXME: we should probably allocate entries dynamically
|
||||||
|
// based if syscall returns ENOBUFS
|
||||||
size_t buffer_size { 0 };
|
dirent entries[128];
|
||||||
Kernel::API::DirectoryEntryList buffer[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int closedir(DIR* dirp)
|
int closedir(DIR* dirp)
|
||||||
|
@ -26,7 +24,6 @@ int closedir(DIR* dirp)
|
||||||
}
|
}
|
||||||
|
|
||||||
close(dirp->fd);
|
close(dirp->fd);
|
||||||
dirp->fd = -1;
|
|
||||||
free(dirp);
|
free(dirp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -45,13 +42,13 @@ int dirfd(DIR* dirp)
|
||||||
|
|
||||||
DIR* fdopendir(int fd)
|
DIR* fdopendir(int fd)
|
||||||
{
|
{
|
||||||
DIR* dirp = (DIR*)malloc(sizeof(DIR) + 4096);
|
DIR* dirp = (DIR*)malloc(sizeof(DIR));
|
||||||
if (dirp == nullptr)
|
if (dirp == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
dirp->fd = fd;
|
dirp->fd = fd;
|
||||||
dirp->current = nullptr;
|
dirp->entry_count = 0;
|
||||||
dirp->buffer_size = 4096;
|
dirp->entry_index = 0;
|
||||||
|
|
||||||
return dirp;
|
return dirp;
|
||||||
}
|
}
|
||||||
|
@ -73,20 +70,15 @@ struct dirent* readdir(DIR* dirp)
|
||||||
}
|
}
|
||||||
|
|
||||||
dirp->entry_index++;
|
dirp->entry_index++;
|
||||||
if (dirp->current && dirp->entry_index < dirp->buffer->entry_count)
|
if (dirp->entry_index < dirp->entry_count)
|
||||||
{
|
return &dirp->entries[dirp->entry_index];
|
||||||
dirp->current = dirp->current->next();
|
|
||||||
return &dirp->current->dirent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syscall(SYS_READ_DIR, dirp->fd, dirp->buffer, dirp->buffer_size) == -1)
|
long entry_count = syscall(SYS_READ_DIR, dirp->fd, dirp->entries, sizeof(dirp->entries) / sizeof(dirp->entries[0]));
|
||||||
return nullptr;
|
if (entry_count <= 0)
|
||||||
|
|
||||||
if (dirp->buffer->entry_count == 0)
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
dirp->entry_count = entry_count;
|
||||||
dirp->entry_index = 0;
|
dirp->entry_index = 0;
|
||||||
dirp->current = dirp->buffer->array;
|
|
||||||
|
|
||||||
return &dirp->current->dirent;
|
return &dirp->entries[0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ __BEGIN_DECLS
|
||||||
#define __need_ino_t
|
#define __need_ino_t
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
struct __DIR;
|
|
||||||
typedef struct __DIR DIR;
|
typedef struct __DIR DIR;
|
||||||
|
|
||||||
#define DT_UNKNOWN 0
|
#define DT_UNKNOWN 0
|
||||||
|
@ -26,7 +25,7 @@ struct dirent
|
||||||
{
|
{
|
||||||
ino_t d_ino; /* File serial number. */
|
ino_t d_ino; /* File serial number. */
|
||||||
unsigned char d_type; /* File type. One of DT_* definitions. */
|
unsigned char d_type; /* File type. One of DT_* definitions. */
|
||||||
char d_name[]; /* Filename string of entry. */
|
char d_name[256]; /* Filename string of entry. */
|
||||||
};
|
};
|
||||||
|
|
||||||
int alphasort(const struct dirent** d1, const struct dirent** d2);
|
int alphasort(const struct dirent** d1, const struct dirent** d2);
|
||||||
|
|
|
@ -7,12 +7,59 @@
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
// FIXME: What do I have to define here?
|
#define _POSIX_AIO_LISTIO_MAX 2
|
||||||
// glibc seems to only define numerical
|
#define _POSIX_AIO_MAX 1
|
||||||
// and posix constants
|
#define _POSIX_ARG_MAX 4096
|
||||||
|
#define _POSIX_CHILD_MAX 25
|
||||||
|
#define _POSIX_DELAYTIMER_MAX 32
|
||||||
|
#define _POSIX_HOST_NAME_MAX 255
|
||||||
|
#define _POSIX_LINK_MAX 8
|
||||||
|
#define _POSIX_LOGIN_NAME_MAX 9
|
||||||
|
#define _POSIX_MAX_CANON 255
|
||||||
|
#define _POSIX_MAX_INPUT 255
|
||||||
|
#define _POSIX_MQ_OPEN_MAX 8
|
||||||
|
#define _POSIX_MQ_PRIO_MAX 32
|
||||||
|
#define _POSIX_NAME_MAX 14
|
||||||
|
#define _POSIX_NGROUPS_MAX 8
|
||||||
|
#define _POSIX_OPEN_MAX 20
|
||||||
|
#define _POSIX_PATH_MAX 256
|
||||||
|
#define _POSIX_PIPE_BUF 512
|
||||||
|
#define _POSIX_RE_DUP_MAX 255
|
||||||
|
#define _POSIX_RTSIG_MAX 8
|
||||||
|
#define _POSIX_SEM_NSEMS_MAX 256
|
||||||
|
#define _POSIX_SEM_VALUE_MAX 32767
|
||||||
|
#define _POSIX_SIGQUEUE_MAX 32
|
||||||
|
#define _POSIX_SSIZE_MAX 32767
|
||||||
|
#define _POSIX_SS_REPL_MAX 4
|
||||||
|
#define _POSIX_STREAM_MAX 8
|
||||||
|
#define _POSIX_SYMLINK_MAX 255
|
||||||
|
#define _POSIX_SYMLOOP_MAX 8
|
||||||
|
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
|
||||||
|
#define _POSIX_THREAD_KEYS_MAX 128
|
||||||
|
#define _POSIX_THREAD_THREADS_MAX 64
|
||||||
|
#define _POSIX_TIMER_MAX 32
|
||||||
|
#define _POSIX_TRACE_EVENT_NAME_MAX 30
|
||||||
|
#define _POSIX_TRACE_NAME_MAX 8
|
||||||
|
#define _POSIX_TRACE_SYS_MAX 8
|
||||||
|
#define _POSIX_TRACE_USER_EVENT_MAX 32
|
||||||
|
#define _POSIX_TTY_NAME_MAX 9
|
||||||
|
#define _POSIX_TZNAME_MAX 6
|
||||||
|
#define _POSIX2_BC_BASE_MAX 99
|
||||||
|
#define _POSIX2_BC_DIM_MAX 2048
|
||||||
|
#define _POSIX2_BC_SCALE_MAX 99
|
||||||
|
#define _POSIX2_BC_STRING_MAX 1000
|
||||||
|
#define _POSIX2_CHARCLASS_NAME_MAX 14
|
||||||
|
#define _POSIX2_COLL_WEIGHTS_MAX 2
|
||||||
|
#define _POSIX2_EXPR_NEST_MAX 32
|
||||||
|
#define _POSIX2_LINE_MAX 2048
|
||||||
|
#define _POSIX2_RE_DUP_MAX 255
|
||||||
|
#define _XOPEN_IOV_MAX 16
|
||||||
|
#define _XOPEN_NAME_MAX 255
|
||||||
|
#define _XOPEN_PATH_MAX 1024
|
||||||
|
|
||||||
#define OPEN_MAX 64
|
#define OPEN_MAX 64
|
||||||
#define NAME_MAX 255
|
#define NAME_MAX 255
|
||||||
|
#define LOGIN_NAME_MAX 256
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -516,6 +516,52 @@ int putenv(char* string)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qsort_swap(void* lhs, void* rhs, size_t width)
|
||||||
|
{
|
||||||
|
uint8_t buffer[64];
|
||||||
|
size_t swapped = 0;
|
||||||
|
while (swapped < width)
|
||||||
|
{
|
||||||
|
const size_t to_swap = BAN::Math::min(width - swapped, sizeof(buffer));
|
||||||
|
memcpy(buffer, lhs, to_swap);
|
||||||
|
memcpy(lhs, rhs, to_swap);
|
||||||
|
memcpy(rhs, buffer, to_swap);
|
||||||
|
swapped += to_swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t* qsort_partition(uint8_t* pbegin, uint8_t* pend, size_t width, int (*compar)(const void*, const void*))
|
||||||
|
{
|
||||||
|
uint8_t* pivot = pend - width;
|
||||||
|
uint8_t* p1 = pbegin;
|
||||||
|
for (uint8_t* p2 = pbegin; p2 < pivot; p2 += width)
|
||||||
|
{
|
||||||
|
if (compar(p2, pivot) >= 0)
|
||||||
|
continue;
|
||||||
|
qsort_swap(p1, p2, width);
|
||||||
|
p1 += width;
|
||||||
|
}
|
||||||
|
qsort_swap(p1, pivot, width);
|
||||||
|
return p1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qsort_impl(uint8_t* pbegin, uint8_t* pend, size_t width, int (*compar)(const void*, const void*))
|
||||||
|
{
|
||||||
|
if ((pend - pbegin) / width <= 1)
|
||||||
|
return;
|
||||||
|
uint8_t* mid = qsort_partition(pbegin, pend, width, compar);
|
||||||
|
qsort_impl(pbegin, mid, width, compar);
|
||||||
|
qsort_impl(mid + width, pend, width, compar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qsort(void* base, size_t nel, size_t width, int (*compar)(const void*, const void*))
|
||||||
|
{
|
||||||
|
if (width == 0)
|
||||||
|
return;
|
||||||
|
uint8_t* pbegin = static_cast<uint8_t*>(base);
|
||||||
|
qsort_impl(pbegin, pbegin + nel * width, width, compar);
|
||||||
|
}
|
||||||
|
|
||||||
// Constants and algorithm from https://en.wikipedia.org/wiki/Permuted_congruential_generator
|
// Constants and algorithm from https://en.wikipedia.org/wiki/Permuted_congruential_generator
|
||||||
|
|
||||||
static uint64_t s_rand_state = 0x4d595df4d0f33173;
|
static uint64_t s_rand_state = 0x4d595df4d0f33173;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
#include <kernel/Syscall.h>
|
#include <kernel/Syscall.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -93,6 +94,11 @@ ssize_t pread(int fildes, void* buf, size_t nbyte, off_t offset)
|
||||||
return syscall(SYS_PREAD, fildes, buf, nbyte, offset);
|
return syscall(SYS_PREAD, fildes, buf, nbyte, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
off_t lseek(int fildes, off_t offset, int whence)
|
||||||
|
{
|
||||||
|
return syscall(SYS_SEEK, fildes, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
int dup(int fildes)
|
int dup(int fildes)
|
||||||
{
|
{
|
||||||
return syscall(SYS_DUP, fildes);
|
return syscall(SYS_DUP, fildes);
|
||||||
|
@ -460,3 +466,15 @@ int tcsetpgrp(int fildes, pid_t pgid_id)
|
||||||
{
|
{
|
||||||
return syscall(SYS_TCSETPGRP, fildes, pgid_id);
|
return syscall(SYS_TCSETPGRP, fildes, pgid_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* getlogin(void)
|
||||||
|
{
|
||||||
|
static char buffer[LOGIN_NAME_MAX];
|
||||||
|
auto* pw = getpwuid(geteuid());
|
||||||
|
if (pw == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
strncpy(buffer, pw->pw_name, LOGIN_NAME_MAX - 1);
|
||||||
|
buffer[LOGIN_NAME_MAX - 1] = '\0';
|
||||||
|
endpwent();
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <BAN/HashSet.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/Hash.h>
|
||||||
|
#include <BAN/HashSet.h>
|
||||||
|
#include <BAN/StringView.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <BAN/Vector.h>
|
|
||||||
#include <BAN/HashSet.h>
|
#include <BAN/HashSet.h>
|
||||||
|
#include <BAN/StringView.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <BAN/Endianness.h>
|
#include <BAN/Endianness.h>
|
||||||
#include <BAN/IPv4.h>
|
#include <BAN/IPv4.h>
|
||||||
#include <BAN/MAC.h>
|
#include <BAN/MAC.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/UniqPtr.h>
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
class Image
|
class Image
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
#include <pwd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
auto* pw = getpwuid(geteuid());
|
char* login = getlogin();
|
||||||
if (pw == nullptr)
|
if (login == nullptr)
|
||||||
{
|
{
|
||||||
printf("unknown user %d\n", geteuid());
|
printf("unknown user %d\n", geteuid());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("%s\n", pw->pw_name);
|
printf("%s\n", login);
|
||||||
endpwent();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue