commit 01f91fef9e95f76fa044f6fe4a92bcd8a5fb61dc
parent d9b07a955ad27b4143c3f34b18b1130957718d50
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Fri, 9 Jan 2026 00:38:14 +0000
ls: fix repeated output
Diffstat:
2 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/linux.hpp b/linux.hpp
@@ -75,6 +75,10 @@ struct span
{
return begin() + size();
}
+ T& operator[](size_t n)
+ {
+ return ptr[n];
+ }
private:
T* ptr = nullptr;
size_t len = 0;
@@ -172,6 +176,9 @@ struct [[gnu::packed]] linux_dirent64 {
off64_t d_off; /* Not an offset; see getdents() */
unsigned short d_reclen; /* Size of this dirent */
unsigned char d_type; /* File type */
+
+ linux_dirent64* next() noexcept { return reinterpret_cast<linux_dirent64*>(reinterpret_cast<char*>(this) + d_reclen); }
+ char* name() noexcept { return reinterpret_cast<char*>(this) + sizeof(*this); }
};
extern syscall_result<size_t> getdents64(file dir, span<char> buffer) noexcept;
diff --git a/ls.cpp b/ls.cpp
@@ -1,31 +1,45 @@
#include "linux.hpp"
+template <typename T>
+struct spanstack
+{
+ spanstack(span<T> st) : storage{st} {}
+
+ bool empty() const noexcept { return not n; }
+ bool full() const noexcept { return n == storage.size(); }
+ span<T const> data() noexcept { return {(T const*)storage.begin(), n}; }
+ void push_back(T const& v) noexcept
+ {
+ assert(not full());
+ storage[n++] = v;
+ }
+private:
+ span<T> storage;
+ size_t n = 0;
+};
+
int main()
{
auto dir = openat(AT_FDCWD, ".", O_RDONLY, 0);
assert(dir);
alignas(linux_dirent64) char buf[256];
- span<char const> ios[sizeof(buf)/sizeof(linux_dirent64)];
+ span<char const> ios_storage[sizeof(buf)/sizeof(linux_dirent64)];
for (;;)
{
- unsigned n_io = 0;
+ spanstack ios{span{ios_storage}};
auto res = getdents64(*dir, buf);
- size_t n = *res;
-
- if (!n)
+ void* const end = buf + *res;
+ if (end == buf)
break;
- for (size_t i = 0; i + sizeof(linux_dirent64) < n;)
+ for (auto ent = reinterpret_cast<linux_dirent64*>(buf); ent != end; ent = ent->next())
{
- auto e = reinterpret_cast<linux_dirent64*>(buf + i);
- char* const name = buf + i + sizeof(linux_dirent64);
+ char* const name = ent->name();
size_t len = c_str{name}.length();
name[len++] = '\n';
- ios[n_io++] = span<char const>{name, len};
- i += e->d_reclen;
- break;
+ ios.push_back({name, len});
}
- *write(stdout, ios);
+ *write(stdout, ios.data());
}
}