Compare commits

...

16 Commits

Author SHA1 Message Date
0f678f845c
String: Add operator=
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-07 12:14:21 +02:00
4cac49038c
sh: Use StringBuilder instead of C-like manual joining 2023-04-07 12:11:28 +02:00
7b8260f3f6
all: Enable/disable debug symbols/optimization in COMMON_FLAGS 2023-04-07 12:07:08 +02:00
d07b00a892
all: Move all warning flags to a common CMake variable 2023-04-07 12:02:49 +02:00
4e48d024d9
libluna: Add StringBuilder 2023-04-07 11:53:52 +02:00
4c0dff9b32
libos: Remove a stray os-freestanding from the CMakeLists 2023-04-07 11:53:41 +02:00
a9b5cf99f7
UBSAN: Add __ubsan_handle_nonnull_arg 2023-04-07 11:53:19 +02:00
8e8706be27
sh: Use try_move instead of try_set
Looks like Vector does not like being copied. I'll have to look into that later...
2023-04-07 11:52:59 +02:00
1210d2b7da
libluna: Add/remove some const qualifiers 2023-04-07 11:52:20 +02:00
1c6fd95a70
Result: Add from_syscall() 2023-04-07 10:56:49 +02:00
cb67b41a39
libc: Set errno in mbstowcs() and wcstombs() 2023-04-07 10:55:22 +02:00
1f0e185904
kernel: Use try_set_value(_or_error) in various places 2023-04-07 10:55:04 +02:00
baa2296aed
Result: Add try_{set,move}_value_or_error 2023-04-07 10:43:29 +02:00
c752b2b343
libos: Put everything under the os namespace 2023-04-07 10:40:46 +02:00
f1e2937528
ArgumentParser: Parse short value arguments 2023-04-07 10:37:15 +02:00
9b8996adeb
libluna: Add String::format 2023-04-07 10:37:00 +02:00
33 changed files with 477 additions and 292 deletions

View File

@ -28,6 +28,20 @@ set(CMAKE_FIND_ROOT_PATH ${LUNA_ROOT}/toolchain/${LUNA_ARCH}-luna)
message(STATUS "Configuring Luna for ${LUNA_ARCH}") message(STATUS "Configuring Luna for ${LUNA_ARCH}")
set(COMMON_FLAGS -Wall -Wextra -Werror -Wvla
-Wdisabled-optimization -Wformat=2 -Winit-self
-Wmissing-include-dirs -Wswitch-default -Wcast-qual
-Wundef -Wcast-align -Wwrite-strings -Wlogical-op
-Wredundant-decls -Wshadow -Wconversion
-fno-asynchronous-unwind-tables -fno-omit-frame-pointer
-std=c++20 -fno-rtti -fno-exceptions)
if(LUNA_NO_OPTIMIZATIONS)
set(COMMON_FLAGS ${COMMON_FLAGS} -ggdb)
else()
set(COMMON_FLAGS ${COMMON_FLAGS} -Os)
endif()
add_subdirectory(libluna) add_subdirectory(libluna)
add_subdirectory(libos) add_subdirectory(libos)
add_subdirectory(libc) add_subdirectory(libc)

View File

@ -1,6 +1,6 @@
function(luna_app SOURCE_FILE APP_NAME) function(luna_app SOURCE_FILE APP_NAME)
add_executable(${APP_NAME} ${SOURCE_FILE}) add_executable(${APP_NAME} ${SOURCE_FILE})
target_compile_options(${APP_NAME} PRIVATE -Os -Wall -Wextra -pedantic -Werror -Wno-write-strings) target_compile_options(${APP_NAME} PRIVATE -Os ${COMMON_FLAGS} -Wno-write-strings)
add_dependencies(${APP_NAME} libc) add_dependencies(${APP_NAME} libc)
target_include_directories(${APP_NAME} PRIVATE ${LUNA_BASE}/usr/include) target_include_directories(${APP_NAME} PRIVATE ${LUNA_BASE}/usr/include)
install(TARGETS ${APP_NAME} DESTINATION ${LUNA_ROOT}/initrd/bin) install(TARGETS ${APP_NAME} DESTINATION ${LUNA_ROOT}/initrd/bin)

View File

