Compare commits
73 Commits
6eea3bda06
...
8ab823fc43
Author | SHA1 | Date | |
---|---|---|---|
8ab823fc43 | |||
a2b6149f50 | |||
d5d21e1eb0 | |||
e85dc97e91 | |||
2c7ae3c61b | |||
f0f1a9c46c | |||
1d4055411d | |||
033b4c3db8 | |||
744ca07799 | |||
8f0356700c | |||
dad573f1fe | |||
870cb867ee | |||
11d47c3982 | |||
2eb973ca2b | |||
a227578107 | |||
8e28d45b9c | |||
f8e6b45dd2 | |||
ff68f574ff | |||
da6daff8c7 | |||
09cb378a7a | |||
d58a56a1d1 | |||
096a4e7953 | |||
9c30641587 | |||
75b3e78d34 | |||
d801fe6bb8 | |||
41f9d8cadd | |||
36cc66c2e9 | |||
d6b75f5981 | |||
c6bff6f8b4 | |||
03bde69c65 | |||
9752ab29d3 | |||
2445c2f6aa | |||
7aaa05ded6 | |||
3253151cb7 | |||
e28f8f7520 | |||
65aa931931 | |||
2192399ca2 | |||
0df32b92b3 | |||
baab157431 | |||
0fcc5b9a5e | |||
92a4174f02 | |||
48e97de59c | |||
f092e41247 | |||
c5ffbae6a0 | |||
790d9d119b | |||
554a8ee300 | |||
1caf80bde2 | |||
5b496791c5 | |||
fd99fc88ee | |||
4ac0adee57 | |||
432a5c27cb | |||
8e01e2cd77 | |||
ee7671a8cb | |||
efa96655f3 | |||
a7c4e8900c | |||
f7763ca2bc | |||
f104d491e0 | |||
786bec0b18 | |||
57e1f49a32 | |||
b49d9d55b7 | |||
99080b8c50 | |||
9ecf259c71 | |||
dc107d14d7 | |||
d39f0387fe | |||
1fa0bbfa37 | |||
39296773d2 | |||
d328c722f0 | |||
2177828456 | |||
3252612d90 | |||
48a7ffcce8 | |||
57a05b73f3 | |||
60dc10d4fc | |||
a8379b6c73 |
@ -261,7 +261,7 @@ static Result<void> load_service(const os::Path& path)
|
|||||||
|
|
||||||
if (service.command.is_empty())
|
if (service.command.is_empty())
|
||||||
{
|
{
|
||||||
do_log("[init] service file is missing 'Command' entry, aborting!\n");
|
do_log("[init] service file is missing 'Command' or 'Script' entry, aborting!\n");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
username = name.view();
|
username = name.view();
|
||||||
}
|
}
|
||||||
|
|
||||||
execl("/usr/bin/su", "login", "-lp", "--", username.chars(), nullptr);
|
execl("/bin/su", "login", "-lp", "--", username.chars(), nullptr);
|
||||||
|
|
||||||
perror("su");
|
perror("su");
|
||||||
return 1;
|
return 1;
|
||||||
|
66
apps/ls.cpp
66
apps/ls.cpp
@ -8,7 +8,6 @@
|
|||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
#include <os/Mode.h>
|
#include <os/Mode.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
void find_user_and_group(struct stat& st, StringView& owner, StringView& group)
|
void find_user_and_group(struct stat& st, StringView& owner, StringView& group)
|
||||||
{
|
{
|
||||||
@ -48,46 +47,18 @@ int sort_reverse(const os::Directory::Entry* a, const os::Directory::Entry* b)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RESET_COLORS "\x1b[m"
|
static Result<String> entry_join(const Vector<os::Directory::Entry>& vec, StringView delim)
|
||||||
#define SYMLINK_COLOR "\x1b[36m"
|
|
||||||
#define FILE_COLOR "\x1b[1;32m"
|
|
||||||
#define DIR_COLOR "\x1b[1;34m"
|
|
||||||
#define SOCKET_COLOR "\x1b[33m"
|
|
||||||
#define SPECIAL_COLOR "\x1b[35m"
|
|
||||||
#define STICKY_COLOR "\x1b[30;1;42m"
|
|
||||||
#define SETUID_COLOR "\x1b[30;1;41m"
|
|
||||||
#define EXEC_COLOR "\x1b[1;31m"
|
|
||||||
|
|
||||||
static const char* file_type_color(const os::Directory::Entry& entry)
|
|
||||||
{
|
|
||||||
if (entry.mode & S_ISVTX) return STICKY_COLOR;
|
|
||||||
if (entry.mode & S_ISUID || entry.mode & S_ISGID) return SETUID_COLOR;
|
|
||||||
|
|
||||||
switch (entry.mode & S_IFMT)
|
|
||||||
{
|
|
||||||
case S_IFREG: return entry.mode & S_IXUSR ? EXEC_COLOR : FILE_COLOR;
|
|
||||||
case S_IFDIR: return DIR_COLOR;
|
|
||||||
case S_IFLNK: return SYMLINK_COLOR;
|
|
||||||
case S_IFSOCK: return SOCKET_COLOR;
|
|
||||||
default: return SPECIAL_COLOR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result<String> entry_join(const Vector<os::Directory::Entry>& vec, StringView delim, bool colors)
|
|
||||||
{
|
{
|
||||||
if (vec.size() == 0) return String {};
|
if (vec.size() == 0) return String {};
|
||||||
|
if (vec.size() == 1) return vec[0].name.clone();
|
||||||
|
|
||||||
StringBuilder sb;
|
StringBuilder sb;
|
||||||
if (colors) TRY(sb.add(StringView { file_type_color(vec[0]) }));
|
|
||||||
TRY(sb.add(vec[0].name));
|
TRY(sb.add(vec[0].name));
|
||||||
if (colors) TRY(sb.add(StringView { RESET_COLORS }));
|
|
||||||
|
|
||||||
for (usize i = 1; i < vec.size(); i++)
|
for (usize i = 1; i < vec.size(); i++)
|
||||||
{
|
{
|
||||||
TRY(sb.add(delim));
|
TRY(sb.add(delim));
|
||||||
if (colors) TRY(sb.add(StringView { file_type_color(vec[i]) }));
|
|
||||||
TRY(sb.add(vec[i].name));
|
TRY(sb.add(vec[i].name));
|
||||||
if (colors) TRY(sb.add(StringView { RESET_COLORS }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.string();
|
return sb.string();
|
||||||
@ -104,7 +75,6 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
bool follow_symlink_args { false };
|
bool follow_symlink_args { false };
|
||||||
bool one_per_line { false };
|
bool one_per_line { false };
|
||||||
bool list_directories { false };
|
bool list_directories { false };
|
||||||
bool no_colors { false };
|
|
||||||
|
|
||||||
StringView sort_type { "name" };
|
StringView sort_type { "name" };
|
||||||
|
|
||||||
@ -128,8 +98,6 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
parser.add_switch_argument(list_directories, 'd', "directory"_sv, "list directories instead of their contents"_sv);
|
parser.add_switch_argument(list_directories, 'd', "directory"_sv, "list directories instead of their contents"_sv);
|
||||||
parser.add_value_argument(sort_type, ' ', "sort"_sv, "sort by name, size or time"_sv);
|
parser.add_value_argument(sort_type, ' ', "sort"_sv, "sort by name, size or time"_sv);
|
||||||
parser.add_switch_argument(reverse_sort, 'r', "reverse"_sv, "reverse order while sorting"_sv);
|
parser.add_switch_argument(reverse_sort, 'r', "reverse"_sv, "reverse order while sorting"_sv);
|
||||||
parser.add_switch_argument(no_colors, ' ', "no-colors"_sv,
|
|
||||||
"disable coloring of output (defaults to true when not in a TTY)"_sv);
|
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
Vector<os::Directory::Entry> files;
|
Vector<os::Directory::Entry> files;
|
||||||
@ -186,13 +154,11 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
if (!long_list)
|
if (!long_list)
|
||||||
{
|
{
|
||||||
auto list = TRY(entry_join(files, one_per_line ? "\n"_sv : " "_sv, !no_colors && isatty(STDIN_FILENO)));
|
auto list = TRY(entry_join(files, one_per_line ? "\n"_sv : " "_sv));
|
||||||
if (!list.is_empty()) os::println("%s", list.chars());
|
if (!list.is_empty()) os::println("%s", list.chars());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool colors = !no_colors && isatty(STDIN_FILENO);
|
|
||||||
|
|
||||||
for (const auto& file : files)
|
for (const auto& file : files)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -210,32 +176,14 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
if (!human_readable && !si)
|
if (!human_readable && !si)
|
||||||
{
|
{
|
||||||
if (colors)
|
os::println("%s %u %4s %4s %10lu %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||||
{
|
st.st_size, file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||||
os::println("%s %u %4s %4s %10lu %s%s" RESET_COLORS "%s" SYMLINK_COLOR "%s" RESET_COLORS,
|
|
||||||
formatted_mode, st.st_nlink, owner.chars(), group.chars(), st.st_size,
|
|
||||||
file_type_color(file), file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
os::println("%s %u %4s %4s %10lu %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
|
||||||
st.st_size, file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto size = TRY(to_dynamic_unit(st.st_size, 10, false, si ? Unit::SI : Unit::Binary, false));
|
auto size = TRY(to_dynamic_unit(st.st_size, 10, false, si ? Unit::SI : Unit::Binary, false));
|
||||||
if (colors)
|
os::println("%s %u %4s %4s %6s %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||||
{
|
size.chars(), file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||||
os::println("%s %u %4s %4s %6s %s%s" RESET_COLORS "%s" SYMLINK_COLOR "%s" RESET_COLORS,
|
|
||||||
formatted_mode, st.st_nlink, owner.chars(), group.chars(), size.chars(),
|
|
||||||
file_type_color(file), file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
os::println("%s %u %4s %4s %6s %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
|
||||||
size.chars(), file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,9 +72,10 @@ int main()
|
|||||||
// Now, mount the /dev file system on the new root.
|
// Now, mount the /dev file system on the new root.
|
||||||
mount_devfs();
|
mount_devfs();
|
||||||
|
|
||||||
char* argv[] = { "/usr/bin/init", nullptr };
|
setenv("PATH", "/sbin:/usr/bin", 1);
|
||||||
|
char* argv[] = { "init", nullptr };
|
||||||
char* envp[] = { nullptr };
|
char* envp[] = { nullptr };
|
||||||
execve(argv[0], argv, envp);
|
execvpe(argv[0], argv, envp);
|
||||||
|
|
||||||
fail_errno("Failed to execute init");
|
fail_errno("Failed to execute init");
|
||||||
|
|
||||||
|
30
apps/rm.cpp
30
apps/rm.cpp
@ -1,35 +1,10 @@
|
|||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <os/Directory.h>
|
|
||||||
#include <os/File.h>
|
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
|
|
||||||
Result<void> remove_wrapper(const os::Path& path, bool verbose)
|
|
||||||
{
|
|
||||||
TRY(os::FileSystem::remove(path));
|
|
||||||
if (verbose) os::println("removed '%s'", path.name().chars());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> remove_tree(const os::Path& path, bool verbose)
|
|
||||||
{
|
|
||||||
auto rc = remove_wrapper(path, verbose);
|
|
||||||
if (!rc.has_error()) return {};
|
|
||||||
if (rc.error() != ENOTEMPTY) return rc.release_error();
|
|
||||||
|
|
||||||
auto dir = TRY(os::Directory::open(path));
|
|
||||||
|
|
||||||
Vector<String> entries = TRY(dir->list_names(os::Directory::Filter::ParentAndBase));
|
|
||||||
|
|
||||||
for (const auto& entry : entries) { TRY(remove_tree({ dir->fd(), entry.view() }, verbose)); }
|
|
||||||
|
|
||||||
return remove_wrapper(path, verbose);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<int> luna_main(int argc, char** argv)
|
Result<int> luna_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
StringView path;
|
StringView path;
|
||||||
bool recursive;
|
bool recursive;
|
||||||
bool verbose;
|
|
||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Remove a path from the file system."_sv);
|
parser.add_description("Remove a path from the file system."_sv);
|
||||||
@ -37,12 +12,11 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
parser.add_positional_argument(path, "path"_sv, true);
|
parser.add_positional_argument(path, "path"_sv, true);
|
||||||
parser.add_switch_argument(recursive, 'r', "recursive"_sv,
|
parser.add_switch_argument(recursive, 'r', "recursive"_sv,
|
||||||
"remove a directory recursively (by default, rm removes only empty directories)"_sv);
|
"remove a directory recursively (by default, rm removes only empty directories)"_sv);
|
||||||
parser.add_switch_argument(verbose, 'v', "verbose"_sv, "log every removed file and directory"_sv);
|
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
if (!recursive) TRY(remove_wrapper(path, verbose));
|
if (!recursive) TRY(os::FileSystem::remove(path));
|
||||||
else
|
else
|
||||||
TRY(remove_tree(path, verbose));
|
TRY(os::FileSystem::remove_tree(path));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
chdir(entry->pw_dir);
|
chdir(entry->pw_dir);
|
||||||
clearenv();
|
clearenv();
|
||||||
setenv("PATH", "/usr/bin:/usr/local/bin", 1);
|
setenv("PATH", "/bin:/sbin", 1);
|
||||||
setpgid(0, 0);
|
setpgid(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
root:toor:0:0:Administrator:/:/usr/bin/sh
|
root:toor:0:0:Administrator:/:/bin/sh
|
||||||
selene:moon:1000:1000:User:/home/selene:/usr/bin/sh
|
selene:moon:1000:1000:User:/home/selene:/bin/sh
|
||||||
|
@ -161,11 +161,7 @@ void io_thread()
|
|||||||
static void timer_interrupt(Registers* regs, void*)
|
static void timer_interrupt(Registers* regs, void*)
|
||||||
{
|
{
|
||||||
Timer::tick();
|
Timer::tick();
|
||||||
if (should_invoke_scheduler())
|
if (should_invoke_scheduler()) Scheduler::invoke(regs);
|
||||||
{
|
|
||||||
Scheduler::invoke(regs);
|
|
||||||
TextConsole::tick_cursor();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_interrupt(Registers*, void*)
|
static void keyboard_interrupt(Registers*, void*)
|
||||||
|
@ -246,9 +246,6 @@ Result<u64> ConsoleDevice::ioctl(int request, void* arg)
|
|||||||
}
|
}
|
||||||
case TTYSETGFX: {
|
case TTYSETGFX: {
|
||||||
s_is_in_graphical_mode = (bool)arg;
|
s_is_in_graphical_mode = (bool)arg;
|
||||||
if (!s_is_in_graphical_mode) TextConsole::enable_cursor();
|
|
||||||
else
|
|
||||||
TextConsole::disable_cursor();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
default: return err(EINVAL);
|
default: return err(EINVAL);
|
||||||
|
@ -59,8 +59,6 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
Vector<String> envp;
|
Vector<String> envp;
|
||||||
if (args[2]) envp = TRY(copy_string_vector_from_userspace(args[2]));
|
if (args[2]) envp = TRY(copy_string_vector_from_userspace(args[2]));
|
||||||
|
|
||||||
String cmdline = TRY(String::join(argv, " "));
|
|
||||||
|
|
||||||
if ((calculate_userspace_stack_size(argv) + calculate_userspace_stack_size(envp)) > MAX_ARGV_STACK_SIZE)
|
if ((calculate_userspace_stack_size(argv) + calculate_userspace_stack_size(envp)) > MAX_ARGV_STACK_SIZE)
|
||||||
return err(E2BIG);
|
return err(E2BIG);
|
||||||
|
|
||||||
@ -117,7 +115,7 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
if (is_setuid) current->auth.euid = current->auth.suid = inode->metadata().uid;
|
if (is_setuid) current->auth.euid = current->auth.suid = inode->metadata().uid;
|
||||||
if (is_setgid) current->auth.egid = current->auth.sgid = inode->metadata().gid;
|
if (is_setgid) current->auth.egid = current->auth.sgid = inode->metadata().gid;
|
||||||
|
|
||||||
current->cmdline = cmdline.chars();
|
current->name = path.chars();
|
||||||
|
|
||||||
image->apply(current);
|
image->apply(current);
|
||||||
|
|
||||||
@ -161,7 +159,7 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
|||||||
thread->state = ThreadState::Runnable;
|
thread->state = ThreadState::Runnable;
|
||||||
thread->is_kernel = false;
|
thread->is_kernel = false;
|
||||||
thread->fp_data.save();
|
thread->fp_data.save();
|
||||||
thread->cmdline = current->cmdline;
|
thread->name = current->name;
|
||||||
thread->auth = current->auth;
|
thread->auth = current->auth;
|
||||||
thread->current_directory = current->current_directory;
|
thread->current_directory = current->current_directory;
|
||||||
thread->current_directory_path = move(current_directory_path);
|
thread->current_directory_path = move(current_directory_path);
|
||||||
|
@ -35,7 +35,7 @@ Result<u64> sys_pstat(Registers*, SyscallArgs args)
|
|||||||
set_timespec(proc.ps_time, thread->user_ticks_self + thread->kernel_ticks_self);
|
set_timespec(proc.ps_time, thread->user_ticks_self + thread->kernel_ticks_self);
|
||||||
set_timespec(proc.ps_ktime, thread->kernel_ticks_self);
|
set_timespec(proc.ps_ktime, thread->kernel_ticks_self);
|
||||||
set_timespec(proc.ps_utime, thread->kernel_ticks_children);
|
set_timespec(proc.ps_utime, thread->kernel_ticks_children);
|
||||||
strlcpy(proc.ps_name, thread->cmdline.chars(), sizeof(proc.ps_name));
|
strlcpy(proc.ps_name, thread->name.chars(), sizeof(proc.ps_name));
|
||||||
strlcpy(proc.ps_cwd, thread->current_directory_path.is_empty() ? "/" : thread->current_directory_path.chars(),
|
strlcpy(proc.ps_cwd, thread->current_directory_path.is_empty() ? "/" : thread->current_directory_path.chars(),
|
||||||
sizeof(proc.ps_cwd));
|
sizeof(proc.ps_cwd));
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ namespace Scheduler
|
|||||||
g_idle.state = ThreadState::Idle;
|
g_idle.state = ThreadState::Idle;
|
||||||
g_idle.is_kernel = true;
|
g_idle.is_kernel = true;
|
||||||
g_idle.parent = nullptr;
|
g_idle.parent = nullptr;
|
||||||
g_idle.cmdline = "[idle]";
|
g_idle.name = "[idle]";
|
||||||
g_idle.active_directory = nullptr;
|
g_idle.active_directory = nullptr;
|
||||||
|
|
||||||
g_idle.ticks_left = 1;
|
g_idle.ticks_left = 1;
|
||||||
@ -96,7 +96,7 @@ namespace Scheduler
|
|||||||
|
|
||||||
thread->stack = thread_stack;
|
thread->stack = thread_stack;
|
||||||
|
|
||||||
thread->cmdline = name;
|
thread->name = name;
|
||||||
|
|
||||||
thread->is_kernel = true;
|
thread->is_kernel = true;
|
||||||
thread->active_directory = MMU::kernel_page_directory();
|
thread->active_directory = MMU::kernel_page_directory();
|
||||||
@ -148,7 +148,7 @@ namespace Scheduler
|
|||||||
thread->is_kernel = false;
|
thread->is_kernel = false;
|
||||||
thread->id = 1;
|
thread->id = 1;
|
||||||
thread->pgid = 1;
|
thread->pgid = 1;
|
||||||
thread->cmdline = name;
|
thread->name = name;
|
||||||
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };
|
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };
|
||||||
|
|
||||||
Vector<String> args;
|
Vector<String> args;
|
||||||
@ -374,7 +374,7 @@ namespace Scheduler
|
|||||||
{
|
{
|
||||||
kdbgln("%p %c [%-20s] %4d, parent = (%-18p,%d), state = %d, ticks: (k:%04zu,u:%04zu), status = "
|
kdbgln("%p %c [%-20s] %4d, parent = (%-18p,%d), state = %d, ticks: (k:%04zu,u:%04zu), status = "
|
||||||
"%d, cwd = %s",
|
"%d, cwd = %s",
|
||||||
thread, thread->is_kernel ? 'k' : 'u', thread->cmdline.chars(), thread->id, thread->parent,
|
thread, thread->is_kernel ? 'k' : 'u', thread->name.chars(), thread->id, thread->parent,
|
||||||
thread->parent ? thread->parent->id : 0, (int)thread->state, thread->kernel_ticks_self,
|
thread->parent ? thread->parent->id : 0, (int)thread->state, thread->kernel_ticks_self,
|
||||||
thread->user_ticks_self, thread->status,
|
thread->user_ticks_self, thread->status,
|
||||||
thread->current_directory_path.is_empty() ? "/" : thread->current_directory_path.chars());
|
thread->current_directory_path.is_empty() ? "/" : thread->current_directory_path.chars());
|
||||||
|
@ -123,7 +123,7 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
|
|
||||||
mode_t umask { 0 };
|
mode_t umask { 0 };
|
||||||
|
|
||||||
StaticString<128> cmdline;
|
StaticString<128> name;
|
||||||
|
|
||||||
String current_directory_path = {};
|
String current_directory_path = {};
|
||||||
SharedPtr<VFS::Inode> current_directory = {};
|
SharedPtr<VFS::Inode> current_directory = {};
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "video/Framebuffer.h"
|
#include "video/Framebuffer.h"
|
||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
#include <luna/CType.h>
|
#include <luna/CType.h>
|
||||||
#include <luna/EscapeSequence.h>
|
|
||||||
#include <luna/Format.h>
|
#include <luna/Format.h>
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
#include <luna/ScopeGuard.h>
|
#include <luna/ScopeGuard.h>
|
||||||
@ -14,27 +13,8 @@ extern const BOOTBOOT bootboot;
|
|||||||
|
|
||||||
#include "video/BuiltinFont.h"
|
#include "video/BuiltinFont.h"
|
||||||
|
|
||||||
// Default text color.
|
|
||||||
static constexpr u32 WHITE = 0xffffffff;
|
|
||||||
|
|
||||||
// xterm color palette.
|
|
||||||
static constexpr u32 BLACK = 0xff000000;
|
static constexpr u32 BLACK = 0xff000000;
|
||||||
static constexpr u32 RED = 0xffcd0000;
|
static constexpr u32 WHITE = 0xffffffff;
|
||||||
static constexpr u32 GREEN = 0xff00cd00;
|
|
||||||
static constexpr u32 YELLOW = 0xffcdcd00;
|
|
||||||
static constexpr u32 BLUE = 0xff0000ee;
|
|
||||||
static constexpr u32 MAGENTA = 0xffcd00cd;
|
|
||||||
static constexpr u32 CYAN = 0xff00cdcd;
|
|
||||||
static constexpr u32 GRAY = 0xffe5e5e5;
|
|
||||||
|
|
||||||
static constexpr u32 BRIGHT_BLACK = 0xff7f7f7f;
|
|
||||||
static constexpr u32 BRIGHT_RED = 0xffff0000;
|
|
||||||
static constexpr u32 BRIGHT_GREEN = 0xff00ff00;
|
|
||||||
static constexpr u32 BRIGHT_YELLOW = 0xffffff00;
|
|
||||||
static constexpr u32 BRIGHT_BLUE = 0xff5c5cff;
|
|
||||||
static constexpr u32 BRIGHT_MAGENTA = 0xffff00ff;
|
|
||||||
static constexpr u32 BRIGHT_CYAN = 0xff00ffff;
|
|
||||||
static constexpr u32 BRIGHT_GRAY = 0xffffffff;
|
|
||||||
|
|
||||||
static u32 g_background_color = BLACK;
|
static u32 g_background_color = BLACK;
|
||||||
static u32 g_foreground_color = WHITE;
|
static u32 g_foreground_color = WHITE;
|
||||||
@ -42,20 +22,11 @@ static u32 g_foreground_color = WHITE;
|
|||||||
static constexpr u32 FONT_HEIGHT = 16;
|
static constexpr u32 FONT_HEIGHT = 16;
|
||||||
static constexpr u32 FONT_WIDTH = 8;
|
static constexpr u32 FONT_WIDTH = 8;
|
||||||
|
|
||||||
static bool bold = false;
|
|
||||||
|
|
||||||
static u32 g_x_position = 0;
|
static u32 g_x_position = 0;
|
||||||
static u32 g_y_position = 0;
|
static u32 g_y_position = 0;
|
||||||
|
|
||||||
static constexpr int CURSOR_TIMEOUT = 500;
|
|
||||||
static int current_cursor_timeout = CURSOR_TIMEOUT;
|
|
||||||
static bool cursor_activated = true;
|
|
||||||
static bool cursor_enabled = true;
|
|
||||||
|
|
||||||
static Utf8StateDecoder utf8_decoder;
|
static Utf8StateDecoder utf8_decoder;
|
||||||
|
|
||||||
static Option<EscapeSequenceParser> escape_sequence_parser;
|
|
||||||
|
|
||||||
static void putwchar_at(wchar_t c, u32 x, u32 y)
|
static void putwchar_at(wchar_t c, u32 x, u32 y)
|
||||||
{
|
{
|
||||||
const u8* glyph = &font[c * 16];
|
const u8* glyph = &font[c * 16];
|
||||||
@ -87,7 +58,7 @@ static void scroll()
|
|||||||
|
|
||||||
static bool should_scroll()
|
static bool should_scroll()
|
||||||
{
|
{
|
||||||
return g_y_position >= Framebuffer::height();
|
return (g_y_position + FONT_HEIGHT) >= Framebuffer::height();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void next_line()
|
static void next_line()
|
||||||
@ -111,216 +82,11 @@ static void erase_current_char()
|
|||||||
Framebuffer::rect(g_x_position, g_y_position, FONT_WIDTH, FONT_HEIGHT, BLACK);
|
Framebuffer::rect(g_x_position, g_y_position, FONT_WIDTH, FONT_HEIGHT, BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_cursor()
|
|
||||||
{
|
|
||||||
Framebuffer::rect(g_x_position, g_y_position, FONT_WIDTH, FONT_HEIGHT, WHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool at_end_of_screen()
|
static bool at_end_of_screen()
|
||||||
{
|
{
|
||||||
return (g_x_position + FONT_WIDTH) > Framebuffer::width();
|
return (g_x_position + FONT_WIDTH) > Framebuffer::width();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_escape_sequence(wchar_t c)
|
|
||||||
{
|
|
||||||
auto rc = escape_sequence_parser->advance(static_cast<u8>(c));
|
|
||||||
if (rc.has_error())
|
|
||||||
{
|
|
||||||
escape_sequence_parser = Option<EscapeSequenceParser> {};
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!rc.value()) return true;
|
|
||||||
if (!escape_sequence_parser->valid())
|
|
||||||
{
|
|
||||||
escape_sequence_parser = Option<EscapeSequenceParser> {};
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& params = escape_sequence_parser->parameters();
|
|
||||||
switch (escape_sequence_parser->code())
|
|
||||||
{
|
|
||||||
case EscapeCode::CursorUp: {
|
|
||||||
int lines = params.size() ? params[0] : 1;
|
|
||||||
int pixels = lines * FONT_HEIGHT;
|
|
||||||
if ((u32)pixels > g_y_position) g_y_position = 0;
|
|
||||||
else
|
|
||||||
g_y_position -= pixels;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case EscapeCode::CursorDown: {
|
|
||||||
int lines = params.size() ? params[0] : 1;
|
|
||||||
int pixels = lines * FONT_HEIGHT;
|
|
||||||
if (pixels + g_y_position >= Framebuffer::height()) g_y_position = Framebuffer::height() - FONT_HEIGHT;
|
|
||||||
else
|
|
||||||
g_y_position += pixels;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case EscapeCode::CursorBack: {
|
|
||||||
int chars = params.size() ? params[0] : 1;
|
|
||||||
int pixels = chars * FONT_WIDTH;
|
|
||||||
if ((u32)pixels > g_x_position) g_x_position = 0;
|
|
||||||
else
|
|
||||||
g_x_position -= pixels;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case EscapeCode::CursorForward: {
|
|
||||||
int chars = params.size() ? params[0] : 1;
|
|
||||||
int pixels = chars * FONT_WIDTH;
|
|
||||||
if (pixels + g_x_position >= Framebuffer::width()) g_x_position = Framebuffer::width() - FONT_WIDTH;
|
|
||||||
else
|
|
||||||
g_x_position += pixels;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case EscapeCode::CursorNextLine: {
|
|
||||||
int lines = params.size() ? params[0] : 1;
|
|
||||||
int pixels = lines * FONT_HEIGHT;
|
|
||||||
if ((u32)pixels > g_y_position) g_y_position = 0;
|
|
||||||
else
|
|
||||||
g_y_position -= pixels;
|
|
||||||
g_x_position = 0;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case EscapeCode::CursorPreviousLine: {
|
|
||||||
int lines = params.size() ? params[0] : 1;
|
|
||||||
int pixels = lines * FONT_HEIGHT;
|
|
||||||
if (pixels + g_y_position >= Framebuffer::height()) g_y_position = Framebuffer::height() - FONT_HEIGHT;
|
|
||||||
else
|
|
||||||
g_y_position += pixels;
|
|
||||||
g_x_position = 0;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case EscapeCode::CursorHorizontalAbsolute: {
|
|
||||||
int line = (params.size() ? params[0] : 1) - 1;
|
|
||||||
if (line < 0) break;
|
|
||||||
u32 position = line * FONT_HEIGHT;
|
|
||||||
if (position >= Framebuffer::height()) position = Framebuffer::height() - FONT_HEIGHT;
|
|
||||||
g_y_position = position;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case EscapeCode::SetCursorPosition: {
|
|
||||||
int x = (params.size() ? params[0] : 1) - 1;
|
|
||||||
int y = (params.size() > 1 ? params[1] : 1) - 1;
|
|
||||||
if (x < 0 || y < 0) break;
|
|
||||||
u32 x_position = x * FONT_WIDTH;
|
|
||||||
if (x_position >= Framebuffer::width()) x_position = Framebuffer::width() - FONT_HEIGHT;
|
|
||||||
g_x_position = x_position;
|
|
||||||
u32 y_position = y * FONT_HEIGHT;
|
|
||||||
if (y_position >= Framebuffer::height()) y_position = Framebuffer::height() - FONT_HEIGHT;
|
|
||||||
g_y_position = y_position;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case EscapeCode::SelectGraphicRendition: {
|
|
||||||
if (!params.size())
|
|
||||||
{
|
|
||||||
g_foreground_color = WHITE;
|
|
||||||
g_background_color = BLACK;
|
|
||||||
bold = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (usize i = 0; i < params.size(); i++)
|
|
||||||
{
|
|
||||||
int arg = params[i];
|
|
||||||
switch (arg)
|
|
||||||
{
|
|
||||||
case 0: {
|
|
||||||
g_foreground_color = BLACK;
|
|
||||||
g_background_color = WHITE;
|
|
||||||
bold = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
bold = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 22: {
|
|
||||||
bold = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 30: {
|
|
||||||
g_foreground_color = bold ? BRIGHT_BLACK : BLACK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 31: {
|
|
||||||
g_foreground_color = bold ? BRIGHT_RED : RED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 32: {
|
|
||||||
g_foreground_color = bold ? BRIGHT_GREEN : GREEN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 33: {
|
|
||||||
g_foreground_color = bold ? BRIGHT_YELLOW : YELLOW;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 34: {
|
|
||||||
g_foreground_color = bold ? BRIGHT_BLUE : BLUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 35: {
|
|
||||||
g_foreground_color = bold ? BRIGHT_MAGENTA : MAGENTA;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 36: {
|
|
||||||
g_foreground_color = bold ? BRIGHT_CYAN : CYAN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 37: {
|
|
||||||
g_foreground_color = bold ? BRIGHT_GRAY : GRAY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 39: {
|
|
||||||
g_foreground_color = WHITE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 40: {
|
|
||||||
g_background_color = bold ? BRIGHT_BLACK : BLACK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 41: {
|
|
||||||
g_background_color = bold ? BRIGHT_RED : RED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 42: {
|
|
||||||
g_background_color = bold ? BRIGHT_GREEN : GREEN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 43: {
|
|
||||||
g_background_color = bold ? BRIGHT_YELLOW : YELLOW;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 44: {
|
|
||||||
g_background_color = bold ? BRIGHT_BLUE : BLUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 45: {
|
|
||||||
g_background_color = bold ? BRIGHT_MAGENTA : MAGENTA;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 46: {
|
|
||||||
g_background_color = bold ? BRIGHT_CYAN : CYAN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 47: {
|
|
||||||
g_background_color = bold ? BRIGHT_GRAY : GRAY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 49: {
|
|
||||||
g_background_color = BLACK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
escape_sequence_parser = Option<EscapeSequenceParser> {};
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace TextConsole
|
namespace TextConsole
|
||||||
{
|
{
|
||||||
void putwchar(wchar_t c)
|
void putwchar(wchar_t c)
|
||||||
@ -328,16 +94,6 @@ namespace TextConsole
|
|||||||
// Unprintable (not in the built-in font) characters get represented as a box
|
// Unprintable (not in the built-in font) characters get represented as a box
|
||||||
if (c > (wchar_t)255) c = (wchar_t)256;
|
if (c > (wchar_t)255) c = (wchar_t)256;
|
||||||
|
|
||||||
if (escape_sequence_parser.has_value())
|
|
||||||
{
|
|
||||||
if (handle_escape_sequence(c)) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erase the current cursor.
|
|
||||||
if (cursor_enabled) erase_current_char();
|
|
||||||
|
|
||||||
bool should_draw_cursor = cursor_enabled;
|
|
||||||
|
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case L'\n': {
|
case L'\n': {
|
||||||
@ -357,13 +113,6 @@ namespace TextConsole
|
|||||||
erase_current_char();
|
erase_current_char();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case L'\x1b':
|
|
||||||
case L'\x9b':
|
|
||||||
case L'\x90':
|
|
||||||
case L'\x9d':
|
|
||||||
escape_sequence_parser = EscapeSequenceParser { (u8)c };
|
|
||||||
should_draw_cursor = false;
|
|
||||||
break;
|
|
||||||
default: {
|
default: {
|
||||||
if (_iscntrl(c)) return;
|
if (_iscntrl(c)) return;
|
||||||
putwchar_at(c, g_x_position, g_y_position);
|
putwchar_at(c, g_x_position, g_y_position);
|
||||||
@ -376,42 +125,6 @@ namespace TextConsole
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_draw_cursor)
|
|
||||||
{
|
|
||||||
current_cursor_timeout = CURSOR_TIMEOUT;
|
|
||||||
cursor_activated = true;
|
|
||||||
draw_cursor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tick_cursor()
|
|
||||||
{
|
|
||||||
if (!cursor_enabled) return;
|
|
||||||
|
|
||||||
current_cursor_timeout--;
|
|
||||||
if (current_cursor_timeout == 0)
|
|
||||||
{
|
|
||||||
current_cursor_timeout = CURSOR_TIMEOUT;
|
|
||||||
cursor_activated = !cursor_activated;
|
|
||||||
|
|
||||||
if (cursor_activated) draw_cursor();
|
|
||||||
else
|
|
||||||
erase_current_char();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable_cursor()
|
|
||||||
{
|
|
||||||
cursor_enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_cursor()
|
|
||||||
{
|
|
||||||
cursor_enabled = true;
|
|
||||||
cursor_activated = true;
|
|
||||||
current_cursor_timeout = CURSOR_TIMEOUT;
|
|
||||||
draw_cursor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> putchar(char c)
|
Result<void> putchar(char c)
|
||||||
|
@ -19,9 +19,6 @@ namespace TextConsole
|
|||||||
Result<void> println(const char* str);
|
Result<void> println(const char* str);
|
||||||
void wprintln(const wchar_t* str);
|
void wprintln(const wchar_t* str);
|
||||||
Result<usize> printf(const char* format, ...) _format(1, 2);
|
Result<usize> printf(const char* format, ...) _format(1, 2);
|
||||||
void tick_cursor();
|
|
||||||
void disable_cursor();
|
|
||||||
void enable_cursor();
|
|
||||||
|
|
||||||
u16 rows();
|
u16 rows();
|
||||||
u16 cols();
|
u16 cols();
|
||||||
|
@ -20,6 +20,7 @@ set(SOURCES
|
|||||||
src/pwd.cpp
|
src/pwd.cpp
|
||||||
src/grp.cpp
|
src/grp.cpp
|
||||||
src/locale.cpp
|
src/locale.cpp
|
||||||
|
src/scanf.cpp
|
||||||
src/signal.cpp
|
src/signal.cpp
|
||||||
src/termios.cpp
|
src/termios.cpp
|
||||||
src/utime.cpp
|
src/utime.cpp
|
||||||
|
263
libc/src/scanf.cpp
Normal file
263
libc/src/scanf.cpp
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <luna/CType.h>
|
||||||
|
#include <luna/NumberParsing.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define FLAG_DISCARD (1 << 0)
|
||||||
|
#define FLAG_ALLOC (1 << 1)
|
||||||
|
#define FLAG_WIDTH (1 << 2)
|
||||||
|
#define FLAG_LONG (1 << 3)
|
||||||
|
#define FLAG_LONG_LONG (1 << 4)
|
||||||
|
#define FLAG_SHORT (1 << 5)
|
||||||
|
#define FLAG_CHAR (1 << 6)
|
||||||
|
|
||||||
|
static int parse_flags(const char** format)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
switch (**format)
|
||||||
|
{
|
||||||
|
case '*':
|
||||||
|
result |= FLAG_DISCARD;
|
||||||
|
(*format)++;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
result |= FLAG_ALLOC;
|
||||||
|
(*format)++;
|
||||||
|
break;
|
||||||
|
default: return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t parse_width(const char** format, int& flags)
|
||||||
|
{
|
||||||
|
size_t result = 0;
|
||||||
|
|
||||||
|
if (_isdigit(**format))
|
||||||
|
{
|
||||||
|
result = scan_unsigned_integer(format);
|
||||||
|
flags |= FLAG_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_type(const char** format, int& flags)
|
||||||
|
{
|
||||||
|
// FIXME: Support %j (intmax_t/uintmax_t)
|
||||||
|
switch (**format)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
flags |= FLAG_SHORT;
|
||||||
|
(*format)++;
|
||||||
|
if (**format == 'h')
|
||||||
|
{
|
||||||
|
flags |= FLAG_CHAR;
|
||||||
|
(*format)++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
flags |= FLAG_LONG;
|
||||||
|
(*format)++;
|
||||||
|
if (**format == 'l')
|
||||||
|
{
|
||||||
|
flags |= FLAG_LONG_LONG;
|
||||||
|
(*format)++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
flags |= (sizeof(ptrdiff_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG;
|
||||||
|
(*format)++;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
flags |= (sizeof(size_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG;
|
||||||
|
(*format)++;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_parsed_signed_integer(ssize_t value, int flags, va_list ap)
|
||||||
|
{
|
||||||
|
if (flags & FLAG_LONG_LONG) *va_arg(ap, signed long long*) = (signed long long)value;
|
||||||
|
else if (flags & FLAG_LONG)
|
||||||
|
*va_arg(ap, signed long*) = (signed long)value;
|
||||||
|
else if (flags & FLAG_SHORT)
|
||||||
|
*va_arg(ap, signed int*) = (signed short)value;
|
||||||
|
else if (flags & FLAG_CHAR)
|
||||||
|
*va_arg(ap, signed int*) = (signed char)value;
|
||||||
|
else
|
||||||
|
*va_arg(ap, signed int*) = (signed int)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_parsed_unsigned_integer(size_t value, int flags, va_list ap)
|
||||||
|
{
|
||||||
|
if (flags & FLAG_LONG_LONG) *va_arg(ap, unsigned long long*) = (unsigned long long)value;
|
||||||
|
else if (flags & FLAG_LONG)
|
||||||
|
*va_arg(ap, unsigned long*) = (unsigned long)value;
|
||||||
|
else if (flags & FLAG_SHORT)
|
||||||
|
*va_arg(ap, unsigned int*) = (unsigned short)value;
|
||||||
|
else if (flags & FLAG_CHAR)
|
||||||
|
*va_arg(ap, unsigned int*) = (unsigned char)value;
|
||||||
|
else
|
||||||
|
*va_arg(ap, unsigned int*) = (unsigned int)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WHITESPACE_CHARACTERS " \t\f\r\n\v"
|
||||||
|
|
||||||
|
static void skip_whitespace(const char** str)
|
||||||
|
{
|
||||||
|
*str += strspn(*str, WHITESPACE_CHARACTERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
int vsscanf(const char* str, const char* format, va_list ap)
|
||||||
|
{
|
||||||
|
int parsed = 0;
|
||||||
|
const char* s = str; // Keep a pointer to the beginning of the string for %n
|
||||||
|
|
||||||
|
if (*str == 0) return EOF;
|
||||||
|
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
if (*format != '%')
|
||||||
|
{
|
||||||
|
normal:
|
||||||
|
if (!_isspace(*format))
|
||||||
|
{
|
||||||
|
if (*str != *format) return parsed;
|
||||||
|
str++;
|
||||||
|
format++;
|
||||||
|
if (*str == 0) return parsed;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_whitespace(&format);
|
||||||
|
skip_whitespace(&str);
|
||||||
|
if (*str == 0) return parsed;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
format++;
|
||||||
|
if (*format == '%')
|
||||||
|
{
|
||||||
|
skip_whitespace(&str);
|
||||||
|
goto normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = parse_flags(&format);
|
||||||
|
size_t width = parse_width(&format, flags);
|
||||||
|
parse_type(&format, flags);
|
||||||
|
char specifier = *format++;
|
||||||
|
if (!specifier) return parsed;
|
||||||
|
|
||||||
|
switch (specifier)
|
||||||
|
{
|
||||||
|
case 's': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t chars = strcspn(str, WHITESPACE_CHARACTERS);
|
||||||
|
if (!chars) return parsed;
|
||||||
|
if ((flags & FLAG_WIDTH) && chars > width) chars = width;
|
||||||
|
if (!(flags & FLAG_DISCARD))
|
||||||
|
{
|
||||||
|
char* ptr;
|
||||||
|
if (flags & FLAG_ALLOC)
|
||||||
|
{
|
||||||
|
ptr = (char*)malloc(chars + 1);
|
||||||
|
if (!ptr) return parsed;
|
||||||
|
*va_arg(ap, char**) = ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ptr = va_arg(ap, char*);
|
||||||
|
memcpy(ptr, str, chars);
|
||||||
|
ptr[chars] = 0;
|
||||||
|
}
|
||||||
|
str += chars;
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'c': {
|
||||||
|
if (strlen(str) < width) return parsed;
|
||||||
|
if (!(flags & FLAG_WIDTH)) width = 1;
|
||||||
|
if (!(flags & FLAG_DISCARD))
|
||||||
|
{
|
||||||
|
char* ptr;
|
||||||
|
if (flags & FLAG_ALLOC)
|
||||||
|
{
|
||||||
|
ptr = (char*)malloc(width);
|
||||||
|
if (!ptr) return parsed;
|
||||||
|
*va_arg(ap, char**) = ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ptr = va_arg(ap, char*);
|
||||||
|
memcpy(ptr, str, width);
|
||||||
|
}
|
||||||
|
str += width;
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
ssize_t value = scan_signed_integer(&str, 10);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_signed_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'i': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
ssize_t value = scan_signed_integer(&str, 0);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_signed_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'o': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t value = scan_unsigned_integer(&str, 8);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'u': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t value = scan_unsigned_integer(&str, 10);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'X':
|
||||||
|
case 'x': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t value = scan_unsigned_integer(&str, 16);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'p': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t value = scan_unsigned_integer(&str, 16);
|
||||||
|
if (!(flags & FLAG_DISCARD)) *va_arg(ap, void**) = (void*)value;
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'n': {
|
||||||
|
if (!(flags & FLAG_DISCARD)) *va_arg(ap, int*) = (int)(str - s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
fprintf(stderr, "vsscanf: unknown conversion specifier: %%%c\n", specifier);
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <luna/Common.h>
|
#include <luna/Common.h>
|
||||||
#include <luna/Format.h>
|
#include <luna/Format.h>
|
||||||
#include <luna/Scanf.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -619,17 +618,12 @@ extern "C"
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vsscanf(const char* str, const char* format, va_list ap)
|
|
||||||
{
|
|
||||||
return scanf_impl(str, format, ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sscanf(const char* str, const char* format, ...)
|
int sscanf(const char* str, const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
|
|
||||||
int rc = scanf_impl(str, format, ap);
|
int rc = vsscanf(str, format, ap);
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
@ -640,7 +634,7 @@ extern "C"
|
|||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
if (!fgets(buf, sizeof(buf), stream)) return EOF;
|
if (!fgets(buf, sizeof(buf), stream)) return EOF;
|
||||||
return scanf_impl(buf, format, ap);
|
return vsscanf(buf, format, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fscanf(FILE* stream, const char* format, ...)
|
int fscanf(FILE* stream, const char* format, ...)
|
||||||
|
@ -23,7 +23,7 @@ static Result<int> try_execvpe(const char* name, char* const* argv, char* const*
|
|||||||
if (strchr(name, '/')) return execve(name, argv, envp);
|
if (strchr(name, '/')) return execve(name, argv, envp);
|
||||||
|
|
||||||
char* path = getenv("PATH");
|
char* path = getenv("PATH");
|
||||||
if (!path) path = const_cast<char*>("/usr/bin:/usr/local/bin");
|
if (!path) path = const_cast<char*>("/bin:/sbin");
|
||||||
|
|
||||||
Vector<String> paths = TRY(StringView { path }.split(":"));
|
Vector<String> paths = TRY(StringView { path }.split(":"));
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ file(GLOB HEADERS include/luna/*.h)
|
|||||||
set(FREESTANDING_SOURCES
|
set(FREESTANDING_SOURCES
|
||||||
${HEADERS}
|
${HEADERS}
|
||||||
src/CRC32.cpp
|
src/CRC32.cpp
|
||||||
src/EscapeSequence.cpp
|
|
||||||
src/Format.cpp
|
src/Format.cpp
|
||||||
src/Sort.cpp
|
src/Sort.cpp
|
||||||
src/NumberParsing.cpp
|
src/NumberParsing.cpp
|
||||||
@ -15,7 +14,6 @@ set(FREESTANDING_SOURCES
|
|||||||
src/SystemError.cpp
|
src/SystemError.cpp
|
||||||
src/Bitmap.cpp
|
src/Bitmap.cpp
|
||||||
src/Buffer.cpp
|
src/Buffer.cpp
|
||||||
src/Scanf.cpp
|
|
||||||
src/Stack.cpp
|
src/Stack.cpp
|
||||||
src/String.cpp
|
src/String.cpp
|
||||||
src/StringBuilder.cpp
|
src/StringBuilder.cpp
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file EscapeSequence.h
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief ANSI escape sequence parsing.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <luna/Vector.h>
|
|
||||||
|
|
||||||
enum class EscapeCode
|
|
||||||
{
|
|
||||||
SaveCursor,
|
|
||||||
RestoreCursor,
|
|
||||||
CursorUp,
|
|
||||||
CursorDown,
|
|
||||||
CursorForward,
|
|
||||||
CursorBack,
|
|
||||||
CursorNextLine,
|
|
||||||
CursorPreviousLine,
|
|
||||||
CursorHorizontalAbsolute,
|
|
||||||
SetCursorPosition,
|
|
||||||
SelectGraphicRendition,
|
|
||||||
};
|
|
||||||
|
|
||||||
class EscapeSequenceParser
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
EscapeSequenceParser(u8 begin);
|
|
||||||
|
|
||||||
Result<bool> advance(u8 byte);
|
|
||||||
|
|
||||||
bool valid() const
|
|
||||||
{
|
|
||||||
return m_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vector<int>& parameters() const
|
|
||||||
{
|
|
||||||
return m_parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
EscapeCode code() const
|
|
||||||
{
|
|
||||||
return m_escape_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum class SequenceType
|
|
||||||
{
|
|
||||||
ESC,
|
|
||||||
CSI,
|
|
||||||
DCS,
|
|
||||||
OSC,
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector<u8> m_parameter;
|
|
||||||
Vector<int> m_parameters;
|
|
||||||
|
|
||||||
SequenceType m_sequence_type;
|
|
||||||
bool m_parsing_parameter { false };
|
|
||||||
bool m_valid { false };
|
|
||||||
|
|
||||||
EscapeCode m_escape_code;
|
|
||||||
};
|
|
@ -1,21 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Scanf.h
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief Scanf implementation.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief scanf() implementation.
|
|
||||||
*
|
|
||||||
* @param str The string to read input from.
|
|
||||||
* @param format The format string.
|
|
||||||
* @param ap The variadic argument list.
|
|
||||||
* @return int The number of arguments read, or -1 if the string was empty.
|
|
||||||
*/
|
|
||||||
int scanf_impl(const char* str, const char* format, va_list ap);
|
|
@ -1,146 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file EscapeSequence.cpp
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief ANSI escape sequence parsing.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <luna/CType.h>
|
|
||||||
#include <luna/Check.h>
|
|
||||||
#include <luna/EscapeSequence.h>
|
|
||||||
#include <luna/NumberParsing.h>
|
|
||||||
|
|
||||||
EscapeSequenceParser::EscapeSequenceParser(u8 begin)
|
|
||||||
{
|
|
||||||
switch (begin)
|
|
||||||
{
|
|
||||||
case 0x1b: m_sequence_type = SequenceType::ESC; break;
|
|
||||||
case 0x9b: m_sequence_type = SequenceType::CSI; break;
|
|
||||||
case 0x90: m_sequence_type = SequenceType::DCS; break;
|
|
||||||
case 0x9d: m_sequence_type = SequenceType::OSC; break;
|
|
||||||
default: fail("Unrecognized escape sequence type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<bool> EscapeSequenceParser::advance(u8 byte)
|
|
||||||
{
|
|
||||||
switch (m_sequence_type)
|
|
||||||
{
|
|
||||||
case SequenceType::ESC: {
|
|
||||||
switch (byte)
|
|
||||||
{
|
|
||||||
case '[': {
|
|
||||||
m_sequence_type = SequenceType::CSI;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
case 'P': {
|
|
||||||
m_sequence_type = SequenceType::DCS;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
case ']': {
|
|
||||||
m_sequence_type = SequenceType::OSC;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
case '7': {
|
|
||||||
m_escape_code = EscapeCode::SaveCursor;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case '8': {
|
|
||||||
m_escape_code = EscapeCode::RestoreCursor;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
default: {
|
|
||||||
m_valid = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case SequenceType::CSI: {
|
|
||||||
if (_isdigit(byte))
|
|
||||||
{
|
|
||||||
m_parsing_parameter = true;
|
|
||||||
TRY(m_parameter.try_append(byte));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_parsing_parameter && byte == ';')
|
|
||||||
{
|
|
||||||
TRY(m_parameters.try_append(0));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_parsing_parameter)
|
|
||||||
{
|
|
||||||
TRY(m_parameter.try_append(0));
|
|
||||||
int value = static_cast<int>(parse_unsigned_integer((const char*)m_parameter.data(), nullptr, 10));
|
|
||||||
m_parameter.clear();
|
|
||||||
TRY(m_parameters.try_append(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (byte)
|
|
||||||
{
|
|
||||||
case 'A': {
|
|
||||||
m_escape_code = EscapeCode::CursorUp;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case 'B': {
|
|
||||||
m_escape_code = EscapeCode::CursorDown;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case 'C': {
|
|
||||||
m_escape_code = EscapeCode::CursorForward;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case 'D': {
|
|
||||||
m_escape_code = EscapeCode::CursorBack;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case 'E': {
|
|
||||||
m_escape_code = EscapeCode::CursorNextLine;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case 'F': {
|
|
||||||
m_escape_code = EscapeCode::CursorPreviousLine;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case 'G': {
|
|
||||||
m_escape_code = EscapeCode::CursorHorizontalAbsolute;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case 'H': {
|
|
||||||
m_escape_code = EscapeCode::SetCursorPosition;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case 'm': {
|
|
||||||
m_escape_code = EscapeCode::SelectGraphicRendition;
|
|
||||||
m_valid = true;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
case ';': {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
default: {
|
|
||||||
m_valid = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case SequenceType::DCS: todo();
|
|
||||||
case SequenceType::OSC: todo();
|
|
||||||
default: todo();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,270 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Scanf.cpp
|
|
||||||
* @author apio (cloudapio.eu)
|
|
||||||
* @brief Scanf implementation.
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023, the Luna authors.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <luna/CString.h>
|
|
||||||
#include <luna/CType.h>
|
|
||||||
#include <luna/DebugLog.h>
|
|
||||||
#include <luna/Heap.h>
|
|
||||||
#include <luna/NumberParsing.h>
|
|
||||||
#include <luna/SystemError.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#define FLAG_DISCARD (1 << 0)
|
|
||||||
#define FLAG_ALLOC (1 << 1)
|
|
||||||
#define FLAG_WIDTH (1 << 2)
|
|
||||||
#define FLAG_LONG (1 << 3)
|
|
||||||
#define FLAG_LONG_LONG (1 << 4)
|
|
||||||
#define FLAG_SHORT (1 << 5)
|
|
||||||
#define FLAG_CHAR (1 << 6)
|
|
||||||
|
|
||||||
static int parse_flags(const char** format)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
switch (**format)
|
|
||||||
{
|
|
||||||
case '*':
|
|
||||||
result |= FLAG_DISCARD;
|
|
||||||
(*format)++;
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
result |= FLAG_ALLOC;
|
|
||||||
(*format)++;
|
|
||||||
break;
|
|
||||||
default: return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t parse_width(const char** format, int& flags)
|
|
||||||
{
|
|
||||||
size_t result = 0;
|
|
||||||
|
|
||||||
if (_isdigit(**format))
|
|
||||||
{
|
|
||||||
result = scan_unsigned_integer(format);
|
|
||||||
flags |= FLAG_WIDTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_type(const char** format, int& flags)
|
|
||||||
{
|
|
||||||
// FIXME: Support %j (intmax_t/uintmax_t)
|
|
||||||
switch (**format)
|
|
||||||
{
|
|
||||||
case 'h':
|
|
||||||
flags |= FLAG_SHORT;
|
|
||||||
(*format)++;
|
|
||||||
if (**format == 'h')
|
|
||||||
{
|
|
||||||
flags |= FLAG_CHAR;
|
|
||||||
(*format)++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
flags |= FLAG_LONG;
|
|
||||||
(*format)++;
|
|
||||||
if (**format == 'l')
|
|
||||||
{
|
|
||||||
flags |= FLAG_LONG_LONG;
|
|
||||||
(*format)++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
flags |= (sizeof(ptrdiff_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG;
|
|
||||||
(*format)++;
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
flags |= (sizeof(size_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG;
|
|
||||||
(*format)++;
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_parsed_signed_integer(ssize_t value, int flags, va_list ap)
|
|
||||||
{
|
|
||||||
if (flags & FLAG_LONG_LONG) *va_arg(ap, signed long long*) = (signed long long)value;
|
|
||||||
else if (flags & FLAG_LONG)
|
|
||||||
*va_arg(ap, signed long*) = (signed long)value;
|
|
||||||
else if (flags & FLAG_SHORT)
|
|
||||||
*va_arg(ap, signed int*) = (signed short)value;
|
|
||||||
else if (flags & FLAG_CHAR)
|
|
||||||
*va_arg(ap, signed int*) = (signed char)value;
|
|
||||||
else
|
|
||||||
*va_arg(ap, signed int*) = (signed int)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_parsed_unsigned_integer(size_t value, int flags, va_list ap)
|
|
||||||
{
|
|
||||||
if (flags & FLAG_LONG_LONG) *va_arg(ap, unsigned long long*) = (unsigned long long)value;
|
|
||||||
else if (flags & FLAG_LONG)
|
|
||||||
*va_arg(ap, unsigned long*) = (unsigned long)value;
|
|
||||||
else if (flags & FLAG_SHORT)
|
|
||||||
*va_arg(ap, unsigned int*) = (unsigned short)value;
|
|
||||||
else if (flags & FLAG_CHAR)
|
|
||||||
*va_arg(ap, unsigned int*) = (unsigned char)value;
|
|
||||||
else
|
|
||||||
*va_arg(ap, unsigned int*) = (unsigned int)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define WHITESPACE_CHARACTERS " \t\f\r\n\v"
|
|
||||||
|
|
||||||
static void skip_whitespace(const char** str)
|
|
||||||
{
|
|
||||||
*str += strspn(*str, WHITESPACE_CHARACTERS);
|
|
||||||
}
|
|
||||||
|
|
||||||
int scanf_impl(const char* str, const char* format, va_list ap)
|
|
||||||
{
|
|
||||||
int parsed = 0;
|
|
||||||
const char* s = str; // Keep a pointer to the beginning of the string for %n
|
|
||||||
|
|
||||||
if (*str == 0) return -1;
|
|
||||||
|
|
||||||
while (*format)
|
|
||||||
{
|
|
||||||
if (*format != '%')
|
|
||||||
{
|
|
||||||
normal:
|
|
||||||
if (!_isspace(*format))
|
|
||||||
{
|
|
||||||
if (*str != *format) return parsed;
|
|
||||||
str++;
|
|
||||||
format++;
|
|
||||||
if (*str == 0) return parsed;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_whitespace(&format);
|
|
||||||
skip_whitespace(&str);
|
|
||||||
if (*str == 0) return parsed;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
format++;
|
|
||||||
if (*format == '%')
|
|
||||||
{
|
|
||||||
skip_whitespace(&str);
|
|
||||||
goto normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int flags = parse_flags(&format);
|
|
||||||
size_t width = parse_width(&format, flags);
|
|
||||||
parse_type(&format, flags);
|
|
||||||
char specifier = *format++;
|
|
||||||
if (!specifier) return parsed;
|
|
||||||
|
|
||||||
switch (specifier)
|
|
||||||
{
|
|
||||||
case 's': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t chars = strcspn(str, WHITESPACE_CHARACTERS);
|
|
||||||
if (!chars) return parsed;
|
|
||||||
if ((flags & FLAG_WIDTH) && chars > width) chars = width;
|
|
||||||
if (!(flags & FLAG_DISCARD))
|
|
||||||
{
|
|
||||||
char* ptr;
|
|
||||||
if (flags & FLAG_ALLOC)
|
|
||||||
{
|
|
||||||
ptr = (char*)malloc_impl(chars + 1).value_or(nullptr);
|
|
||||||
if (!ptr) return parsed;
|
|
||||||
*va_arg(ap, char**) = ptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ptr = va_arg(ap, char*);
|
|
||||||
memcpy(ptr, str, chars);
|
|
||||||
ptr[chars] = 0;
|
|
||||||
}
|
|
||||||
str += chars;
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'c': {
|
|
||||||
if (strlen(str) < width) return parsed;
|
|
||||||
if (!(flags & FLAG_WIDTH)) width = 1;
|
|
||||||
if (!(flags & FLAG_DISCARD))
|
|
||||||
{
|
|
||||||
char* ptr;
|
|
||||||
if (flags & FLAG_ALLOC)
|
|
||||||
{
|
|
||||||
ptr = (char*)malloc_impl(width).value_or(nullptr);
|
|
||||||
if (!ptr) return parsed;
|
|
||||||
*va_arg(ap, char**) = ptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ptr = va_arg(ap, char*);
|
|
||||||
memcpy(ptr, str, width);
|
|
||||||
}
|
|
||||||
str += width;
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'd': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
ssize_t value = scan_signed_integer(&str, 10);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_signed_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'i': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
ssize_t value = scan_signed_integer(&str, 0);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_signed_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'o': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t value = scan_unsigned_integer(&str, 8);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'u': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t value = scan_unsigned_integer(&str, 10);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'X':
|
|
||||||
case 'x': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t value = scan_unsigned_integer(&str, 16);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'p': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t value = scan_unsigned_integer(&str, 16);
|
|
||||||
if (!(flags & FLAG_DISCARD)) *va_arg(ap, void**) = (void*)value;
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'n': {
|
|
||||||
if (!(flags & FLAG_DISCARD)) *va_arg(ap, int*) = (int)(str - s);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
dbgln("vsscanf: unknown conversion specifier: %%%c\n", specifier);
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsed;
|
|
||||||
}
|
|
@ -68,6 +68,15 @@ namespace os
|
|||||||
*/
|
*/
|
||||||
Result<void> remove(const Path& path);
|
Result<void> remove(const Path& path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove a directory tree from the file system recursively, deleting subfiles and subdirectories as
|
||||||
|
* well.
|
||||||
|
*
|
||||||
|
* @param path The path to remove.
|
||||||
|
* @return Result<void> Whether the operation succeeded.
|
||||||
|
*/
|
||||||
|
Result<void> remove_tree(const Path& path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the target of a symbolic link.
|
* @brief Read the target of a symbolic link.
|
||||||
*
|
*
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
#include <os/Directory.h>
|
#include <os/Directory.h>
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static bool should_skip_entry(const char* name, os::Directory::Filter filter)
|
static bool should_skip_entry(const char* name, os::Directory::Filter filter)
|
||||||
@ -32,8 +33,8 @@ namespace os
|
|||||||
{
|
{
|
||||||
auto dir = TRY(adopt_shared_if_nonnull(new (std::nothrow) Directory({})));
|
auto dir = TRY(adopt_shared_if_nonnull(new (std::nothrow) Directory({})));
|
||||||
|
|
||||||
int fd = openat(path.dirfd(), path.name().chars(), O_RDONLY | O_DIRECTORY, 0);
|
long rc = syscall(SYS_openat, path.dirfd(), path.name().chars(), O_RDONLY | O_DIRECTORY, 0);
|
||||||
if (fd < 0) return err(errno);
|
int fd = TRY(Result<int>::from_syscall(rc));
|
||||||
|
|
||||||
DIR* dp = fdopendir(fd);
|
DIR* dp = fdopendir(fd);
|
||||||
if (!dp)
|
if (!dp)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <luna/StringBuilder.h>
|
#include <luna/StringBuilder.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static SharedPtr<os::File> g_stdin = {};
|
static SharedPtr<os::File> g_stdin = {};
|
||||||
@ -82,8 +83,8 @@ namespace os
|
|||||||
{
|
{
|
||||||
auto file = TRY(adopt_shared_if_nonnull(new (std::nothrow) File({})));
|
auto file = TRY(adopt_shared_if_nonnull(new (std::nothrow) File({})));
|
||||||
|
|
||||||
int fd = openat(path.dirfd(), path.name().chars(), flags, mode);
|
long rc = syscall(SYS_openat, path.dirfd(), path.name().chars(), flags, mode);
|
||||||
if (fd < 0) return err(errno);
|
int fd = TRY(Result<int>::from_syscall(rc));
|
||||||
|
|
||||||
file->m_file = fdopen(fd, stdio_mode_from_openmode(flags));
|
file->m_file = fdopen(fd, stdio_mode_from_openmode(flags));
|
||||||
if (!file->m_file) return err(errno);
|
if (!file->m_file) return err(errno);
|
||||||
|
@ -10,13 +10,13 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <luna/Buffer.h>
|
|
||||||
#include <luna/PathParser.h>
|
#include <luna/PathParser.h>
|
||||||
#include <luna/String.h>
|
#include <luna/String.h>
|
||||||
#include <os/Directory.h>
|
#include <os/Directory.h>
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
namespace os::FileSystem
|
namespace os::FileSystem
|
||||||
@ -41,26 +41,39 @@ namespace os::FileSystem
|
|||||||
|
|
||||||
Result<void> stat(const Path& path, struct stat& st, bool follow_symlinks)
|
Result<void> stat(const Path& path, struct stat& st, bool follow_symlinks)
|
||||||
{
|
{
|
||||||
int rc = fstatat(path.dirfd(), path.name().chars(), &st,
|
long rc = syscall(SYS_fstatat, path.dirfd(), path.name().chars(), &st,
|
||||||
(int)(path.is_empty_path() | (follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW)));
|
(int)(path.is_empty_path() | (follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW)));
|
||||||
|
|
||||||
if (rc < 0) return err(errno);
|
return Result<void>::from_syscall(rc);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> create_directory(StringView path, mode_t mode)
|
Result<void> create_directory(StringView path, mode_t mode)
|
||||||
{
|
{
|
||||||
int rc = mkdir(path.chars(), mode);
|
long rc = syscall(SYS_mkdir, path.chars(), mode);
|
||||||
if (rc < 0) return err(errno);
|
|
||||||
return {};
|
return Result<void>::from_syscall(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> remove(const Path& path)
|
Result<void> remove(const Path& path)
|
||||||
{
|
{
|
||||||
// FIXME: This will not work on many operating systems that require rmdir() for directories.
|
long rc = syscall(SYS_unlinkat, path.dirfd(), path.name().chars(), 0);
|
||||||
int rc = unlinkat(path.dirfd(), path.name().chars(), 0);
|
|
||||||
if (rc < 0) return err(errno);
|
return Result<void>::from_syscall(rc);
|
||||||
return {};
|
}
|
||||||
|
|
||||||
|
Result<void> remove_tree(const Path& path)
|
||||||
|
{
|
||||||
|
auto rc = remove(path);
|
||||||
|
if (!rc.has_error()) return {};
|
||||||
|
if (rc.error() != ENOTEMPTY) return rc.release_error();
|
||||||
|
|
||||||
|
auto dir = TRY(os::Directory::open(path));
|
||||||
|
|
||||||
|
Vector<String> entries = TRY(dir->list_names(os::Directory::Filter::ParentAndBase));
|
||||||
|
|
||||||
|
for (const auto& entry : entries) { TRY(remove_tree({ dir->fd(), entry.view() })); }
|
||||||
|
|
||||||
|
return remove(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> readlink(const Path& path)
|
Result<String> readlink(const Path& path)
|
||||||
@ -69,13 +82,14 @@ namespace os::FileSystem
|
|||||||
TRY(stat(path, st, false));
|
TRY(stat(path, st, false));
|
||||||
if (!S_ISLNK(st.st_mode)) return String {};
|
if (!S_ISLNK(st.st_mode)) return String {};
|
||||||
|
|
||||||
Buffer buf = TRY(Buffer::create_sized(st.st_size + 1));
|
char* buf = (char*)TRY(calloc_impl(st.st_size + 1, 1));
|
||||||
memset(buf.data(), 0, buf.size());
|
auto guard = make_scope_guard([buf] { free_impl(buf); });
|
||||||
|
usize nread = TRY(
|
||||||
|
Result<usize>::from_syscall(syscall(SYS_readlinkat, path.dirfd(), path.name().chars(), buf, st.st_size)));
|
||||||
|
|
||||||
ssize_t nread = readlinkat(path.dirfd(), path.name().chars(), (char*)buf.data(), st.st_size);
|
guard.deactivate();
|
||||||
if (nread < 0) return err(errno);
|
|
||||||
|
|
||||||
return String { (char*)buf.release_data(), (usize)nread };
|
return String { buf, nread };
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> working_directory()
|
Result<String> working_directory()
|
||||||
@ -98,8 +112,8 @@ namespace os::FileSystem
|
|||||||
|
|
||||||
Result<void> change_directory(StringView path)
|
Result<void> change_directory(StringView path)
|
||||||
{
|
{
|
||||||
int rc = chdir(path.chars());
|
long rc = syscall(SYS_chdir, path.chars());
|
||||||
if (rc < 0) return err(errno);
|
|
||||||
return {};
|
return Result<void>::from_syscall(rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <os/Process.h>
|
#include <os/Process.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
extern char** environ;
|
extern char** environ;
|
||||||
@ -19,9 +19,8 @@ namespace os
|
|||||||
{
|
{
|
||||||
Result<pid_t> Process::fork()
|
Result<pid_t> Process::fork()
|
||||||
{
|
{
|
||||||
pid_t pid = ::fork();
|
long rc = syscall(SYS_fork);
|
||||||
if (pid < 0) return err(errno);
|
return Result<pid_t>::from_syscall(rc);
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> Process::exec(StringView path, Slice<String> args, bool search_in_path)
|
Result<void> Process::exec(StringView path, Slice<String> args, bool search_in_path)
|
||||||
@ -122,16 +121,14 @@ namespace os
|
|||||||
|
|
||||||
Result<pid_t> Process::wait(pid_t child, int* status, int options)
|
Result<pid_t> Process::wait(pid_t child, int* status, int options)
|
||||||
{
|
{
|
||||||
pid_t pid = waitpid(child, status, options);
|
long rc = syscall(SYS_waitpid, child, status, options);
|
||||||
if (pid < 0) return err(errno);
|
return Result<pid_t>::from_syscall(rc);
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> Process::kill(pid_t pid, int signo)
|
Result<void> Process::kill(pid_t pid, int signo)
|
||||||
{
|
{
|
||||||
int rc = ::kill(pid, signo);
|
long rc = syscall(SYS_kill, pid, signo);
|
||||||
if (rc < 0) return err(errno);
|
return Result<void>::from_syscall(rc);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void Process::exit(int status)
|
[[noreturn]] void Process::exit(int status)
|
||||||
|
@ -133,8 +133,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
if (interactive)
|
if (interactive)
|
||||||
{
|
{
|
||||||
auto cwd = TRY(os::FileSystem::working_directory());
|
auto cwd = TRY(os::FileSystem::working_directory());
|
||||||
os::print("\x1b[%dm%s\x1b[m@\x1b[36m%s\x1b[m:\x1b[1;34m%s\x1b[m%c ", getuid() == 0 ? 31 : 35, username,
|
os::print("%s@%s:%s%c ", username, hostname, cwd.chars(), prompt_end);
|
||||||
hostname, cwd.chars(), prompt_end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto maybe_cmd = input_file->read_line();
|
auto maybe_cmd = input_file->read_line();
|
||||||
|
Loading…
Reference in New Issue
Block a user