Compare commits
15 Commits
1f467580ee
...
59abb5d344
Author | SHA1 | Date |
---|---|---|
Bananymous | 59abb5d344 | |
Bananymous | 9594ee8e47 | |
Bananymous | 7a4ec7f7a3 | |
Bananymous | 51db1706e9 | |
Bananymous | ac9e71d9c7 | |
Bananymous | f3f5ca1bd8 | |
Bananymous | b979023b9d | |
Bananymous | 915dea01c9 | |
Bananymous | 566bb73897 | |
Bananymous | fb0d8d746f | |
Bananymous | 1b24c4f279 | |
Bananymous | a5a041e637 | |
Bananymous | c469d9b3ff | |
Bananymous | 373d166076 | |
Bananymous | 3c54243ac7 |
|
@ -0,0 +1,156 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class numeric_limits
|
||||
{
|
||||
public:
|
||||
numeric_limits() = delete;
|
||||
|
||||
static inline constexpr T max()
|
||||
{
|
||||
if constexpr(is_same_v<T, char>)
|
||||
return __SCHAR_MAX__;
|
||||
if constexpr(is_same_v<T, signed char>)
|
||||
return __SCHAR_MAX__;
|
||||
if constexpr(is_same_v<T, unsigned char>)
|
||||
return (T)__SCHAR_MAX__ * 2 + 1;
|
||||
|
||||
if constexpr(is_same_v<T, short>)
|
||||
return __SHRT_MAX__;
|
||||
if constexpr(is_same_v<T, int>)
|
||||
return __INT_MAX__;
|
||||
if constexpr(is_same_v<T, long>)
|
||||
return __LONG_MAX__;
|
||||
if constexpr(is_same_v<T, long long>)
|
||||
return __LONG_LONG_MAX__;
|
||||
|
||||
if constexpr(is_same_v<T, unsigned short>)
|
||||
return (T)__SHRT_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned int>)
|
||||
return (T)__INT_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned long>)
|
||||
return (T)__LONG_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned long long>)
|
||||
return (T)__LONG_LONG_MAX__ * 2 + 1;
|
||||
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX__;
|
||||
}
|
||||
|
||||
static inline constexpr T min()
|
||||
{
|
||||
if constexpr(is_signed_v<T> && is_integral_v<T>)
|
||||
return -max() - 1;
|
||||
|
||||
if constexpr(is_unsigned_v<T> && is_integral_v<T>)
|
||||
return 0;
|
||||
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN__;
|
||||
}
|
||||
|
||||
static inline constexpr bool has_infinity()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_HAS_INFINITY__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_HAS_INFINITY__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_HAS_INFINITY__;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline constexpr T infinity() requires(has_infinity())
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_inff();
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_inf();
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_infl();
|
||||
}
|
||||
|
||||
static inline constexpr bool has_quiet_NaN()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_HAS_QUIET_NAN__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_HAS_QUIET_NAN__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_HAS_QUIET_NAN__;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline constexpr T quiet_NaN() requires(has_quiet_NaN())
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_nanf("");
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_nan("");
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_nanl("");
|
||||
}
|
||||
|
||||
static inline constexpr int max_exponent2()
|
||||
{
|
||||
static_assert(__FLT_RADIX__ == 2);
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int max_exponent10()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX_10_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX_10_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX_10_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int min_exponent2()
|
||||
{
|
||||
static_assert(__FLT_RADIX__ == 2);
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int min_exponent10()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN_10_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN_10_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN_10_EXP__;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
enum class DeviceNumber : dev_t
|
||||
{
|
||||
Framebuffer = 1,
|
||||
TTY,
|
||||
Serial,
|
||||
Null,
|
||||
Zero,
|
||||
Debug,
|
||||
Input,
|
||||
SCSI,
|
||||
NVMeController,
|
||||
NVMeNamespace,
|
||||
Ethernet,
|
||||
TmpFS,
|
||||
};
|
||||
|
||||
}
|
|
@ -19,7 +19,6 @@ namespace Kernel
|
|||
void add_device(BAN::RefPtr<Device>);
|
||||
void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>);
|
||||
|
||||
dev_t get_next_dev() const;
|
||||
int get_next_input_device() const;
|
||||
|
||||
void initiate_sync(bool should_block);
|
||||
|
|
|
@ -49,6 +49,8 @@ namespace Kernel
|
|||
|
||||
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_inode; }
|
||||
|
||||
virtual dev_t dev() const override { return m_block_device->rdev(); };
|
||||
|
||||
private:
|
||||
Ext2FS(BAN::RefPtr<BlockDevice> block_device)
|
||||
: m_block_device(block_device)
|
||||
|
|
|
@ -10,6 +10,8 @@ namespace Kernel
|
|||
public:
|
||||
virtual ~FileSystem() {}
|
||||
virtual BAN::RefPtr<Inode> root_inode() = 0;
|
||||
|
||||
virtual dev_t dev() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Kernel
|
|||
|
||||
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_inode; }
|
||||
|
||||
virtual dev_t dev() const override { return m_rdev; }
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<TmpInode>> open_inode(ino_t ino);
|
||||
|
||||
BAN::ErrorOr<void> add_to_cache(BAN::RefPtr<TmpInode>);
|
||||
|
@ -115,6 +117,8 @@ namespace Kernel
|
|||
paddr_t find_indirect(PageInfo root, size_t index, size_t depth);
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
|
||||
RecursiveSpinLock m_lock;
|
||||
|
||||
BAN::HashMap<ino_t, BAN::RefPtr<TmpInode>> m_inode_cache;
|
||||
|
|
|
@ -35,8 +35,8 @@ namespace Kernel
|
|||
virtual timespec ctime() const override { return m_inode_info.ctime; }
|
||||
virtual blksize_t blksize() const override { return PAGE_SIZE; }
|
||||
virtual blkcnt_t blocks() const override { return m_inode_info.blocks; }
|
||||
virtual dev_t dev() const override { return 0; } // TODO
|
||||
virtual dev_t rdev() const override { return 0; } // TODO
|
||||
virtual dev_t dev() const override;
|
||||
virtual dev_t rdev() const override { return 0; }
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&);
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace Kernel
|
|||
|
||||
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_fs->root_inode(); }
|
||||
|
||||
// FIXME:
|
||||
virtual dev_t dev() const override { return 0; }
|
||||
|
||||
BAN::ErrorOr<void> mount(const Credentials&, BAN::StringView, BAN::StringView);
|
||||
BAN::ErrorOr<void> mount(const Credentials&, FileSystem*, BAN::StringView);
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ namespace Kernel::Input
|
|||
class PS2Device : public CharacterDevice, public Interruptable
|
||||
{
|
||||
public:
|
||||
PS2Device(PS2Controller&);
|
||||
virtual ~PS2Device() {}
|
||||
|
||||
virtual void send_initialize() = 0;
|
||||
|
@ -27,9 +26,12 @@ namespace Kernel::Input
|
|||
|
||||
virtual void update() final override { m_controller.update_command_queue(); }
|
||||
|
||||
protected:
|
||||
PS2Device(PS2Controller&);
|
||||
|
||||
private:
|
||||
const BAN::String m_name;
|
||||
const dev_t m_rdev;
|
||||
const BAN::String m_name;
|
||||
PS2Controller& m_controller;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#include <kernel/Device/DebugDevice.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<DebugDevice>> DebugDevice::create(mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
auto* result = new DebugDevice(mode, uid, gid, DevFileSystem::get().get_next_dev());
|
||||
static uint32_t minor = 0;
|
||||
auto* result = new DebugDevice(mode, uid, gid, makedev(DeviceNumber::Debug, minor++));
|
||||
if (result == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return BAN::RefPtr<DebugDevice>::adopt(result);
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include <kernel/BootInfo.h>
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/Device/FramebufferDevice.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
|
||||
#include <sys/framebuffer.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -23,7 +25,7 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(ENOTSUP);
|
||||
auto* device_ptr = new FramebufferDevice(
|
||||
0660, 0, 900,
|
||||
DevFileSystem::get().get_next_dev(),
|
||||
makedev(DeviceNumber::Framebuffer, get_framebuffer_device_index()),
|
||||
g_boot_info.framebuffer.address,
|
||||
g_boot_info.framebuffer.width,
|
||||
g_boot_info.framebuffer.height,
|
||||
|
@ -39,7 +41,7 @@ namespace Kernel
|
|||
|
||||
FramebufferDevice::FramebufferDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev, paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp)
|
||||
: CharacterDevice(mode, uid, gid)
|
||||
, m_name(BAN::String::formatted("fb{}", get_framebuffer_device_index()))
|
||||
, m_name(BAN::String::formatted("fb{}", minor(rdev)))
|
||||
, m_rdev(rdev)
|
||||
, m_video_memory_paddr(paddr)
|
||||
, m_width(width)
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/Device/NullDevice.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<NullDevice>> NullDevice::create(mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
auto* result = new NullDevice(mode, uid, gid, DevFileSystem::get().get_next_dev());
|
||||
static uint32_t minor = 0;
|
||||
auto* result = new NullDevice(mode, uid, gid, makedev(DeviceNumber::Null, minor++));
|
||||
if (result == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return BAN::RefPtr<NullDevice>::adopt(result);
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/Device/ZeroDevice.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<ZeroDevice>> ZeroDevice::create(mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
auto* result = new ZeroDevice(mode, uid, gid, DevFileSystem::get().get_next_dev());
|
||||
static uint32_t minor = 0;
|
||||
auto* result = new ZeroDevice(mode, uid, gid, makedev(DeviceNumber::Zero, minor++));
|
||||
if (result == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return BAN::RefPtr<ZeroDevice>::adopt(result);
|
||||
|
|
|
@ -122,17 +122,9 @@ namespace Kernel
|
|||
MUST(static_cast<TmpDirectoryInode*>(root_inode().ptr())->link_inode(*inode, path));
|
||||
}
|
||||
|
||||
dev_t DevFileSystem::get_next_dev() const
|
||||
{
|
||||
LockGuard _(m_device_lock);
|
||||
static dev_t next_dev = 1;
|
||||
return next_dev++;
|
||||
}
|
||||
|
||||
int DevFileSystem::get_next_input_device() const
|
||||
{
|
||||
LockGuard _(m_device_lock);
|
||||
static dev_t next_dev = 0;
|
||||
static BAN::Atomic<dev_t> next_dev = 0;
|
||||
return next_dev++;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/TmpFS/FileSystem.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static dev_t get_next_rdev()
|
||||
{
|
||||
static dev_t minor = 0;
|
||||
return makedev(DeviceNumber::TmpFS, minor++);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<TmpFileSystem*> TmpFileSystem::create(size_t max_pages, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
if (max_pages < 2)
|
||||
|
@ -17,7 +26,8 @@ namespace Kernel
|
|||
}
|
||||
|
||||
TmpFileSystem::TmpFileSystem(size_t max_pages)
|
||||
: m_max_pages(max_pages)
|
||||
: m_rdev(get_next_rdev())
|
||||
, m_max_pages(max_pages)
|
||||
{ }
|
||||
|
||||
BAN::ErrorOr<void> TmpFileSystem::initialize(mode_t mode, uid_t uid, gid_t gid)
|
||||
|
|
|
@ -41,6 +41,11 @@ namespace Kernel
|
|||
|
||||
/* GENERAL INODE */
|
||||
|
||||
dev_t TmpInode::dev() const
|
||||
{
|
||||
return m_fs.dev();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<TmpInode>> TmpInode::create_from_existing(TmpFileSystem& fs, ino_t ino, const TmpInodeInfo& info)
|
||||
{
|
||||
TmpInode* inode_ptr = nullptr;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Input/PS2/Config.h>
|
||||
#include <kernel/Input/PS2/Device.h>
|
||||
|
@ -10,8 +11,8 @@ namespace Kernel::Input
|
|||
|
||||
PS2Device::PS2Device(PS2Controller& controller)
|
||||
: CharacterDevice(0440, 0, 901)
|
||||
, m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device()))
|
||||
, m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0))
|
||||
, m_rdev(makedev(DeviceNumber::Input, DevFileSystem::get().get_next_input_device()))
|
||||
, m_name(BAN::String::formatted("input{}", minor(m_rdev)))
|
||||
, m_controller(controller)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <BAN/Endianness.h>
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
|
||||
|
@ -8,12 +9,6 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
static dev_t get_network_rdev_major()
|
||||
{
|
||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||
return major;
|
||||
}
|
||||
|
||||
static dev_t get_network_rdev_minor()
|
||||
{
|
||||
static dev_t minor = 0;
|
||||
|
@ -23,7 +18,7 @@ namespace Kernel
|
|||
NetworkInterface::NetworkInterface()
|
||||
: CharacterDevice(0400, 0, 0)
|
||||
, m_type(Type::Ethernet)
|
||||
, m_rdev(makedev(get_network_rdev_major(), get_network_rdev_minor()))
|
||||
, m_rdev(makedev(DeviceNumber::Ethernet, get_network_rdev_minor()))
|
||||
{
|
||||
ASSERT(minor(m_rdev) < 10);
|
||||
ASSERT(m_type == Type::Ethernet);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <kernel/Debug.h>
|
||||
#include <kernel/CPUID.h>
|
||||
#include <kernel/Debug.h>
|
||||
#include <kernel/Random.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -18,9 +19,16 @@ namespace Kernel
|
|||
CPUID::get_features(ecx, edx);
|
||||
|
||||
if (ecx & CPUID::ECX_RDRND)
|
||||
{
|
||||
asm volatile("rdrand %0" : "=a"(s_rand_seed));
|
||||
dprintln("RNG seeded by RDRAND");
|
||||
}
|
||||
else
|
||||
dprintln("No RDRAND available");
|
||||
{
|
||||
auto rt = SystemTimer::get().real_time();
|
||||
s_rand_seed ^= rt.tv_sec ^ rt.tv_nsec;
|
||||
dprintln("RNG seeded by real time");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Random::get_u32()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Storage/ATA/ATABus.h>
|
||||
|
@ -9,12 +10,6 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
static dev_t get_ata_dev_major()
|
||||
{
|
||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||
return major;
|
||||
}
|
||||
|
||||
static dev_t get_ata_dev_minor()
|
||||
{
|
||||
static dev_t minor = 0;
|
||||
|
@ -22,7 +17,7 @@ namespace Kernel
|
|||
}
|
||||
|
||||
detail::ATABaseDevice::ATABaseDevice()
|
||||
: m_rdev(makedev(get_ata_dev_major(), get_ata_dev_minor()))
|
||||
: m_rdev(makedev(DeviceNumber::SCSI, get_ata_dev_minor()))
|
||||
{
|
||||
strcpy(m_name, "sda");
|
||||
m_name[2] += minor(m_rdev);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <BAN/Array.h>
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/Storage/NVMe/Controller.h>
|
||||
|
@ -11,12 +12,6 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
static dev_t get_ctrl_dev_major()
|
||||
{
|
||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||
return major;
|
||||
}
|
||||
|
||||
static dev_t get_ctrl_dev_minor()
|
||||
{
|
||||
static dev_t minor = 0;
|
||||
|
@ -36,7 +31,7 @@ namespace Kernel
|
|||
NVMeController::NVMeController(PCI::Device& pci_device)
|
||||
: CharacterDevice(0600, 0, 0)
|
||||
, m_pci_device(pci_device)
|
||||
, m_rdev(makedev(get_ctrl_dev_major(), get_ctrl_dev_minor()))
|
||||
, m_rdev(makedev(DeviceNumber::NVMeController, get_ctrl_dev_minor()))
|
||||
{
|
||||
ASSERT(minor(m_rdev) < 10);
|
||||
strcpy(m_name, "nvmeX");
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Storage/NVMe/Controller.h>
|
||||
#include <kernel/Storage/NVMe/Namespace.h>
|
||||
|
@ -7,12 +8,6 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
static dev_t get_ns_dev_major()
|
||||
{
|
||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||
return major;
|
||||
}
|
||||
|
||||
static dev_t get_ns_dev_minor()
|
||||
{
|
||||
static dev_t minor = 0;
|
||||
|
@ -34,7 +29,7 @@ namespace Kernel
|
|||
, m_nsid(nsid)
|
||||
, m_block_size(block_size)
|
||||
, m_block_count(block_count)
|
||||
, m_rdev(makedev(get_ns_dev_major(), get_ns_dev_minor()))
|
||||
, m_rdev(makedev(DeviceNumber::NVMeNamespace, get_ns_dev_minor()))
|
||||
{
|
||||
ASSERT(minor(m_rdev) < 10);
|
||||
ASSERT(m_controller.name().size() + 2 < sizeof(m_name));
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Kernel
|
|||
{
|
||||
ASSERT(buffer.size() >= block_count * m_device->blksize());
|
||||
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
|
||||
if (m_first_block + block_count > blocks_in_partition)
|
||||
if (first_block + block_count > blocks_in_partition)
|
||||
return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries);
|
||||
TRY(m_device->write_blocks(m_first_block + first_block, block_count, buffer));
|
||||
return {};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <BAN/Array.h>
|
||||
#include <kernel/CriticalScope.h>
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
|
@ -42,9 +43,8 @@ namespace Kernel
|
|||
|
||||
static dev_t next_rdev()
|
||||
{
|
||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||
static dev_t minor = 0;
|
||||
return makedev(major, minor++);
|
||||
return makedev(DeviceNumber::Serial, minor++);
|
||||
}
|
||||
|
||||
void Serial::initialize()
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
#include <BAN/UTF8.h>
|
||||
#include <kernel/Debug.h>
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/Process.h>
|
||||
|
@ -26,9 +27,8 @@ namespace Kernel
|
|||
|
||||
static dev_t next_rdev()
|
||||
{
|
||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||
static dev_t minor = 0;
|
||||
return makedev(major, minor++);
|
||||
return makedev(DeviceNumber::TTY, minor++);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> VirtualTTY::create(TerminalDriver* driver)
|
||||
|
|
|
@ -131,7 +131,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> HPET::initialize(bool force_pic)
|
||||
{
|
||||
auto* header = (ACPI::HPET*)ACPI::get().get_header("HPET"sv, 0);
|
||||
auto* header = static_cast<const ACPI::HPET*>(ACPI::get().get_header("HPET"sv, 0));
|
||||
if (header == nullptr)
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
|
||||
|
@ -153,7 +153,7 @@ namespace Kernel
|
|||
|
||||
m_is_64bit = regs.capabilities & COUNT_SIZE_CAP;
|
||||
|
||||
// Disable main counter and reset value
|
||||
// Disable and reset main counter
|
||||
regs.configuration.low = regs.configuration.low & ~ENABLE_CNF;
|
||||
regs.main_counter.high = 0;
|
||||
regs.main_counter.low = 0;
|
||||
|
@ -244,27 +244,28 @@ namespace Kernel
|
|||
if (m_is_64bit)
|
||||
return regs.main_counter.full;
|
||||
|
||||
uint32_t current = regs.main_counter.low;
|
||||
uint64_t wraps = m_32bit_wraps;
|
||||
if (current < (uint32_t)m_last_ticks)
|
||||
CriticalScope _;
|
||||
uint32_t current_low = regs.main_counter.low;
|
||||
uint32_t wraps = m_32bit_wraps;
|
||||
if (current_low < (uint32_t)m_last_ticks)
|
||||
wraps++;
|
||||
return (wraps << 32) | current;
|
||||
return ((uint64_t)wraps << 32) | current_low;
|
||||
}
|
||||
|
||||
void HPET::handle_irq()
|
||||
{
|
||||
auto& regs = registers();
|
||||
|
||||
uint64_t current_ticks { 0 };
|
||||
uint64_t current_ticks;
|
||||
|
||||
if (m_is_64bit)
|
||||
current_ticks = regs.main_counter.full;
|
||||
else
|
||||
{
|
||||
uint32_t current = regs.main_counter.low;
|
||||
if (current < (uint32_t)m_last_ticks)
|
||||
uint32_t current_low = regs.main_counter.low;
|
||||
if (current_low < (uint32_t)m_last_ticks)
|
||||
m_32bit_wraps++;
|
||||
current_ticks = ((uint64_t)m_32bit_wraps << 32) | current;
|
||||
current_ticks = ((uint64_t)m_32bit_wraps << 32) | current_low;
|
||||
}
|
||||
|
||||
m_last_ticks = current_ticks;
|
||||
|
@ -274,7 +275,8 @@ namespace Kernel
|
|||
|
||||
uint64_t HPET::ms_since_boot() const
|
||||
{
|
||||
return ns_since_boot() / 1'000'000;
|
||||
auto current = time_since_boot();
|
||||
return current.tv_sec * 1'000 + current.tv_nsec / 1'000'000;
|
||||
}
|
||||
|
||||
uint64_t HPET::ns_since_boot() const
|
||||
|
|
|
@ -42,30 +42,30 @@ struct stat
|
|||
#define st_ctime st_ctim.tv_sec
|
||||
#define st_mtime st_mtim.tv_sec
|
||||
|
||||
#define S_IRWXU ((mode_t)00700)
|
||||
#define S_IRUSR ((mode_t)00400)
|
||||
#define S_IWUSR ((mode_t)00200)
|
||||
#define S_IXUSR ((mode_t)00100)
|
||||
#define S_IRWXG ((mode_t)00070)
|
||||
#define S_IRGRP ((mode_t)00040)
|
||||
#define S_IWGRP ((mode_t)00020)
|
||||
#define S_IXGRP ((mode_t)00010)
|
||||
#define S_IRWXO ((mode_t)00007)
|
||||
#define S_IROTH ((mode_t)00004)
|
||||
#define S_IWOTH ((mode_t)00002)
|
||||
#define S_IXOTH ((mode_t)00001)
|
||||
#define S_ISUID ((mode_t)04000)
|
||||
#define S_ISGID ((mode_t)02000)
|
||||
#define S_ISVTX ((mode_t)01000)
|
||||
#define S_IRWXU 00700
|
||||
#define S_IRUSR 00400
|
||||
#define S_IWUSR 00200
|
||||
#define S_IXUSR 00100
|
||||
#define S_IRWXG 00070
|
||||
#define S_IRGRP 00040
|
||||
#define S_IWGRP 00020
|
||||
#define S_IXGRP 00010
|
||||
#define S_IRWXO 00007
|
||||
#define S_IROTH 00004
|
||||
#define S_IWOTH 00002
|
||||
#define S_IXOTH 00001
|
||||
#define S_ISUID 04000
|
||||
#define S_ISGID 02000
|
||||
#define S_ISVTX 01000
|
||||
|
||||
#define S_IFIFO ((mode_t)0010000)
|
||||
#define S_IFCHR ((mode_t)0020000)
|
||||
#define S_IFDIR ((mode_t)0040000)
|
||||
#define S_IFBLK ((mode_t)0060000)
|
||||
#define S_IFREG ((mode_t)0100000)
|
||||
#define S_IFLNK ((mode_t)0120000)
|
||||
#define S_IFSOCK ((mode_t)0140000)
|
||||
#define S_IFMASK ((mode_t)0170000)
|
||||
#define S_IFIFO 0010000
|
||||
#define S_IFCHR 0020000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_IFBLK 0060000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IFLNK 0120000
|
||||
#define S_IFSOCK 0140000
|
||||
#define S_IFMASK 0170000
|
||||
#define S_IFMT S_IFMASK
|
||||
|
||||
#define S_ISBLK(mode) ((mode & S_IFMASK) == S_IFBLK)
|
||||
|
|
|
@ -122,17 +122,6 @@ static void integer_to_string(char* buffer, T value, int base, bool upper, forma
|
|||
template<BAN::floating_point T>
|
||||
static void floating_point_to_string(char* buffer, T value, bool upper, const format_options_t options)
|
||||
{
|
||||
if (isnan(value))
|
||||
{
|
||||
if (value < (T)0.0)
|
||||
{
|
||||
*buffer = '-';
|
||||
buffer++;
|
||||
}
|
||||
strcpy(buffer, upper ? "NAN" : "nan");
|
||||
return;
|
||||
}
|
||||
|
||||
int percision = 6;
|
||||
if (options.percision != -1)
|
||||
percision = options.percision;
|
||||
|
@ -150,6 +139,11 @@ static void floating_point_to_string(char* buffer, T value, bool upper, const fo
|
|||
else if (options.show_plus_sign_as_space)
|
||||
buffer[offset++] = ' ';
|
||||
|
||||
if (isnan(value))
|
||||
{
|
||||
strcpy(buffer + offset, upper ? "NAN" : "nan");
|
||||
return;
|
||||
}
|
||||
if (isinf(value))
|
||||
{
|
||||
strcpy(buffer + offset, upper ? "INF" : "inf");
|
||||
|
@ -223,6 +217,17 @@ static void floating_point_to_exponent_string(char* buffer, T value, bool upper,
|
|||
else if (options.show_plus_sign_as_space)
|
||||
buffer[offset++] = ' ';
|
||||
|
||||
if (isnan(value))
|
||||
{
|
||||
strcpy(buffer + offset, upper ? "NAN" : "nan");
|
||||
return;
|
||||
}
|
||||
if (isinf(value))
|
||||
{
|
||||
strcpy(buffer + offset, upper ? "INF" : "inf");
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate which number to put as exponent
|
||||
int exponent = 0;
|
||||
if (value != (T)0.0)
|
||||
|
|
|
@ -81,7 +81,7 @@ static mode_t parse_mode_string(const char* mode_str)
|
|||
return 0;
|
||||
if (len == 3 && mode_str[1] == mode_str[2])
|
||||
return 0;
|
||||
if (strcspn(mode_str + 1, "b+") != len - 1)
|
||||
if (strspn(mode_str + 1, "b+") != len - 1)
|
||||
return 0;
|
||||
bool plus = (mode_str[1] == '+' || mode_str[2] == '+');
|
||||
switch (mode_str[0])
|
||||
|
|
323
libc/stdlib.cpp
323
libc/stdlib.cpp
|
@ -1,10 +1,12 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <BAN/Limits.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <icxxabi.h>
|
||||
|
@ -50,24 +52,329 @@ int atexit(void (*func)(void))
|
|||
return 0;
|
||||
}
|
||||
|
||||
int atoi(const char* str)
|
||||
static constexpr int get_base_digit(char c, int base)
|
||||
{
|
||||
int digit = -1;
|
||||
if (isdigit(c))
|
||||
digit = c - '0';
|
||||
else if (isalpha(c))
|
||||
digit = 10 + tolower(c) - 'a';
|
||||
if (digit < base)
|
||||
return digit;
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_multiplication_overflow(T a, T b)
|
||||
{
|
||||
if (a == 0 || b == 0)
|
||||
return false;
|
||||
if ((a > 0) == (b > 0))
|
||||
return a > BAN::numeric_limits<T>::max() / b;
|
||||
else
|
||||
return a < BAN::numeric_limits<T>::min() / b;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_addition_overflow(T a, T b)
|
||||
{
|
||||
if (a > 0 && b > 0)
|
||||
return a > BAN::numeric_limits<T>::max() - b;
|
||||
if (a < 0 && b < 0)
|
||||
return a < BAN::numeric_limits<T>::min() - b;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_digit_append_overflow(bool negative, T current, int digit, int base)
|
||||
{
|
||||
if (BAN::is_unsigned_v<T> && negative && digit)
|
||||
return true;
|
||||
if (will_multiplication_overflow<T>(current, base))
|
||||
return true;
|
||||
if (will_addition_overflow<T>(current * base, current < 0 ? -digit : digit))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static T strtoT(const char* str, char** endp, int base, int& error)
|
||||
{
|
||||
// validate base
|
||||
if (base != 0 && (base < 2 || base > 36))
|
||||
{
|
||||
error = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// skip whitespace
|
||||
while (isspace(*str))
|
||||
str++;
|
||||
|
||||
// get sign and skip it
|
||||
bool negative = (*str == '-');
|
||||
|
||||
if (*str == '-' || *str == '+')
|
||||
str++;
|
||||
|
||||
int res = 0;
|
||||
while (isdigit(*str))
|
||||
// determine base from prefix
|
||||
if (base == 0)
|
||||
{
|
||||
res = (res * 10) + (*str - '0');
|
||||
str++;
|
||||
if (strncasecmp(str, "0x", 2) == 0)
|
||||
base = 16;
|
||||
else if (*str == '0')
|
||||
base = 8;
|
||||
else if (isdigit(*str))
|
||||
base = 10;
|
||||
}
|
||||
|
||||
return negative ? -res : res;
|
||||
// check for invalid conversion
|
||||
if (get_base_digit(*str, base) == -1)
|
||||
{
|
||||
if (endp)
|
||||
*endp = const_cast<char*>(str);
|
||||
error = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// remove "0x" prefix from hexadecimal
|
||||
if (base == 16 && strncasecmp(str, "0x", 2) == 0 && get_base_digit(str[2], base) != -1)
|
||||
str += 2;
|
||||
|
||||
bool overflow = false;
|
||||
|
||||
T result = 0;
|
||||
// calculate the value of the number in string
|
||||
while (!overflow)
|
||||
{
|
||||
int digit = get_base_digit(*str, base);
|
||||
if (digit == -1)
|
||||
break;
|
||||
str++;
|
||||
|
||||
overflow = will_digit_append_overflow(negative, result, digit, base);
|
||||
if (!overflow)
|
||||
result = result * base + (negative ? -digit : digit);
|
||||
}
|
||||
|
||||
// save endp if asked
|
||||
if (endp)
|
||||
{
|
||||
while (get_base_digit(*str, base) != -1)
|
||||
str++;
|
||||
*endp = const_cast<char*>(str);
|
||||
}
|
||||
|
||||
// return error on overflow
|
||||
if (overflow)
|
||||
{
|
||||
error = ERANGE;
|
||||
if constexpr(BAN::is_unsigned_v<T>)
|
||||
return BAN::numeric_limits<T>::max();
|
||||
return negative ? BAN::numeric_limits<T>::min() : BAN::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<BAN::floating_point T>
|
||||
static T strtoT(const char* str, char** endp, int& error)
|
||||
{
|
||||
// find nan end including possible n-char-sequence
|
||||
auto get_nan_end = [](const char* str) -> const char*
|
||||
{
|
||||
ASSERT(strcasecmp(str, "nan") == 0);
|
||||
if (str[3] != '(')
|
||||
return str + 3;
|
||||
for (size_t i = 4; isalnum(str[i]) || str[i] == '_'; i++)
|
||||
if (str[i] == ')')
|
||||
return str + i + 1;
|
||||
return str + 3;
|
||||
};
|
||||
|
||||
// skip whitespace
|
||||
while (isspace(*str))
|
||||
str++;
|
||||
|
||||
// get sign and skip it
|
||||
bool negative = (*str == '-');
|
||||
if (*str == '-' || *str == '+')
|
||||
str++;
|
||||
|
||||
// check for infinity or nan
|
||||
{
|
||||
T result = 0;
|
||||
|
||||
if (strncasecmp(str, "inf", 3) == 0)
|
||||
{
|
||||
result = BAN::numeric_limits<T>::infinity();
|
||||
str += strncasecmp(str, "infinity", 8) ? 3 : 8;
|
||||
}
|
||||
else if (strncasecmp(str, "nan", 3) == 0)
|
||||
{
|
||||
result = BAN::numeric_limits<T>::quiet_NaN();
|
||||
str = get_nan_end(str);
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
if (endp)
|
||||
*endp = const_cast<char*>(str);
|
||||
return negative ? -result : result;
|
||||
}
|
||||
}
|
||||
|
||||
// no conversion can be performed -- not ([digit] || .[digit])
|
||||
if (!(isdigit(*str) || (str[0] == '.' && isdigit(str[1]))))
|
||||
{
|
||||
error = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int base = 10;
|
||||
int exponent = 0;
|
||||
int exponents_per_digit = 1;
|
||||
|
||||
// check whether we have base 16 value -- (0x[xdigit] || 0x.[xdigit])
|
||||
if (strncasecmp(str, "0x", 2) == 0 && (isxdigit(str[2]) || (str[2] == '.' && isxdigit(str[3]))))
|
||||
{
|
||||
base = 16;
|
||||
exponents_per_digit = 4;
|
||||
str += 2;
|
||||
}
|
||||
|
||||
// parse whole part
|
||||
T result = 0;
|
||||
T multiplier = 1;
|
||||
while (true)
|
||||
{
|
||||
int digit = get_base_digit(*str, base);
|
||||
if (digit == -1)
|
||||
break;
|
||||
str++;
|
||||
|
||||
if (result)
|
||||
exponent += exponents_per_digit;
|
||||
if (digit)
|
||||
result += multiplier * digit;
|
||||
if (result)
|
||||
multiplier /= base;
|
||||
}
|
||||
|
||||
if (*str == '.')
|
||||
str++;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int digit = get_base_digit(*str, base);
|
||||
if (digit == -1)
|
||||
break;
|
||||
str++;
|
||||
|
||||
if (result == 0)
|
||||
exponent -= exponents_per_digit;
|
||||
if (digit)
|
||||
result += multiplier * digit;
|
||||
if (result)
|
||||
multiplier /= base;
|
||||
}
|
||||
|
||||
if (tolower(*str) == (base == 10 ? 'e' : 'p'))
|
||||
{
|
||||
char* maybe_end = nullptr;
|
||||
int exp_error = 0;
|
||||
|
||||
int extra_exponent = strtoT<int>(str + 1, &maybe_end, 10, exp_error);
|
||||
if (exp_error != EINVAL)
|
||||
{
|
||||
if (exp_error == ERANGE || will_addition_overflow(exponent, extra_exponent))
|
||||
exponent = negative ? BAN::numeric_limits<int>::min() : BAN::numeric_limits<int>::max();
|
||||
else
|
||||
exponent += extra_exponent;
|
||||
str = maybe_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (endp)
|
||||
*endp = const_cast<char*>(str);
|
||||
|
||||
// no over/underflow can happed with zero
|
||||
if (result == 0)
|
||||
return 0;
|
||||
|
||||
const int max_exponent = (base == 10) ? BAN::numeric_limits<T>::max_exponent10() : BAN::numeric_limits<T>::max_exponent2();
|
||||
if (exponent > max_exponent)
|
||||
{
|
||||
error = ERANGE;
|
||||
result = BAN::numeric_limits<T>::infinity();
|
||||
return negative ? -result : result;
|
||||
}
|
||||
|
||||
const int min_exponent = (base == 10) ? BAN::numeric_limits<T>::min_exponent10() : BAN::numeric_limits<T>::min_exponent2();
|
||||
if (exponent < min_exponent)
|
||||
{
|
||||
error = ERANGE;
|
||||
result = 0;
|
||||
return negative ? -result : result;
|
||||
}
|
||||
|
||||
if (exponent)
|
||||
result *= BAN::Math::pow<T>((base == 10) ? 10 : 2, exponent);
|
||||
return result;
|
||||
}
|
||||
|
||||
double atof(const char* str)
|
||||
{
|
||||
return strtod(str, nullptr);
|
||||
}
|
||||
|
||||
int atoi(const char* str)
|
||||
{
|
||||
return strtol(str, nullptr, 10);
|
||||
}
|
||||
|
||||
long atol(const char* str)
|
||||
{
|
||||
return strtol(str, nullptr, 10);
|
||||
}
|
||||
|
||||
long long atoll(const char* str)
|
||||
{
|
||||
return strtoll(str, nullptr, 10);
|
||||
}
|
||||
|
||||
float strtof(const char* __restrict str, char** __restrict endp)
|
||||
{
|
||||
return strtoT<float>(str, endp, errno);
|
||||
}
|
||||
|
||||
double strtod(const char* __restrict str, char** __restrict endp)
|
||||
{
|
||||
return strtoT<double>(str, endp, errno);
|
||||
}
|
||||
|
||||
long double strtold(const char* __restrict str, char** __restrict endp)
|
||||
{
|
||||
return strtoT<long double>(str, endp, errno);
|
||||
}
|
||||
|
||||
long strtol(const char* __restrict str, char** __restrict endp, int base)
|
||||
{
|
||||
return strtoT<long>(str, endp, base, errno);
|
||||
}
|
||||
|
||||
long long strtoll(const char* __restrict str, char** __restrict endp, int base)
|
||||
{
|
||||
return strtoT<long long>(str, endp, base, errno);
|
||||
}
|
||||
|
||||
unsigned long strtoul(const char* __restrict str, char** __restrict endp, int base)
|
||||
{
|
||||
return strtoT<unsigned long>(str, endp, base, errno);
|
||||
}
|
||||
|
||||
unsigned long long strtoull(const char* __restrict str, char** __restrict endp, int base)
|
||||
{
|
||||
return strtoT<unsigned long long>(str, endp, base, errno);
|
||||
}
|
||||
|
||||
char* getenv(const char* name)
|
||||
|
|
|
@ -448,6 +448,68 @@ BAN::Optional<int> execute_builtin(BAN::Vector<BAN::String>& args, int fd_in, in
|
|||
|
||||
return ret;
|
||||
}
|
||||
else if (args.front() == "test-strtox")
|
||||
{
|
||||
#define TEST(num, base) do { errno = 0; printf("strtol(\"" num "\", nullptr, " #base ") = %ld ", strtol(num, nullptr, base)); puts(errno ? strerrorname_np(errno) : ""); } while (false)
|
||||
TEST("0", 10);
|
||||
TEST("", 10);
|
||||
TEST("+", 10);
|
||||
TEST("123", 10);
|
||||
TEST("-123", 10);
|
||||
TEST("7fffffffffffffff", 10);
|
||||
TEST("7fffffffffffffff", 16);
|
||||
TEST("8000000000000000", 16);
|
||||
TEST("-8000000000000000", 16);
|
||||
TEST("-8000000000000001", 16);
|
||||
TEST("123", 0);
|
||||
TEST("0123", 0);
|
||||
TEST("0x123", 0);
|
||||
TEST("123", 1);
|
||||
TEST("hello", 10);
|
||||
TEST("hello", 36);
|
||||
#undef TEST
|
||||
#define TEST(num, base) do { errno = 0; printf("strtoul(\"" num "\", nullptr, " #base ") = %lu ", strtoul(num, nullptr, base)); puts(errno ? strerrorname_np(errno) : ""); } while (false)
|
||||
TEST("0", 10);
|
||||
TEST("123", 10);
|
||||
TEST("-123", 10);
|
||||
TEST("-1", 10);
|
||||
TEST("fffffffffffffff", 16);
|
||||
TEST("ffffffffffffffff", 16);
|
||||
TEST("10000000000000000", 16);
|
||||
#undef TEST
|
||||
#define TEST(num) do { errno = 0; printf("strtod(\"" num "\", nullptr) = %e ", strtod(num, nullptr)); puts(errno ? strerrorname_np(errno) : ""); } while (false)
|
||||
TEST("0");
|
||||
TEST(".1");
|
||||
TEST("1.");
|
||||
TEST("0x.1");
|
||||
TEST("0x1.");
|
||||
TEST("123");
|
||||
TEST("-123");
|
||||
TEST("0x123");
|
||||
TEST("123.456");
|
||||
TEST("-123.456");
|
||||
TEST("1.2e5");
|
||||
TEST("1.e5");
|
||||
TEST(".2e5");
|
||||
TEST("0x1.2p5");
|
||||
TEST("0x1.p5");
|
||||
TEST("0x.2p5");
|
||||
TEST("1e999");
|
||||
TEST("-1e999");
|
||||
TEST("1e308");
|
||||
TEST("1e-307");
|
||||
TEST("1e309");
|
||||
TEST("1e-308");
|
||||
TEST("0.00000000001e312");
|
||||
TEST("1000000000000e-312");
|
||||
TEST("0e999");
|
||||
TEST("0e-999");
|
||||
TEST("1237754.446f");
|
||||
TEST("inf");
|
||||
TEST("-inf");
|
||||
TEST("nan");
|
||||
#undef TEST
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
|
|
Loading…
Reference in New Issue