@ -35,7 +35,7 @@ int main(int argc, char** argv)
{ {
StringView filename; StringView filename;
ArgumentParser parser; os::ArgumentParser parser;
parser.add_positional_argument(filename, "file"_sv, "-"_sv); parser.add_positional_argument(filename, "file"_sv, "-"_sv);
Vector<StringView> extra_files = parser.parse(argc, argv).value(); Vector<StringView> extra_files = parser.parse(argc, argv).value();

View File

@ -9,7 +9,7 @@ int main(int argc, char** argv)
{ {
StringView date; StringView date;
ArgumentParser parser; os::ArgumentParser parser;
parser.add_value_argument(date, 'd', "date"_sv, true); parser.add_value_argument(date, 'd', "date"_sv, true);
parser.parse(argc, argv); parser.parse(argc, argv);

View File

@ -9,7 +9,7 @@ int main(int argc, char** argv)
FILE* f; FILE* f;
StringView pathname; StringView pathname;
ArgumentParser parser; os::ArgumentParser parser;
parser.add_positional_argument(pathname, "file"_sv, true); parser.add_positional_argument(pathname, "file"_sv, true);
parser.parse(argc, argv); parser.parse(argc, argv);

View File

@ -11,7 +11,7 @@ int main(int argc, char** argv)
bool show_all { false }; bool show_all { false };
bool show_almost_all { false }; bool show_almost_all { false };
ArgumentParser parser; os::ArgumentParser parser;
parser.add_positional_argument(pathname, "directory"_sv, "/"_sv); parser.add_positional_argument(pathname, "directory"_sv, "/"_sv);
parser.add_switch_argument(show_all, 'a', "all"_sv); parser.add_switch_argument(show_all, 'a', "all"_sv);
parser.add_switch_argument(show_almost_all, 'A', "almost-all"_sv); parser.add_switch_argument(show_almost_all, 'A', "almost-all"_sv);

View File

@ -1,3 +1,4 @@
#include <luna/StringBuilder.h>
#include <luna/Vector.h> #include <luna/Vector.h>
#include <errno.h> #include <errno.h>
@ -21,7 +22,7 @@ static Result<Vector<char*>> split_command_into_argv(const char* cmd)
for (;;) for (;;)
{ {
char* segment = strtok(NULL, " \n"); segment = strtok(NULL, " \n");
TRY(result.try_append(segment)); TRY(result.try_append(segment));
if (segment == NULL) return result; if (segment == NULL) return result;
@ -30,21 +31,23 @@ static Result<Vector<char*>> split_command_into_argv(const char* cmd)
return result; return result;
} }
static char* join_path(const char* str1, const char* str2) static Result<String> join_path(const char* str1, const char* str2)
{ {
char* buf = (char*)malloc(strlen(str1) + strlen(str2) + 1); StringBuilder sb;
strlcpy(buf, str1, strlen(str1) + 1); TRY(sb.add(StringView { str1 }));
strncat(buf, str2, strlen(str2)); TRY(sb.add(StringView { str2 }));
return buf; return sb.string();
} }
static int execute_in_path(const char* dir, char** argv) static int execute_in_path(const char* dir, char** argv)
{ {
char* path = join_path(dir, argv[0]); String path;
bool ok = join_path(dir, argv[0]).try_move_value_or_error(path, errno);
if (!ok) return -1;
int err = errno; int err = errno;
int status = execv(path, argv); int status = execv(path.chars(), argv);
free(path);
if (errno == ENOENT) if (errno == ENOENT)
{ {
@ -93,16 +96,14 @@ int main()
if (child == 0) if (child == 0)
{ {
auto maybe_argv = split_command_into_argv(command); Vector<char*> argv;
if (maybe_argv.has_error()) bool ok = split_command_into_argv(command).try_move_value_or_error(argv, errno);
if (!ok)
{ {
errno = maybe_argv.error();
perror("failed to parse command"); perror("failed to parse command");
return 1; return 1;
} }
auto argv = maybe_argv.release_value();
if (argv[0] == NULL) return 0; if (argv[0] == NULL) return 0;
sh_execvp(argv.data()); sh_execvp(argv.data());
perror(argv[0]); perror(argv[0]);

View File

@ -76,13 +76,8 @@ target_link_libraries(moon luna-freestanding)
target_compile_definitions(moon PRIVATE IN_MOON) target_compile_definitions(moon PRIVATE IN_MOON)
target_compile_options(moon PRIVATE -Wall -Wextra -Werror -Wvla -Wsign-conversion) target_compile_options(moon PRIVATE ${COMMON_FLAGS})
target_compile_options(moon PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self) target_compile_options(moon PRIVATE -nostdlib -mcmodel=kernel -ffreestanding)
target_compile_options(moon PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef)
target_compile_options(moon PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion)
target_compile_options(moon PRIVATE -fno-rtti -ffreestanding -fno-exceptions)
target_compile_options(moon PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer)
target_compile_options(moon PRIVATE -nostdlib -mcmodel=kernel)
if("${LUNA_ARCH}" MATCHES "x86_64") if("${LUNA_ARCH}" MATCHES "x86_64")
target_compile_options(moon PRIVATE -mno-red-zone) target_compile_options(moon PRIVATE -mno-red-zone)
@ -90,12 +85,8 @@ if("${LUNA_ARCH}" MATCHES "x86_64")
target_link_options(moon PRIVATE -mno-red-zone) target_link_options(moon PRIVATE -mno-red-zone)
endif() endif()
if(MOON_DEBUG_SYMBOLS) if(MOON_DEBUG)
message(STATUS "Building Moon with debug symbols")
target_compile_options(moon PRIVATE -ggdb)
include(debug.cmake) include(debug.cmake)
else()
target_compile_options(moon PRIVATE -Os)
endif() endif()
target_link_options(moon PRIVATE -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mcmodel=kernel) target_link_options(moon PRIVATE -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mcmodel=kernel)

View File

@ -30,10 +30,9 @@ namespace KernelVM
{ {
auto kernelvm_bitmap = g_kernelvm_bitmap.lock(); auto kernelvm_bitmap = g_kernelvm_bitmap.lock();
const auto maybe_index = kernelvm_bitmap->find_and_toggle(false); usize index;
if (!maybe_index.has_value()) return err(ENOMEM); bool ok = kernelvm_bitmap->find_and_toggle(false).try_set_value(index);
if (!ok) return err(ENOMEM);
const usize index = maybe_index.value();
g_used_vm += ARCH_PAGE_SIZE; g_used_vm += ARCH_PAGE_SIZE;

View File

@ -139,10 +139,9 @@ namespace MemoryManager
{ {
auto frame_bitmap = g_frame_bitmap.lock(); auto frame_bitmap = g_frame_bitmap.lock();
const auto maybe_index = frame_bitmap->find_and_toggle(false, start_index); usize index;
if (!maybe_index.has_value()) return err(ENOMEM); bool ok = frame_bitmap->find_and_toggle(false, start_index).try_set_value(index);
if (!ok) return err(ENOMEM);
const usize index = maybe_index.value();
start_index = index + 1; start_index = index + 1;

View File

@ -65,15 +65,13 @@ Result<bool> UserVM::try_expand(usize size)
Result<u64> UserVM::alloc_one_page() Result<u64> UserVM::alloc_one_page()
{ {
u64 index; u64 index;
const auto maybe_index = m_bitmap.find_and_toggle(false); bool ok = m_bitmap.find_and_toggle(false).try_set_value(index);
if (!maybe_index.has_value()) if (!ok)
{ {
bool success = TRY(try_expand()); bool success = TRY(try_expand());
if (!success) return err(ENOMEM); if (!success) return err(ENOMEM);
index = TRY(Result<u64>::from_option(m_bitmap.find_and_toggle(false), ENOMEM)); index = TRY(Result<u64>::from_option(m_bitmap.find_and_toggle(false), ENOMEM));
} }
else
index = maybe_index.value();
return VM_BASE + index * ARCH_PAGE_SIZE; return VM_BASE + index * ARCH_PAGE_SIZE;
} }
@ -81,15 +79,13 @@ Result<u64> UserVM::alloc_one_page()
Result<u64> UserVM::alloc_several_pages(usize count) Result<u64> UserVM::alloc_several_pages(usize count)
{ {
u64 index; u64 index;
const auto maybe_index = m_bitmap.find_and_toggle_region(false, count); bool ok = m_bitmap.find_and_toggle_region(false, count).try_set_value(index);
if (!maybe_index.has_value()) if (!ok)
{ {
bool success = TRY(try_expand((count / 8) + INITIAL_VM_SIZE)); bool success = TRY(try_expand((count / 8) + INITIAL_VM_SIZE));
if (!success) return err(ENOMEM); if (!success) return err(ENOMEM);
index = TRY(Result<u64>::from_option(m_bitmap.find_and_toggle_region(false, count), ENOMEM)); index = TRY(Result<u64>::from_option(m_bitmap.find_and_toggle_region(false, count), ENOMEM));
} }
else
index = maybe_index.value();
return VM_BASE + index * ARCH_PAGE_SIZE; return VM_BASE + index * ARCH_PAGE_SIZE;
} }

View File

@ -19,13 +19,12 @@ Result<u64> sys_getdents(Registers*, SyscallArgs args)
usize nwrite = 0; usize nwrite = 0;
while (nwrite < count) while (nwrite < count)
{ {
auto maybe_entry = descriptor.inode->get(descriptor.offset); VFS::DirectoryEntry entry;
if (!maybe_entry.has_value()) break; bool ok = descriptor.inode->get(descriptor.offset).try_set_value(entry);
if (!ok) break;
descriptor.offset++; descriptor.offset++;
auto entry = maybe_entry.release_value();
luna_dirent kent; luna_dirent kent;
kent.inode = entry.inode->inode_number(); kent.inode = entry.inode->inode_number();
strlcpy(kent.name, entry.name.chars(), entry.name.length() + 1); strlcpy(kent.name, entry.name.chars(), entry.name.length() + 1);

View File

@ -24,27 +24,27 @@ Result<u64> sys_open(Registers*, SyscallArgs args)
// Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR // Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR
if ((flags & O_RDWR) == 0) { return err(EINVAL); } if ((flags & O_RDWR) == 0) { return err(EINVAL); }
auto maybe_inode = VFS::resolve_path(path.chars()); int error;
if (maybe_inode.has_error()) bool ok = VFS::resolve_path(path.chars()).try_set_value_or_error(inode, error);
if (!ok)
{ {
if (maybe_inode.error() == ENOENT && (flags & O_CREAT)) if (error == ENOENT && (flags & O_CREAT))
{ {
inode = TRY(VFS::create_file(path.chars())); inode = TRY(VFS::create_file(path.chars()));
inode->chmod(mode); inode->chmod(mode);
} }
else else
return maybe_inode.release_error(); return err(error);
} }
else if (flags & O_EXCL) else if (flags & O_EXCL)
return err(EEXIST); return err(EEXIST);
else else
{ {
inode = maybe_inode.release_value();
if ((flags & O_RDONLY) && (inode->mode() & S_IRUSR) == 0) return err(EACCES); if ((flags & O_RDONLY) && (inode->mode() & S_IRUSR) == 0) return err(EACCES);
if ((flags & O_WRONLY) && (inode->mode() & S_IWUSR) == 0) return err(EACCES); if ((flags & O_WRONLY) && (inode->mode() & S_IWUSR) == 0) return err(EACCES);
} }
if(inode->type() != VFS::InodeType::Directory && (flags & O_DIRECTORY)) return err(ENOTDIR); if (inode->type() != VFS::InodeType::Directory && (flags & O_DIRECTORY)) return err(ENOTDIR);
if ((flags & O_WRONLY) && (flags & O_TRUNC)) inode->truncate(0); if ((flags & O_WRONLY) && (flags & O_TRUNC)) inode->truncate(0);

View File

@ -40,8 +40,7 @@ target_link_libraries(bare_libc PUBLIC luna)
target_include_directories(bare_libc PUBLIC include/) target_include_directories(bare_libc PUBLIC include/)
target_compile_options(bare_libc PRIVATE -Os -Wall -Wextra -Werror -nostdlib) target_compile_options(bare_libc PRIVATE ${COMMON_FLAGS})
target_compile_options(bare_libc PRIVATE -fno-exceptions -fno-rtti)
target_link_options(bare_libc PRIVATE -nostdlib) target_link_options(bare_libc PRIVATE -nostdlib)

View File

@ -33,7 +33,7 @@ extern "C"
long rc = syscall(SYS_getdents, stream->_fd, &ent, 1); long rc = syscall(SYS_getdents, stream->_fd, &ent, 1);
if (rc < 0) if (rc < 0)
{ {
errno = -rc; errno = (int)-rc;
return nullptr; return nullptr;
} }

View File

@ -278,19 +278,19 @@ extern "C"
int vfprintf(FILE* stream, const char* format, va_list ap) int vfprintf(FILE* stream, const char* format, va_list ap)
{ {
usize rc = cstyle_format( usize count = cstyle_format(
format, format,
[](char c, void* f) -> Result<void> { [](char c, void* f) -> Result<void> {
int rc = fputc(c, (FILE*)f); int rc = fputc(c, (FILE*)f);
if (rc == EOF) return err(errno); if (rc == EOF) return err(errno);
return {}; return {};
}, },
stream, ap) stream, ap)
.value_or(-1); .value_or(-1);
if (rc == (usize)-1) return -1; if (count == (usize)-1) return -1;
return (int)rc; return (int)count;
} }
int fprintf(FILE* stream, const char* format, ...) int fprintf(FILE* stream, const char* format, ...)

View File

@ -107,23 +107,35 @@ extern "C"
size_t mbstowcs(wchar_t* buf, const char* src, size_t max) size_t mbstowcs(wchar_t* buf, const char* src, size_t max)
{ {
if (max == 0) return 0; if (max == 0) return 0;
size_t result = (size_t)-1;
Utf8StringDecoder decoder(src); Utf8StringDecoder decoder(src);
if (!buf) { return decoder.code_points().value_or((size_t)-1); } if (!buf)
{
decoder.code_points().try_set_value_or_error(result, errno);
return result;
}
return decoder.decode(buf, max).value_or((size_t)-1); decoder.decode(buf, max).try_set_value_or_error(result, errno);
return result;
} }
size_t wcstombs(char* buf, const wchar_t* src, size_t max) size_t wcstombs(char* buf, const wchar_t* src, size_t max)
{ {
if (max == 0) return 0; if (max == 0) return 0;
size_t result = (size_t)-1;
Utf8StringEncoder encoder(src); Utf8StringEncoder encoder(src);
if (!buf) { return encoder.byte_length().value_or((size_t)-1); } if (!buf)
{
encoder.byte_length().try_set_value_or_error(result, errno);
return result;
}
return encoder.encode(buf, max).value_or((size_t)-1); encoder.encode(buf, max).try_set_value_or_error(result, errno);
return result;
} }
void* malloc(size_t size) void* malloc(size_t size)

View File

@ -14,6 +14,7 @@ set(FREESTANDING_SOURCES
src/Buffer.cpp src/Buffer.cpp
src/Stack.cpp src/Stack.cpp
src/String.cpp src/String.cpp
src/StringBuilder.cpp
src/StringView.cpp src/StringView.cpp
src/Utf8.cpp src/Utf8.cpp
src/TarStream.cpp src/TarStream.cpp
@ -32,24 +33,15 @@ set(SOURCES
add_library(luna-freestanding ${FREESTANDING_SOURCES}) add_library(luna-freestanding ${FREESTANDING_SOURCES})
target_compile_definitions(luna-freestanding PRIVATE USE_FREESTANDING) target_compile_definitions(luna-freestanding PRIVATE USE_FREESTANDING)
target_compile_options(luna-freestanding PRIVATE -Os -Wall -Wextra -Werror -Wvla) target_compile_options(luna-freestanding PRIVATE ${COMMON_FLAGS})
target_compile_options(luna-freestanding PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self -Wsign-conversion) target_compile_options(luna-freestanding PRIVATE -nostdlib -mcmodel=kernel -ffreestanding)
target_compile_options(luna-freestanding PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef)
target_compile_options(luna-freestanding PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion)
target_compile_options(luna-freestanding PRIVATE -fno-rtti -ffreestanding -fno-exceptions)
target_compile_options(luna-freestanding PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer)
target_compile_options(luna-freestanding PRIVATE -nostdlib -mcmodel=kernel)
target_include_directories(luna-freestanding PUBLIC include/) target_include_directories(luna-freestanding PUBLIC include/)
target_include_directories(luna-freestanding PRIVATE ${LUNA_ROOT}/kernel/src) target_include_directories(luna-freestanding PRIVATE ${LUNA_ROOT}/kernel/src)
set_target_properties(luna-freestanding PROPERTIES CXX_STANDARD 20) set_target_properties(luna-freestanding PROPERTIES CXX_STANDARD 20)
add_library(luna ${SOURCES}) add_library(luna ${SOURCES})
target_compile_options(luna PRIVATE -Os -Wall -Wextra -Werror -Wvla) target_compile_options(luna PRIVATE ${COMMON_FLAGS})
target_compile_options(luna PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self)
target_compile_options(luna PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef)
target_compile_options(luna PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion)
target_compile_options(luna PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -std=c++20 -fno-rtti -fno-exceptions)
target_include_directories(luna PUBLIC include/) target_include_directories(luna PUBLIC include/)
target_include_directories(luna PUBLIC ${LUNA_BASE}/usr/include) target_include_directories(luna PUBLIC ${LUNA_BASE}/usr/include)
@ -59,9 +51,3 @@ target_compile_options(luna-freestanding PRIVATE -mno-80387 -mno-mmx -mno-sse -m
target_compile_definitions(luna-freestanding PUBLIC ARCH_X86_64) target_compile_definitions(luna-freestanding PUBLIC ARCH_X86_64)
target_compile_definitions(luna PUBLIC ARCH_X86_64) target_compile_definitions(luna PUBLIC ARCH_X86_64)
endif() endif()
if(LUNA_DEBUG_SYMBOLS)
message(STATUS "Building Luna with debug symbols")
target_compile_options(luna PRIVATE -ggdb)
target_compile_options(luna-freestanding PRIVATE -ggdb)
endif()

View File

@ -19,7 +19,7 @@ class Buffer
Result<u8*> slice(usize offset, usize size); Result<u8*> slice(usize offset, usize size);
Result<void> append_data(u8* data, usize size); Result<void> append_data(const u8* data, usize size);
u8* data() u8* data()
{ {

View File

@ -110,11 +110,25 @@ template <typename T> class Result
return m_value.try_set_value(ref); return m_value.try_set_value(ref);
} }
bool try_set_value_or_error(T& ref, int& err) const
{
bool ok = m_value.try_set_value(ref);
if (!ok) err = m_error;
return ok;
}
bool try_move_value(T& ref) bool try_move_value(T& ref)
{ {
return m_value.try_move_value(ref); return m_value.try_move_value(ref);
} }
bool try_move_value_or_error(T& ref, int& err)
{
bool ok = m_value.try_move_value(ref);
if (!ok) err = m_error;
return ok;
}
T release_value(SourceLocation caller = SourceLocation::current()) T release_value(SourceLocation caller = SourceLocation::current())
{ {
expect_at(has_value(), caller, "Result::release_value() called on a Result that holds an error"); expect_at(has_value(), caller, "Result::release_value() called on a Result that holds an error");
@ -134,6 +148,13 @@ template <typename T> class Result
return Error { error }; return Error { error };
} }
static Result<T> from_syscall(long rc)
{
if (rc < 0) return Error { (int)-rc };
else
return (T)rc;
}
private: private:
Option<T> m_value; Option<T> m_value;
int m_error; int m_error;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <luna/Result.h> #include <luna/Result.h>
#include <luna/StringView.h> #include <luna/StringView.h>
#include <stdarg.h>
class String class String
{ {
@ -16,12 +17,18 @@ class String
String(String&&); String(String&&);
String(const String&) = delete; String(const String&) = delete;
String& operator=(String&&);
String& operator=(const String&) = delete;
~String(); ~String();
Result<String> clone() const; Result<String> clone() const;
Result<String> substring(usize begin, usize size) const; Result<String> substring(usize begin, usize size) const;
static Result<String> format(const String& fmt, ...);
static Result<String> format(StringView fmt, ...);
static Result<String> from_cstring(const char* str); static Result<String> from_cstring(const char* str);
const char* chars() const const char* chars() const
@ -75,4 +82,6 @@ class String
bool m_inline { true }; bool m_inline { true };
usize m_length { 0 }; usize m_length { 0 };
static Result<String> vformat(StringView fmt, va_list ap);
}; };

View File

@ -0,0 +1,22 @@
#pragma once
#include <luna/Buffer.h>
#include <luna/String.h>
class StringBuilder
{
public:
Result<void> add(const String& value);
Result<void> add(StringView value);
Result<void> add(void* value);
Result<void> add(long value);
Result<void> add(unsigned long value);
Result<void> add(char value);
Result<void> format(StringView fmt, ...);
Result<void> vformat(StringView fmt, va_list ap);
Result<String> string();
private:
Buffer m_data;
};

View File

@ -70,5 +70,11 @@ namespace UBSAN
{ {
SourceLocation location; SourceLocation location;
}; };
struct NonnullArgInfo
{
SourceLocation location;
SourceLocation attr_location;
};
} }
} }

View File

@ -2,5 +2,4 @@
#include <luna/Result.h> #include <luna/Result.h>
#include <luna/String.h> #include <luna/String.h>
usize to_dynamic_unit_cstr(usize value, char* buffer, usize max);
Result<String> to_dynamic_unit(usize value); Result<String> to_dynamic_unit(usize value);

View File

@ -46,7 +46,7 @@ Result<u8*> Buffer::slice(usize offset, usize size)
return m_data + offset; return m_data + offset;
} }
Result<void> Buffer::append_data(u8* data, usize size) Result<void> Buffer::append_data(const u8* data, usize size)
{ {
memcpy(TRY(slice_at_end(size)), data, size); memcpy(TRY(slice_at_end(size)), data, size);

View File

@ -1,6 +1,8 @@
#include <luna/Alloc.h> #include <luna/Alloc.h>
#include <luna/CString.h> #include <luna/CString.h>
#include <luna/Format.h>
#include <luna/String.h> #include <luna/String.h>
#include <luna/Vector.h>
String::String() String::String()
{ {
@ -21,6 +23,24 @@ String::String(String&& other)
other.m_string = nullptr; other.m_string = nullptr;
} }
String& String::operator=(String&& other)
{
if (&other == this) return *this;
if (!m_inline) free_impl(m_string);
m_inline = other.m_inline;
m_string = other.m_string;
m_length = other.m_length;
if (m_inline) memcpy(m_inline_storage, other.m_inline_storage, sizeof(m_inline_storage));
other.m_string = nullptr;
return *this;
}
String::String(char* c_str) String::String(char* c_str)
{ {
check(c_str); check(c_str);
@ -61,6 +81,43 @@ const char& String::operator[](usize index) const
return chars()[index]; return chars()[index];
} }
Result<String> String::format(const String& fmt, ...)
{
va_list ap;
va_start(ap, fmt);
auto rc = vformat(fmt.view(), ap);
va_end(ap);
return rc;
}
Result<String> String::format(StringView fmt, ...)
{
va_list ap;
va_start(ap, fmt);
auto rc = vformat(fmt, ap);
va_end(ap);
return rc;
}
Result<String> String::vformat(StringView fmt, va_list ap)
{
Vector<char> buf;
TRY(cstyle_format(
fmt.chars(), [](char c, void* data) -> Result<void> { return ((Vector<char>*)data)->try_append(c); }, &buf,
ap));
TRY(buf.try_append(0));
return from_cstring(buf.data());
}
Result<String> String::from_cstring(const char* str) Result<String> String::from_cstring(const char* str)
{ {
usize len = strlen(str); usize len = strlen(str);

View File

@ -0,0 +1,65 @@
#include <luna/Format.h>
#include <luna/StringBuilder.h>
#include <luna/Vector.h>
Result<void> StringBuilder::add(StringView value)
{
return m_data.append_data((const u8*)value.chars(), value.length());
}
Result<void> StringBuilder::add(const String& value)
{
return add(value.view());
}
Result<void> StringBuilder::add(void* value)
{
return format("%p"_sv, value);
}
Result<void> StringBuilder::add(long value)
{
return format("%li"_sv, value);
}
Result<void> StringBuilder::add(unsigned long value)
{
return format("%lu"_sv, value);
}
Result<void> StringBuilder::add(char value)
{
return format("%c"_sv, value);
}
Result<void> StringBuilder::format(StringView fmt, ...)
{
va_list ap;
va_start(ap, fmt);
auto rc = vformat(fmt, ap);
va_end(ap);
return rc;
}
Result<void> StringBuilder::vformat(StringView fmt, va_list ap)
{
Vector<char> temp;
TRY(cstyle_format(
fmt.chars(), [](char c, void* buf) -> Result<void> { return ((Vector<char>*)buf)->try_append(c); }, &temp, ap));
TRY(m_data.append_data((u8*)temp.data(), temp.size()));
return {};
}
Result<String> StringBuilder::string()
{
char nul = '\0';
TRY(m_data.append_data((u8*)&nul, 1));
return String::from_cstring((const char*)m_data.data());
}

View File

@ -118,4 +118,10 @@ extern "C"
}; };
__ubsan_handle_type_mismatch(&info, pointer); __ubsan_handle_type_mismatch(&info, pointer);
} }
void __ubsan_handle_nonnull_arg(NonnullArgInfo* info, intptr_t)
{
dbgln("ubsan: null argument at %s:%d:%d", DISPLAY(info->location));
ub_panic();
}
} }

View File

@ -1,12 +1,11 @@
#include <luna/Alloc.h> #include <luna/Alloc.h>
#include <luna/Format.h>
#include <luna/Result.h> #include <luna/Result.h>
#include <luna/ScopeGuard.h> #include <luna/ScopeGuard.h>
#include <luna/Units.h> #include <luna/Units.h>
usize to_dynamic_unit_cstr(usize value, char* buffer, usize max) Result<String> to_dynamic_unit(usize value)
{ {
if (value < 1024) { return string_format(buffer, max, "%zu bytes", value); } if (value < 1024) { return String::format("%zu bytes"_sv, value); }
const char* unit_prefixes = "KMGTPE"; const char* unit_prefixes = "KMGTPE";
while (value > (1024 * 1024)) while (value > (1024 * 1024))
@ -15,14 +14,5 @@ usize to_dynamic_unit_cstr(usize value, char* buffer, usize max)
unit_prefixes++; unit_prefixes++;
} }
return string_format(buffer, max, "%zu.%zu %ciB", value / 1024, (value % 1024) / 103, *unit_prefixes); return String::format("%zu.%zu %ciB"_sv, value / 1024, (value % 1024) / 103, *unit_prefixes);
}
Result<String> to_dynamic_unit(usize value)
{
char* const buf = TRY(make_array<char>(64));
to_dynamic_unit_cstr(value, buf, 64);
return String { buf };
} }

View File

@ -8,20 +8,10 @@ set(SOURCES
) )
add_library(os ${SOURCES}) add_library(os ${SOURCES})
target_compile_options(os PRIVATE -Os -Wall -Wextra -Werror -Wvla) target_compile_options(os PRIVATE ${COMMON_FLAGS})
target_compile_options(os PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self)
target_compile_options(os PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef)
target_compile_options(os PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion)
target_compile_options(os PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -std=c++20 -fno-rtti -fno-exceptions)
target_include_directories(os PUBLIC include/) target_include_directories(os PUBLIC include/)
target_include_directories(os PUBLIC ${LUNA_BASE}/usr/include) target_include_directories(os PUBLIC ${LUNA_BASE}/usr/include)
if("${LUNA_ARCH}" MATCHES "x86_64") if("${LUNA_ARCH}" MATCHES "x86_64")
target_compile_definitions(os PUBLIC ARCH_X86_64) target_compile_definitions(os PUBLIC ARCH_X86_64)
endif() endif()
if(LUNA_DEBUG_SYMBOLS)
message(STATUS "Building libOS with debug symbols")
target_compile_options(os PRIVATE -ggdb)
target_compile_options(os-freestanding PRIVATE -ggdb)
endif()

View File

@ -2,47 +2,50 @@
#include <luna/StringView.h> #include <luna/StringView.h>
#include <luna/Vector.h> #include <luna/Vector.h>
class ArgumentParser namespace os
{ {
public: class ArgumentParser
ArgumentParser() = default;
Result<void> add_positional_argument(StringView& out, StringView name, bool required);
Result<void> add_positional_argument(StringView& out, StringView name, StringView fallback);
Result<void> add_switch_argument(bool& out, char short_flag, StringView long_flag);
Result<void> add_value_argument(StringView& out, char short_flag, StringView long_flag, bool value_required);
Result<void> add_value_argument(StringView& out, char short_flag, StringView long_flag, StringView fallback);
Result<Vector<StringView>> parse(int argc, char* const* argv);
private:
struct PositionalArgument
{ {
StringView* out; public:
StringView name; ArgumentParser() = default;
bool required;
StringView fallback;
};
struct SwitchArgument Result<void> add_positional_argument(StringView& out, StringView name, bool required);
{ Result<void> add_positional_argument(StringView& out, StringView name, StringView fallback);
bool* out;
char short_flag;
StringView long_flag;
};
struct ValueArgument Result<void> add_switch_argument(bool& out, char short_flag, StringView long_flag);
{
StringView* out;
char short_flag;
StringView long_flag;
bool required;
StringView fallback;
};
Vector<PositionalArgument> m_positional_args; Result<void> add_value_argument(StringView& out, char short_flag, StringView long_flag, bool value_required);
Vector<SwitchArgument> m_switch_args; Result<void> add_value_argument(StringView& out, char short_flag, StringView long_flag, StringView fallback);
Vector<ValueArgument> m_value_args;
}; Result<Vector<StringView>> parse(int argc, char* const* argv);
private:
struct PositionalArgument
{
StringView* out;
StringView name;
bool required;
StringView fallback;
};
struct SwitchArgument
{
bool* out;
char short_flag;
StringView long_flag;
};
struct ValueArgument
{
StringView* out;
char short_flag;
StringView long_flag;
bool required;
StringView fallback;
};
Vector<PositionalArgument> m_positional_args;
Vector<SwitchArgument> m_switch_args;
Vector<ValueArgument> m_value_args;
};
}

View File

@ -2,130 +2,94 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
Result<void> ArgumentParser::add_positional_argument(StringView& out, StringView name, bool required) namespace os
{ {
PositionalArgument arg { &out, name, required, {} }; Result<void> ArgumentParser::add_positional_argument(StringView& out, StringView name, bool required)
return m_positional_args.try_append(move(arg));
}
Result<void> ArgumentParser::add_positional_argument(StringView& out, StringView name, StringView fallback)
{
PositionalArgument arg { &out, name, false, fallback };
return m_positional_args.try_append(move(arg));
}
Result<void> ArgumentParser::add_switch_argument(bool& out, char short_flag, StringView long_flag)
{
SwitchArgument arg { &out, short_flag, long_flag };
return m_switch_args.try_append(move(arg));
}
Result<void> ArgumentParser::add_value_argument(StringView& out, char short_flag, StringView long_flag,
bool value_required)
{
ValueArgument arg { &out, short_flag, long_flag, value_required, {} };
return m_value_args.try_append(move(arg));
}
Result<void> ArgumentParser::add_value_argument(StringView& out, char short_flag, StringView long_flag,
StringView fallback)
{
ValueArgument arg { &out, short_flag, long_flag, false, fallback };
return m_value_args.try_append(move(arg));
}
static bool looks_like_short_flag(StringView arg)
{
return arg.length() > 1 && arg[0] == '-';
}
static bool looks_like_long_flag(StringView arg)
{
return arg.length() > 2 && arg[0] == '-' && arg[1] == '-';
}
Result<Vector<StringView>> ArgumentParser::parse(int argc, char* const* argv)
{
StringView program_name = argv[0];
Vector<StringView> leftovers;
Option<ValueArgument> current_value_argument = {};
bool is_parsing_value_argument = false;
bool is_still_parsing_flags = true;
for (int i = 1; i < argc; i++)
{ {
StringView arg = argv[i]; PositionalArgument arg { &out, name, required, {} };
if (is_parsing_value_argument) return m_positional_args.try_append(move(arg));
{ }
*current_value_argument->out = arg;
is_parsing_value_argument = false;
continue;
}
if (is_still_parsing_flags) Result<void> ArgumentParser::add_positional_argument(StringView& out, StringView name, StringView fallback)
{
PositionalArgument arg { &out, name, false, fallback };
return m_positional_args.try_append(move(arg));
}
Result<void> ArgumentParser::add_switch_argument(bool& out, char short_flag, StringView long_flag)
{
SwitchArgument arg { &out, short_flag, long_flag };
return m_switch_args.try_append(move(arg));
}
Result<void> ArgumentParser::add_value_argument(StringView& out, char short_flag, StringView long_flag,
bool value_required)
{
ValueArgument arg { &out, short_flag, long_flag, value_required, {} };
return m_value_args.try_append(move(arg));
}
Result<void> ArgumentParser::add_value_argument(StringView& out, char short_flag, StringView long_flag,
StringView fallback)
{
ValueArgument arg { &out, short_flag, long_flag, false, fallback };
return m_value_args.try_append(move(arg));
}
static bool looks_like_short_flag(StringView arg)
{
return arg.length() > 1 && arg[0] == '-';
}
static bool looks_like_long_flag(StringView arg)
{
return arg.length() > 2 && arg[0] == '-' && arg[1] == '-';
}
Result<Vector<StringView>> ArgumentParser::parse(int argc, char* const* argv)
{
StringView program_name = argv[0];
Vector<StringView> leftovers;
Option<ValueArgument> current_value_argument = {};
bool is_parsing_value_argument = false;
bool is_still_parsing_flags = true;
for (int i = 1; i < argc; i++)
{ {
if (arg == "--") StringView arg = argv[i];
if (is_parsing_value_argument)
{ {
is_still_parsing_flags = false; *current_value_argument->out = arg;
is_parsing_value_argument = false;
continue; continue;
} }
if (looks_like_long_flag(arg)) if (is_still_parsing_flags)
{ {
StringView flag = &arg[2]; if (arg == "--")
bool found = false;
for (const auto& current : m_switch_args)
{ {
if (current.long_flag == flag) is_still_parsing_flags = false;
{ continue;
*current.out = true;
found = true;
break;
}
} }
for (const auto& current : m_value_args) if (looks_like_long_flag(arg))
{ {
if (current.long_flag == flag) StringView flag = &arg[2];
{
current_value_argument = current;
is_parsing_value_argument = true;
found = true;
break;
}
}
if (found) continue;
fprintf(stderr, "%s: unrecognized option '%s'\n", program_name.chars(), arg.chars());
exit(1);
}
else if (looks_like_short_flag(arg))
{
StringView flags = &arg[1];
for (char c : flags)
{
bool found = false; bool found = false;
// FIXME: Implement value arguments for short flags.
for (const auto& current : m_switch_args) for (const auto& current : m_switch_args)
{ {
if (current.short_flag == ' ') continue; if (current.long_flag == flag)
if (current.short_flag == c)
{ {
*current.out = true; *current.out = true;
found = true; found = true;
@ -133,47 +97,104 @@ Result<Vector<StringView>> ArgumentParser::parse(int argc, char* const* argv)
} }
} }
for (const auto& current : m_value_args)
{
if (current.long_flag == flag)
{
current_value_argument = current;
is_parsing_value_argument = true;
found = true;
break;
}
}
if (found) continue; if (found) continue;
fprintf(stderr, "%s: invalid option -- '%c'\n", program_name.chars(), c); fprintf(stderr, "%s: unrecognized option '%s'\n", program_name.chars(), arg.chars());
exit(1); exit(1);
} }
else if (looks_like_short_flag(arg))
{
StringView flags = &arg[1];
for (usize j = 0; j < flags.length(); j++)
{
char c = flags[j];
bool found = false;
// Last flag, this could be a value flag
if (j + 1 == flags.length())
{
for (const auto& current : m_value_args)
{
if (current.short_flag == ' ') continue;
if (current.short_flag == c)
{
current_value_argument = current;
is_parsing_value_argument = true;
found = true;
break;
}
}
if (found) continue;
}
for (const auto& current : m_switch_args)
{
if (current.short_flag == ' ') continue;
if (current.short_flag == c)
{
*current.out = true;
found = true;
break;
}
}
if (found) continue;
fprintf(stderr, "%s: invalid option -- '%c'\n", program_name.chars(), c);
exit(1);
}
continue;
}
}
Option<PositionalArgument> current = m_positional_args.try_dequeue();
if (!current.has_value())
{
TRY(leftovers.try_append(arg));
continue; continue;
} }
*current->out = arg;
} }
Option<PositionalArgument> current = m_positional_args.try_dequeue(); if (is_parsing_value_argument)
if (!current.has_value())
{ {
TRY(leftovers.try_append(arg)); if (current_value_argument->required)
continue; {
fprintf(stderr, "%s: option '--%s' requires an argument\n", program_name.chars(),
current_value_argument->long_flag.chars());
exit(1);
}
else { *current_value_argument->out = current_value_argument->fallback; }
} }
*current->out = arg; // Loop through all remaining positional arguments.
} for (const auto& arg : m_positional_args)
if (is_parsing_value_argument)
{
if (current_value_argument->required)
{ {
fprintf(stderr, "%s: option '--%s' requires an argument\n", program_name.chars(), if (arg.required)
current_value_argument->long_flag.chars()); {
exit(1); fprintf(stderr, "%s: required argument '%s' not provided\n", program_name.chars(), arg.name.chars());
exit(1);
}
else { *arg.out = arg.fallback; }
} }
else { *current_value_argument->out = current_value_argument->fallback; }
}
// Loop through all remaining positional arguments. return leftovers;
for (const auto& arg : m_positional_args)
{
if (arg.required)
{
fprintf(stderr, "%s: required argument '%s' not provided\n", program_name.chars(), arg.name.chars());
exit(1);
}
else { *arg.out = arg.fallback; }
} }
return leftovers;
} }

View File

@ -11,7 +11,7 @@ tools/full-clean.sh
tools/install-headers.sh tools/install-headers.sh
cmake -S . -B $LUNA_BUILD_DIR -DMOON_DEBUG_SYMBOLS=ON -DLUNA_DEBUG_SYMBOLS=ON -G "$LUNA_CMAKE_GENERATOR_NAME" cmake -S . -B $LUNA_BUILD_DIR -DLUNA_NO_OPTIMIZATIONS=ON -DMOON_DEBUG=ON -G "$LUNA_CMAKE_GENERATOR_NAME"
cmake --build $LUNA_BUILD_DIR cmake --build $LUNA_BUILD_DIR
cmake --install $LUNA_BUILD_DIR cmake --install $LUNA_BUILD_DIR