Compare commits
	
		
			No commits in common. "59abb5d344d46609edcf0016f4bfd70a90aa87b2" and "1f467580eed557e70d6857b9ba472c0b30f9fbb7" have entirely different histories.
		
	
	
		
			59abb5d344
			...
			1f467580ee
		
	
		|  | @ -1,156 +0,0 @@ | |||
| #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; | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -1,24 +0,0 @@ | |||
| #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,6 +19,7 @@ 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,8 +49,6 @@ 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,8 +10,6 @@ namespace Kernel | |||
| 	public: | ||||
| 		virtual ~FileSystem() {} | ||||
| 		virtual BAN::RefPtr<Inode> root_inode() = 0; | ||||
| 
 | ||||
| 		virtual dev_t dev() const = 0; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -46,8 +46,6 @@ 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>); | ||||
|  | @ -117,8 +115,6 @@ 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; | ||||
| 		virtual dev_t		rdev()		const override { return 0; } | ||||
| 		virtual dev_t		dev()		const override { return 0; } // TODO
 | ||||
| 		virtual dev_t		rdev()		const override { return 0; } // TODO
 | ||||
| 
 | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&); | ||||
|  |  | |||
|  | @ -17,9 +17,6 @@ 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,6 +9,7 @@ namespace Kernel::Input | |||
| 	class PS2Device : public CharacterDevice, public Interruptable | ||||
| 	{ | ||||
| 	public: | ||||
| 		PS2Device(PS2Controller&); | ||||
| 		virtual ~PS2Device() {} | ||||
| 
 | ||||
| 		virtual void send_initialize() = 0; | ||||
|  | @ -26,12 +27,9 @@ namespace Kernel::Input | |||
| 
 | ||||
| 		virtual void update() final override { m_controller.update_command_queue(); } | ||||
| 
 | ||||
| 	protected: | ||||
| 		PS2Device(PS2Controller&); | ||||
| 
 | ||||
| 	private: | ||||
| 		const dev_t m_rdev; | ||||
| 		const BAN::String m_name; | ||||
| 		const dev_t m_rdev; | ||||
| 		PS2Controller& m_controller; | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,17 +1,14 @@ | |||
| #include <kernel/Device/DebugDevice.h> | ||||
| #include <kernel/Device/DeviceNumbers.h> | ||||
| #include <kernel/FS/DevFS/FileSystem.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) | ||||
| 	{ | ||||
| 		static uint32_t minor = 0; | ||||
| 		auto* result = new DebugDevice(mode, uid, gid, makedev(DeviceNumber::Debug, minor++)); | ||||
| 		auto* result = new DebugDevice(mode, uid, gid, DevFileSystem::get().get_next_dev()); | ||||
| 		if (result == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		return BAN::RefPtr<DebugDevice>::adopt(result); | ||||
|  |  | |||
|  | @ -1,12 +1,10 @@ | |||
| #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 | ||||
| { | ||||
|  | @ -25,7 +23,7 @@ namespace Kernel | |||
| 			return BAN::Error::from_errno(ENOTSUP); | ||||
| 		auto* device_ptr = new FramebufferDevice( | ||||
| 			0660, 0, 900, | ||||
| 			makedev(DeviceNumber::Framebuffer, get_framebuffer_device_index()), | ||||
| 			DevFileSystem::get().get_next_dev(), | ||||
| 			g_boot_info.framebuffer.address, | ||||
| 			g_boot_info.framebuffer.width, | ||||
| 			g_boot_info.framebuffer.height, | ||||
|  | @ -41,7 +39,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{}", minor(rdev))) | ||||
| 		, m_name(BAN::String::formatted("fb{}", get_framebuffer_device_index())) | ||||
| 		, m_rdev(rdev) | ||||
| 		, m_video_memory_paddr(paddr) | ||||
| 		, m_width(width) | ||||
|  |  | |||
|  | @ -1,15 +1,12 @@ | |||
| #include <kernel/Device/DeviceNumbers.h> | ||||
| #include <kernel/Device/NullDevice.h> | ||||
| 
 | ||||
| #include <sys/sysmacros.h> | ||||
| #include <kernel/FS/DevFS/FileSystem.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::RefPtr<NullDevice>> NullDevice::create(mode_t mode, uid_t uid, gid_t gid) | ||||
| 	{ | ||||
| 		static uint32_t minor = 0; | ||||
| 		auto* result = new NullDevice(mode, uid, gid, makedev(DeviceNumber::Null, minor++)); | ||||
| 		auto* result = new NullDevice(mode, uid, gid, DevFileSystem::get().get_next_dev()); | ||||
| 		if (result == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		return BAN::RefPtr<NullDevice>::adopt(result); | ||||
|  |  | |||
|  | @ -1,15 +1,12 @@ | |||
| #include <kernel/Device/DeviceNumbers.h> | ||||
| #include <kernel/Device/ZeroDevice.h> | ||||
| 
 | ||||
| #include <sys/sysmacros.h> | ||||
| #include <kernel/FS/DevFS/FileSystem.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::RefPtr<ZeroDevice>> ZeroDevice::create(mode_t mode, uid_t uid, gid_t gid) | ||||
| 	{ | ||||
| 		static uint32_t minor = 0; | ||||
| 		auto* result = new ZeroDevice(mode, uid, gid, makedev(DeviceNumber::Zero, minor++)); | ||||
| 		auto* result = new ZeroDevice(mode, uid, gid, DevFileSystem::get().get_next_dev()); | ||||
| 		if (result == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		return BAN::RefPtr<ZeroDevice>::adopt(result); | ||||
|  |  | |||
|  | @ -122,9 +122,17 @@ 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 | ||||
| 	{ | ||||
| 		static BAN::Atomic<dev_t> next_dev = 0; | ||||
| 		LockGuard _(m_device_lock); | ||||
| 		static dev_t next_dev = 0; | ||||
| 		return next_dev++; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,18 +1,9 @@ | |||
| #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) | ||||
|  | @ -26,8 +17,7 @@ namespace Kernel | |||
| 	} | ||||
| 
 | ||||
| 	TmpFileSystem::TmpFileSystem(size_t max_pages) | ||||
| 		: m_rdev(get_next_rdev()) | ||||
| 		, m_max_pages(max_pages) | ||||
| 		: m_max_pages(max_pages) | ||||
| 	{ } | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> TmpFileSystem::initialize(mode_t mode, uid_t uid, gid_t gid) | ||||
|  |  | |||
|  | @ -41,11 +41,6 @@ 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,4 +1,3 @@ | |||
| #include <kernel/Device/DeviceNumbers.h> | ||||
| #include <kernel/FS/DevFS/FileSystem.h> | ||||
| #include <kernel/Input/PS2/Config.h> | ||||
| #include <kernel/Input/PS2/Device.h> | ||||
|  | @ -11,8 +10,8 @@ namespace Kernel::Input | |||
| 
 | ||||
| 	PS2Device::PS2Device(PS2Controller& controller) | ||||
| 		: CharacterDevice(0440, 0, 901) | ||||
| 		, m_rdev(makedev(DeviceNumber::Input, DevFileSystem::get().get_next_input_device())) | ||||
| 		, m_name(BAN::String::formatted("input{}", minor(m_rdev))) | ||||
| 		, m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device())) | ||||
| 		, m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0)) | ||||
| 		, m_controller(controller) | ||||
| 	{ } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| #include <BAN/Endianness.h> | ||||
| #include <kernel/Device/DeviceNumbers.h> | ||||
| #include <kernel/FS/DevFS/FileSystem.h> | ||||
| #include <kernel/Networking/NetworkInterface.h> | ||||
| 
 | ||||
|  | @ -9,6 +8,12 @@ | |||
| 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; | ||||
|  | @ -18,7 +23,7 @@ namespace Kernel | |||
| 	NetworkInterface::NetworkInterface() | ||||
| 		: CharacterDevice(0400, 0, 0) | ||||
| 		, m_type(Type::Ethernet) | ||||
| 		, m_rdev(makedev(DeviceNumber::Ethernet, get_network_rdev_minor())) | ||||
| 		, m_rdev(makedev(get_network_rdev_major(), get_network_rdev_minor())) | ||||
| 	{ | ||||
| 		ASSERT(minor(m_rdev) < 10); | ||||
| 		ASSERT(m_type == Type::Ethernet); | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| #include <kernel/CPUID.h> | ||||
| #include <kernel/Debug.h> | ||||
| #include <kernel/CPUID.h> | ||||
| #include <kernel/Random.h> | ||||
| #include <kernel/Timer/Timer.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
|  | @ -19,16 +18,9 @@ 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 | ||||
| 		{ | ||||
| 			auto rt = SystemTimer::get().real_time(); | ||||
| 			s_rand_seed ^= rt.tv_sec ^ rt.tv_nsec; | ||||
| 			dprintln("RNG seeded by real time"); | ||||
| 		} | ||||
| 			dprintln("No RDRAND available"); | ||||
| 	} | ||||
| 
 | ||||
| 	uint32_t Random::get_u32() | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| #include <kernel/Device/DeviceNumbers.h> | ||||
| #include <kernel/FS/DevFS/FileSystem.h> | ||||
| #include <kernel/IO.h> | ||||
| #include <kernel/Storage/ATA/ATABus.h> | ||||
|  | @ -10,6 +9,12 @@ | |||
| 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; | ||||
|  | @ -17,7 +22,7 @@ namespace Kernel | |||
| 	} | ||||
| 
 | ||||
| 	detail::ATABaseDevice::ATABaseDevice() | ||||
| 		: m_rdev(makedev(DeviceNumber::SCSI, get_ata_dev_minor())) | ||||
| 		: m_rdev(makedev(get_ata_dev_major(), get_ata_dev_minor())) | ||||
| 	{ | ||||
| 		strcpy(m_name, "sda"); | ||||
| 		m_name[2] += minor(m_rdev); | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| #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> | ||||
|  | @ -12,6 +11,12 @@ | |||
| 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; | ||||
|  | @ -31,7 +36,7 @@ namespace Kernel | |||
| 	NVMeController::NVMeController(PCI::Device& pci_device) | ||||
| 		: CharacterDevice(0600, 0, 0) | ||||
| 		, m_pci_device(pci_device) | ||||
| 		, m_rdev(makedev(DeviceNumber::NVMeController, get_ctrl_dev_minor())) | ||||
| 		, m_rdev(makedev(get_ctrl_dev_major(), get_ctrl_dev_minor())) | ||||
| 	{ | ||||
| 		ASSERT(minor(m_rdev) < 10); | ||||
| 		strcpy(m_name, "nvmeX"); | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| #include <kernel/Device/DeviceNumbers.h> | ||||
| #include <kernel/FS/DevFS/FileSystem.h> | ||||
| #include <kernel/Storage/NVMe/Controller.h> | ||||
| #include <kernel/Storage/NVMe/Namespace.h> | ||||
|  | @ -8,6 +7,12 @@ | |||
| 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; | ||||
|  | @ -29,7 +34,7 @@ namespace Kernel | |||
| 		, m_nsid(nsid) | ||||
| 		, m_block_size(block_size) | ||||
| 		, m_block_count(block_count) | ||||
| 		, m_rdev(makedev(DeviceNumber::NVMeNamespace, get_ns_dev_minor())) | ||||
| 		, m_rdev(makedev(get_ns_dev_major(), 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 (first_block + block_count > blocks_in_partition) | ||||
| 		if (m_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,6 +1,5 @@ | |||
| #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> | ||||
|  | @ -43,8 +42,9 @@ namespace Kernel | |||
| 
 | ||||
| 	static dev_t next_rdev() | ||||
| 	{ | ||||
| 		static dev_t major = DevFileSystem::get().get_next_dev(); | ||||
| 		static dev_t minor = 0; | ||||
| 		return makedev(DeviceNumber::Serial, minor++); | ||||
| 		return makedev(major, minor++); | ||||
| 	} | ||||
| 
 | ||||
| 	void Serial::initialize() | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ | |||
| #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> | ||||
|  | @ -27,8 +26,9 @@ namespace Kernel | |||
| 
 | ||||
| 	static dev_t next_rdev() | ||||
| 	{ | ||||
| 		static dev_t major = DevFileSystem::get().get_next_dev(); | ||||
| 		static dev_t minor = 0; | ||||
| 		return makedev(DeviceNumber::TTY, minor++); | ||||
| 		return makedev(major, 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 = static_cast<const ACPI::HPET*>(ACPI::get().get_header("HPET"sv, 0)); | ||||
| 		auto* header = (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 and reset main counter
 | ||||
| 		// Disable main counter and reset value
 | ||||
| 		regs.configuration.low = regs.configuration.low & ~ENABLE_CNF; | ||||
| 		regs.main_counter.high = 0; | ||||
| 		regs.main_counter.low = 0; | ||||
|  | @ -244,28 +244,27 @@ namespace Kernel | |||
| 		if (m_is_64bit) | ||||
| 			return regs.main_counter.full; | ||||
| 
 | ||||
| 		CriticalScope _; | ||||
| 		uint32_t current_low = regs.main_counter.low; | ||||
| 		uint32_t wraps = m_32bit_wraps; | ||||
| 		if (current_low < (uint32_t)m_last_ticks) | ||||
| 		uint32_t current = regs.main_counter.low; | ||||
| 		uint64_t wraps = m_32bit_wraps; | ||||
| 		if (current < (uint32_t)m_last_ticks) | ||||
| 			wraps++; | ||||
| 		return ((uint64_t)wraps << 32) | current_low; | ||||
| 		return (wraps << 32) | current; | ||||
| 	} | ||||
| 
 | ||||
| 	void HPET::handle_irq() | ||||
| 	{ | ||||
| 		auto& regs = registers(); | ||||
| 
 | ||||
| 		uint64_t current_ticks; | ||||
| 		uint64_t current_ticks { 0 }; | ||||
| 
 | ||||
| 		if (m_is_64bit) | ||||
| 			current_ticks = regs.main_counter.full; | ||||
| 		else | ||||
| 		{ | ||||
| 			uint32_t current_low = regs.main_counter.low; | ||||
| 			if (current_low < (uint32_t)m_last_ticks) | ||||
| 			uint32_t current = regs.main_counter.low; | ||||
| 			if (current < (uint32_t)m_last_ticks) | ||||
| 				m_32bit_wraps++; | ||||
| 			current_ticks = ((uint64_t)m_32bit_wraps << 32) | current_low; | ||||
| 			current_ticks = ((uint64_t)m_32bit_wraps << 32) | current; | ||||
| 		} | ||||
| 
 | ||||
| 		m_last_ticks = current_ticks; | ||||
|  | @ -275,8 +274,7 @@ namespace Kernel | |||
| 
 | ||||
| 	uint64_t HPET::ms_since_boot() const | ||||
| 	{ | ||||
| 		auto current = time_since_boot(); | ||||
| 		return current.tv_sec * 1'000 + current.tv_nsec / 1'000'000; | ||||
| 		return ns_since_boot() / 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		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_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_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_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_IFMT		S_IFMASK | ||||
| 
 | ||||
| #define S_ISBLK(mode)	((mode & S_IFMASK) == S_IFBLK) | ||||
|  |  | |||
|  | @ -122,6 +122,17 @@ 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; | ||||
|  | @ -139,11 +150,6 @@ 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"); | ||||
|  | @ -217,17 +223,6 @@ 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 (strspn(mode_str + 1, "b+") != len - 1) | ||||
| 	if (strcspn(mode_str + 1, "b+") != len - 1) | ||||
| 		return 0; | ||||
| 	bool plus = (mode_str[1] == '+' || mode_str[2] == '+'); | ||||
| 	switch (mode_str[0]) | ||||
|  |  | |||
							
								
								
									
										337
									
								
								libc/stdlib.cpp
								
								
								
								
							
							
						
						
									
										337
									
								
								libc/stdlib.cpp
								
								
								
								
							|  | @ -1,12 +1,10 @@ | |||
| #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 <strings.h> | ||||
| #include <sys/syscall.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include <icxxabi.h> | ||||
|  | @ -52,329 +50,24 @@ int atexit(void (*func)(void)) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 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++; | ||||
| 
 | ||||
| 	// determine base from prefix
 | ||||
| 	if (base == 0) | ||||
| 	{ | ||||
| 		if (strncasecmp(str, "0x", 2) == 0) | ||||
| 			base = 16; | ||||
| 		else if (*str == '0') | ||||
| 			base = 8; | ||||
| 		else if (isdigit(*str)) | ||||
| 			base = 10; | ||||
| 	} | ||||
| 
 | ||||
| 	// 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); | ||||
| 	while (isspace(*str)) | ||||
| 		str++; | ||||
| 
 | ||||
| 	bool negative = (*str == '-'); | ||||
| 
 | ||||
| 	if (*str == '-' || *str == '+') | ||||
| 		str++; | ||||
| 
 | ||||
| 	int res = 0; | ||||
| 	while (isdigit(*str)) | ||||
| 	{ | ||||
| 		res = (res * 10) + (*str - '0'); | ||||
| 		str++; | ||||
| 	} | ||||
| 
 | ||||
| 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); | ||||
| 	return negative ? -res : res; | ||||
| } | ||||
| 
 | ||||
| char* getenv(const char* name) | ||||
|  |  | |||
|  | @ -448,68 +448,6 @@ 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