diff options
101 files changed, 845 insertions, 3270 deletions
@@ -1 +1,3 @@ -tree.txt
\ No newline at end of file +tree.txt +build/ +fs.img
\ No newline at end of file @@ -1,21 +1,338 @@ -MIT License
-
-Copyright (c) 2025 Richard Qin
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
\ No newline at end of file + GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Moe Ghoul>, 1 April 1989
+ Moe Ghoul, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
@@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + TOOLCHAIN_PREFIX := riscv64-linux-gnu- CC := $(TOOLCHAIN_PREFIX)gcc CXX := $(TOOLCHAIN_PREFIX)g++ @@ -1,136 +1,140 @@ -# Lume Operating System - -**Lume** is an experimental operating system kernel built from scratch for the **RISC-V 64** architecture. This project aims to explore the core implementation details of a modern Unix-like operating system. - -## 🚀 Current Status - -The project is currently deep in **Phase 2: Memory & Process Management**. - -The kernel has successfully transitioned from the bootloader to supervisor mode, enabled Sv39 virtual memory paging, and supports the execution of the first user-space process (`initcode`). It features basic process lifecycle management (creation, execution, termination, and reclamation). - -### ✅ Key Features Implemented - -* **Architecture Support** - * **Target**: RISC-V 64-bit (Sv39). - * **Modes**: Supervisor Mode (S-Mode) and User Mode (U-Mode). - * **Boot Flow**: OpenSBI -> Kernel Entry -> Main. - -* **Memory Management** - * **PMM (Physical Memory Management)**: Page frame allocator based on a free-list structure. - * **VM (Virtual Memory)**: Full Sv39 multi-level page table mapping. - * **Address Space**: - * **Kernel**: Higher-half mapping (Direct Mapping) + Trampoline. - * **User**: Independent page tables per process, containing code, data, stack, and trap pages. - * **Isolation**: `Trampoline` page mechanism for safe Kernel/User transitions. - -* **Process & Scheduling** - * **Process Model**: `struct Proc` (PCB) managing independent kernel stacks and trap frames. - * **Scheduling**: Preemptive Round-Robin scheduler driven by hardware timer interrupts. - * **Context Switching**: Assembly-level `swtch` logic to save/restore callee-saved registers. - * **Synchronization**: Spinlocks for protecting critical kernel data structures. - -* **System Calls** - A syscall dispatch framework (`ecall`) is established, currently supporting: - * `SYS_fork`: Create a child process (deep copy of memory and page tables). - * `SYS_exit`: Terminate the current process. - * `SYS_wait`: Wait for a child process to exit and reap resources. - * `SYS_write`: Write output to the console (currently direct via UART). - * `SYS_getpid`: Retrieve the current process ID. - * `SYS_putc`: Character output for debugging. - -* **Drivers** - * **UART**: Basic initialization and polled I/O for kernel logging. - -## 📂 Project Structure - -```text -Lume/ -├── src/ -│ ├── boot/ # Bootloader code (entry.S) -│ ├── kernel/ # Core kernel subsystems -│ │ ├── mm/ # Memory Management (pmm.cc, vm.cc) -│ │ ├── proc/ # Process Management (proc.cc, swtch.S) -│ │ ├── trap/ # Interrupt & Exception handling (trap.S, trampoline.S) -│ │ ├── syscall.cc # System call dispatcher -│ │ ├── main.cc # Kernel entry point -│ │ └── ... -│ ├── user/ # User-space programs (init.cc, usys.S) -│ ├── drivers/ # Hardware drivers (uart.cc) -│ └── lib/ # Kernel utility libraries (string.cc) -├── include/ # Header files -├── Makefile # Build configuration -└── link.ld # Kernel linker script -``` +# Lume OS +**A Lightweight, Educational RISC-V Operating System** +> Luminescence in the Deep Night -## 🛠️ Build & Run -This project relies on the GCC RISC-V toolchain and QEMU emulator. +Lume OS is a 64-bit monolithic operating system kernel written in C++ for the RISC-V architecture. Currently designed for educational purposes and kernel hacking, the project is now evolving towards a Tiny Linux-Compatible Kernel capable of running standard Linux userspace binaries (musl libc, BusyBox, etc.) by implementing the Linux Syscall ABI. -### Prerequisites -Compiler: riscv64-linux-gnu-gcc / g++ +## 🛠 Build & Run -Emulator: qemu-system-riscv64 +### Prerequisites +* Toolchain: `riscv64-linux-gnu-g++` / `gcc` -Build Tool: make +* Emulator: `qemu-system-riscv64` -### Commands -1. **Compile Kernel & User Programs:** +* Build System: `make` +### Compiling ```Bash +# Compile kernel and user programs make all ``` -2. **Run in QEMU (No Graphic Mode):** +### Running in QEMU ```Bash +# Run the OS make run -``` -Expected Output: You will see kernel boot logs, page table initialization, and output from the first user process (`initcode`). -3. **Debug Mode (GDB):** - -```Bash +# Debug mode (attaches GDB) make debug ``` -This starts QEMU in a paused state, waiting for a GDB connection on port 1234. -4. **Clean Build Artifacts:** +## 🏗 System Architecture & Current Features +Based on the current source tree, Lume OS implements the following core subsystems: -```Bash -make clean -``` +### 1. Kernel Core & Hardware Abstraction +* Architecture: RISC-V 64-bit (Sv39 paging) targeting QEMU `virt` machine. + +* Boot: Device Tree (FDT) parsing for hardware discovery. + +* Concurrency: SMP (Symmetric Multi-Processing) support with per-CPU state management. + +* Traps: Supervisor-mode interrupt and exception handling. + +### 2. Memory Management +* Physical Memory: Buddy System allocator for page-level management. + +* Kernel Heap: SLAB allocator (`kmalloc`/`kfree`) for efficient object management. + +* Virtual Memory: Basic paging support. Current user process memory model is linear (heap grows contiguously via `sbrk`). + +### 3. Process Management +* Scheduling: Round-Robin scheduler with per-CPU runqueues and work stealing mechanisms. + +* Context Switching: Saves callee-saved registers; currently lacks FPU/Vector state saving. -## 🗺️ Roadmap -* [x] Phase 1: Foundation +* Lifecycle: Basic `fork`, `exec`, `exit`, and `wait` system calls. - [x] UART Driver & Formatted Output. +### 4. File System & I/O +* VFS: A preliminary Virtual File System abstraction with `inode` polymorphism. - [x] Physical Memory Allocator (PMM). +* Filesystem: FAT32 implementation with basic read/write/create/delete support. - [x] Basic Interrupt Handling Framework. +* Buffer Cache: Block-level caching (Bio) coupled with the VirtIO driver. -* [x] Phase 2: Memory & Process (In Progress) +* Drivers: - [x] Virtual Memory (Sv39) & Kernel Page Tables. + * VirtIO: Block device driver (MMIO). - [x] User Address Space Construction. + * UART: 16550A-compatible serial console driver with line buffering. - [x] Preemptive Scheduler. + * PLIC: Platform-Level Interrupt Controller support. - [x] Basic System Calls (fork, exit, wait, write). +### 5. User Space +* Libc: A minimal custom C library (`ulib`) providing stdio (`printf`/`scanf`), stdlib (`malloc`/`free`), and string operations. - [ ] exec System Call (ELF Loader). +* Shell: A functional shell (`sh`) supporting pipes (`|`), redirection (`<`, `>`), and background execution (`&`). - [ ] sbrk for Dynamic Heap Growth. +* Utils: Standard Unix-like tools: `ls`, `cat`, `echo`, `mkdir`, `rm`, `touch`, `cp`, `mv`. -* [ ] Phase 3: File System & I/O (Planned) +## 📉 Gap Analysis: Lume OS vs. Linux +To achieve the goal of binary compatibility with the Linux ecosystem, Lume OS is currently undergoing a major refactoring. The following table highlights the critical differences: - [ ] VirtIO Block Device Driver. +|Subsystem|Lume OS (Current)|Linux / Modern Goal|Gap & Impact| +|:------:|:---------:|:--------:|:---------:| +|Syscall ABI|Custom IDs & `-1` return codes|Standard RISC-V headers & `-errno`|Binaries compiled for Linux cannot run on Lume.| +|Memory Model|Linear `p->sz` (Heap only)|VMA (Virtual Memory Areas)|Cannot support `mmap`, memory gaps, or dynamic libraries (`.so`).| +|Binary Format|Static ELF only|Dynamic ELF (`PT_INTERP`)|Cannot run `ld.so` or shared libraries; high memory waste.| +|Threading|Single-threaded Processes|1:1 Threads (`clone` + NPTL)|Cannot support `pthreads` or modern concurrent apps.| +|Filesystem|Tightly coupled FAT32|VFS + Mount Points + Pseudo FS|Missing `/dev`, `/proc`, `/sys`; standard tools (`top`, `ps`) fail.| +|Signals|Basic `kill` flag|Full Signal Handling|No `Ctrl-C` handling, `SIGSEGV` recovery, or async notifications.| +|I/O Model|Synchronous/Blocking|Async/Non-blocking (`poll`/`epoll`)|Cannot support high-performance servers (e.g., Nginx).| - [ ] Virtual File System (VFS). +## 🗺️ Roadmap to Linux Compatibility +We are executing a 4-phase plan to transform Lume OS into a Tiny Linux Clone. - [ ] File I/O System Calls (open, read, close). -* [ ] Phase 4: Waiting for you... +### Phase 1: Core Architecture Refactoring (The Foundation) +* [ ] VMA Implementation: Replace `sz` with `vm_area_struct` (RB-Tree/List) to support mmap and demand paging. + +* [ ] VFS 2.0: Decouple FAT32. Implement `struct mount`, `dentry` cache, and `RamFS`. + +* [ ] DevFS & ProcFS: Implement `/dev` and `/proc` mounting support. + +* [ ] Syscall Alignment: Renumber syscalls to match Linux RISC-V 64 ABI and standardize errno. + +### Phase 2: Runtime Environment +* [ ] ELF Interpreter: Support `PT_INTERP` to load dynamic linkers (`ld-musl-riscv64.so.1`). + +* [ ] Auxiliary Vector: Construct `AT_RANDOM`, `AT_PHDR`, etc., on the user stack. + +* [ ] New Syscalls: `brk`, `writev`, `readv`, `ioctl` (TTY), `getdents64`. + +### Phase 3: Advanced Process Features +* [ ] Threading: Implement `sys_clone` with `CLONE_VM` / `CLONE_THREAD`. + +* [ ] Synchronization: Implement `sys_futex` for userspace locking. + +* [ ] Signals: Implement `sigaction`, signal frame construction, and `sigreturn` trampoline. + +### Phase 4: Ecosystem & Networking +* [ ] Network Stack: Port lwIP and implement `virtio-net` driver. + +* [ ] Socket API: Implement `socket`, `bind`, `connect`, `poll`. + +* [ ] Userland: Port Musl Libc and BusyBox. ## 📄 License -This project is open-source under the MIT License. See the LICENSE file for details. ------------- -Copyright (c) 2025 Richard Qin
\ No newline at end of file + +Lume OS is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +Lume OS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. + +See the [LICENSE](LICENSE) file for details.
\ No newline at end of file diff --git a/include/common/fcntl.h b/include/common/fcntl.h index 24d40fa..6059538 100644 --- a/include/common/fcntl.h +++ b/include/common/fcntl.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #define O_RDONLY 0x000 diff --git a/include/common/types.h b/include/common/types.h index 8924699..aa2cb08 100644 --- a/include/common/types.h +++ b/include/common/types.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once typedef unsigned char uint8_t; diff --git a/include/drivers/plic.h b/include/drivers/plic.h index 11e8c8a..cdcd0ce 100644 --- a/include/drivers/plic.h +++ b/include/drivers/plic.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/drivers/uart.h b/include/drivers/uart.h index 85b04b0..1cdc938 100644 --- a/include/drivers/uart.h +++ b/include/drivers/uart.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "drivers/uart_color.h" diff --git a/include/drivers/uart_color.h b/include/drivers/uart_color.h index a63d57a..7ecc28b 100644 --- a/include/drivers/uart_color.h +++ b/include/drivers/uart_color.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + // ANSI Escape Codes for Modern Terminal Colors #define ANSI_RESET "\033[0m" #define ANSI_RED "\033[31m" diff --git a/include/drivers/virtio.h b/include/drivers/virtio.h index ea2c9a6..9fda8cf 100644 --- a/include/drivers/virtio.h +++ b/include/drivers/virtio.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/fs/fat32.h b/include/fs/fat32.h index 1bd60ef..63d62ae 100644 --- a/include/fs/fat32.h +++ b/include/fs/fat32.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "fs/fs.h" #include "kernel/buf.h" diff --git a/include/fs/file.h b/include/fs/file.h index a92d8f8..9aff1af 100644 --- a/include/fs/file.h +++ b/include/fs/file.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "fs/fs.h" diff --git a/include/fs/fs.h b/include/fs/fs.h index 235ec80..967858b 100644 --- a/include/fs/fs.h +++ b/include/fs/fs.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "kernel/spinlock.h" diff --git a/include/fs/stat.h b/include/fs/stat.h index cdce05a..e60ae42 100644 --- a/include/fs/stat.h +++ b/include/fs/stat.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/kernel/buf.h b/include/kernel/buf.h index 099523d..d0d849c 100644 --- a/include/kernel/buf.h +++ b/include/kernel/buf.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "kernel/spinlock.h" diff --git a/include/kernel/config.h b/include/kernel/config.h index 56a1aa6..45d85cd 100644 --- a/include/kernel/config.h +++ b/include/kernel/config.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/kernel/cpu.h b/include/kernel/cpu.h index 92890b6..62bdc17 100644 --- a/include/kernel/cpu.h +++ b/include/kernel/cpu.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "kernel/proc_def.h" diff --git a/include/kernel/elf.h b/include/kernel/elf.h index c216f1c..30193d2 100644 --- a/include/kernel/elf.h +++ b/include/kernel/elf.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/kernel/exec.h b/include/kernel/exec.h index 964e3bb..304e03f 100644 --- a/include/kernel/exec.h +++ b/include/kernel/exec.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once namespace Exec diff --git a/include/kernel/mm.h b/include/kernel/mm.h index 3b59edb..e3de09a 100644 --- a/include/kernel/mm.h +++ b/include/kernel/mm.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/kernel/pmm.h b/include/kernel/pmm.h index d31473f..1fc3070 100644 --- a/include/kernel/pmm.h +++ b/include/kernel/pmm.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "kernel/spinlock.h" diff --git a/include/kernel/proc.h b/include/kernel/proc.h index c740d53..e11dc47 100644 --- a/include/kernel/proc.h +++ b/include/kernel/proc.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "kernel/proc_def.h" diff --git a/include/kernel/proc_def.h b/include/kernel/proc_def.h index c671f8d..50f27d7 100644 --- a/include/kernel/proc_def.h +++ b/include/kernel/proc_def.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "common/fcntl.h" diff --git a/include/kernel/runqueue.h b/include/kernel/runqueue.h index ea6e4cc..14704ce 100644 --- a/include/kernel/runqueue.h +++ b/include/kernel/runqueue.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "kernel/spinlock.h" #include "kernel/proc_def.h" diff --git a/include/kernel/sbi.h b/include/kernel/sbi.h index ec262ee..a6be5b3 100644 --- a/include/kernel/sbi.h +++ b/include/kernel/sbi.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/kernel/slab.h b/include/kernel/slab.h index 650f8a9..bb7b699 100644 --- a/include/kernel/slab.h +++ b/include/kernel/slab.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/kernel/spinlock.h b/include/kernel/spinlock.h index 3102e68..1511199 100644 --- a/include/kernel/spinlock.h +++ b/include/kernel/spinlock.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/kernel/sync.h b/include/kernel/sync.h index 83d88c8..7f7c208 100644 --- a/include/kernel/sync.h +++ b/include/kernel/sync.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" #include "kernel/spinlock.h" diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index 348fd63..af4c474 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn +*/ + #pragma once #define SYS_putc 1 diff --git a/include/kernel/timer.h b/include/kernel/timer.h index 193c47d..8b97bbe 100644 --- a/include/kernel/timer.h +++ b/include/kernel/timer.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #include "common/types.h" namespace Timer{ diff --git a/include/kernel/trap.h b/include/kernel/trap.h index 35b225c..ddc1d12 100644 --- a/include/kernel/trap.h +++ b/include/kernel/trap.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/lib/string.h b/include/lib/string.h index 309bf02..6a74942 100644 --- a/include/lib/string.h +++ b/include/lib/string.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #pragma once #include "common/types.h" diff --git a/include/ulib/assert.h b/include/ulib/assert.h index a083aff..014be9b 100644 --- a/include/ulib/assert.h +++ b/include/ulib/assert.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #ifndef _ASSERT_H #define _ASSERT_H diff --git a/include/ulib/cstdlib b/include/ulib/cstdlib index 69b9bb6..8b07338 100644 --- a/include/ulib/cstdlib +++ b/include/ulib/cstdlib @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #ifndef _CPP_CSTDLIB #define _CPP_CSTDLIB diff --git a/include/ulib/cstring b/include/ulib/cstring index bb8ab44..d65dc8d 100644 --- a/include/ulib/cstring +++ b/include/ulib/cstring @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #ifndef _CPP_CSTRING #define _CPP_CSTRING diff --git a/include/ulib/ctypes.h b/include/ulib/ctypes.h index 3e0bc22..1ec204e 100644 --- a/include/ulib/ctypes.h +++ b/include/ulib/ctypes.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #ifndef _CTYPE_H #define _CTYPE_H diff --git a/include/ulib/cxx.cc b/include/ulib/cxx.cc index d24de1e..f454fea 100644 --- a/include/ulib/cxx.cc +++ b/include/ulib/cxx.cc @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #include "ulib/stdlib.h" diff --git a/include/ulib/errno.h b/include/ulib/errno.h index 03ff8fd..19da4d1 100644 --- a/include/ulib/errno.h +++ b/include/ulib/errno.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #ifndef _ERRNO_H #define _ERRNO_H diff --git a/include/ulib/iostream b/include/ulib/iostream index 83ed74c..b05f603 100644 --- a/include/ulib/iostream +++ b/include/ulib/iostream @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #ifndef _IOSTREAM #define _IOSTREAM diff --git a/include/ulib/limits.h b/include/ulib/limits.h index 030ffbb..b317e6a 100644 --- a/include/ulib/limits.h +++ b/include/ulib/limits.h @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #pragma once #define CHAR_BIT 8 diff --git a/include/ulib/stdio.h b/include/ulib/stdio.h index 2e19b87..a6df21d 100644 --- a/include/ulib/stdio.h +++ b/include/ulib/stdio.h @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ /* Standard I/O Library for Lume OS */ #ifndef _STDIO_H diff --git a/include/ulib/stdlib.h b/include/ulib/stdlib.h index 7dc325e..6d8f75d 100644 --- a/include/ulib/stdlib.h +++ b/include/ulib/stdlib.h @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ + #ifndef _STDLIB_H #define _STDLIB_H diff --git a/include/ulib/string.h b/include/ulib/string.h index 6e87157..c7519ea 100644 --- a/include/ulib/string.h +++ b/include/ulib/string.h @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #ifndef _STRING_H #define _STRING_H diff --git a/include/ulib/types.h b/include/ulib/types.h index 2f15bf1..69ee233 100644 --- a/include/ulib/types.h +++ b/include/ulib/types.h @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #ifndef _ULIB_TYPES_H #define _ULIB_TYPES_H diff --git a/include/user/user.h b/include/user/user.h index 345f8be..0be036b 100644 --- a/include/user/user.h +++ b/include/user/user.h @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #pragma once typedef unsigned long long uint64; @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + OUTPUT_ARCH( "riscv" ) ENTRY( _start ) diff --git a/src/boot/entry.S b/src/boot/entry.S index 6d75bcf..8910ddc 100644 --- a/src/boot/entry.S +++ b/src/boot/entry.S @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + .section .text.entry .global _start diff --git a/src/drivers/plic.cc b/src/drivers/plic.cc index a759597..f9e306b 100644 --- a/src/drivers/plic.cc +++ b/src/drivers/plic.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" #include "kernel/riscv.h" #include "drivers/plic.h" diff --git a/src/drivers/uart.cc b/src/drivers/uart.cc index 55609ba..96ae182 100644 --- a/src/drivers/uart.cc +++ b/src/drivers/uart.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "drivers/uart.h" #include "kernel/riscv.h" #include "kernel/spinlock.h" diff --git a/src/drivers/virtio_dist.cc b/src/drivers/virtio_dist.cc index 9c981d4..b2acd8e 100644 --- a/src/drivers/virtio_dist.cc +++ b/src/drivers/virtio_dist.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "drivers/virtio.h" #include "kernel/riscv.h" #include "kernel/pmm.h" diff --git a/src/fs/fat32.cc b/src/fs/fat32.cc index 17b543c..e4089d4 100644 --- a/src/fs/fat32.cc +++ b/src/fs/fat32.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "fs/fat32.h" #include "lib/string.h" #include "drivers/uart.h" diff --git a/src/fs/file.cc b/src/fs/file.cc index 9f12dc1..d814332 100644 --- a/src/fs/file.cc +++ b/src/fs/file.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "fs/file.h" #include "kernel/spinlock.h" #include "kernel/mm.h" diff --git a/src/fs/fs.cc b/src/fs/fs.cc index 9e3d50e..b93f363 100644 --- a/src/fs/fs.cc +++ b/src/fs/fs.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "fs/fs.h" #include "kernel/riscv.h" #include "drivers/uart.h" diff --git a/src/kernel/bio.cc b/src/kernel/bio.cc index 6e63d60..5f1aae9 100644 --- a/src/kernel/bio.cc +++ b/src/kernel/bio.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "kernel/buf.h" #include "kernel/spinlock.h" #include "kernel/riscv.h" diff --git a/src/kernel/config.cc b/src/kernel/config.cc index 47f7a3e..36858a1 100644 --- a/src/kernel/config.cc +++ b/src/kernel/config.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" uint64 g_uart_base = 0; diff --git a/src/kernel/cxx.cc b/src/kernel/cxx.cc index 14bfe68..00f2799 100644 --- a/src/kernel/cxx.cc +++ b/src/kernel/cxx.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" #include "kernel/pmm.h" #include "drivers/uart.h" diff --git a/src/kernel/fdt.cc b/src/kernel/fdt.cc index 5334845..e9f8422 100644 --- a/src/kernel/fdt.cc +++ b/src/kernel/fdt.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" #include "drivers/uart.h" #include "kernel/config.h" diff --git a/src/kernel/initcode.S b/src/kernel/initcode.S index 8b56ce6..22e55ca 100644 --- a/src/kernel/initcode.S +++ b/src/kernel/initcode.S @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + .section .rodata .global initcode_start .global initcode_end diff --git a/src/kernel/main.cc b/src/kernel/main.cc index 9a24028..22cffd6 100644 --- a/src/kernel/main.cc +++ b/src/kernel/main.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" #include "kernel/riscv.h" #include "drivers/uart.h" diff --git a/src/kernel/mm/pmm.cc b/src/kernel/mm/pmm.cc index e871d8a..2d0c44f 100644 --- a/src/kernel/mm/pmm.cc +++ b/src/kernel/mm/pmm.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" #include "kernel/riscv.h" #include "kernel/pmm.h" diff --git a/src/kernel/mm/slab.cc b/src/kernel/mm/slab.cc index 702dc5c..3bb6b1b 100644 --- a/src/kernel/mm/slab.cc +++ b/src/kernel/mm/slab.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "kernel/slab.h" #include "kernel/pmm.h" #include "kernel/spinlock.h" diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc index 1155d2c..47b80e9 100644 --- a/src/kernel/mm/vm.cc +++ b/src/kernel/mm/vm.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "kernel/mm.h" #include "kernel/pmm.h" #include "kernel/riscv.h" diff --git a/src/kernel/proc/exec.cc b/src/kernel/proc/exec.cc index 22e4842..e5294d9 100644 --- a/src/kernel/proc/exec.cc +++ b/src/kernel/proc/exec.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" #include "kernel/riscv.h" #include "kernel/proc.h" diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc index 6940a3e..3923fe8 100644 --- a/src/kernel/proc/proc.cc +++ b/src/kernel/proc/proc.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "kernel/proc.h" #include "kernel/proc_def.h" #include "kernel/runqueue.h" diff --git a/src/kernel/proc/swtch.S b/src/kernel/proc/swtch.S index f59de20..d55c03e 100644 --- a/src/kernel/proc/swtch.S +++ b/src/kernel/proc/swtch.S @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + .global swtch swtch: diff --git a/src/kernel/sbi.cc b/src/kernel/sbi.cc index 9570d74..5ae7edb 100644 --- a/src/kernel/sbi.cc +++ b/src/kernel/sbi.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" #include "kernel/sbi.h" diff --git a/src/kernel/spinlock.cc b/src/kernel/spinlock.cc index 55dfc6b..aadce21 100644 --- a/src/kernel/spinlock.cc +++ b/src/kernel/spinlock.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "kernel/spinlock.h" #include "kernel/riscv.h" #include "kernel/cpu.h" diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc index 9f88649..b891ada 100644 --- a/src/kernel/syscall.cc +++ b/src/kernel/syscall.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "kernel/syscall.h" #include "common/types.h" #include "common/fcntl.h" diff --git a/src/kernel/timer.cc b/src/kernel/timer.cc index 3cbf11e..fc02f27 100644 --- a/src/kernel/timer.cc +++ b/src/kernel/timer.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "common/types.h" #include "kernel/config.h" #include "kernel/spinlock.h" diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc index 7e4d11e..11af409 100644 --- a/src/kernel/trap/handler.cc +++ b/src/kernel/trap/handler.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "kernel/trap.h" #include "kernel/riscv.h" #include "kernel/proc.h" diff --git a/src/kernel/trap/trampoline.S b/src/kernel/trap/trampoline.S index 478d345..57d6f25 100644 --- a/src/kernel/trap/trampoline.S +++ b/src/kernel/trap/trampoline.S @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + .section .text .globl trampoline .globl uservec diff --git a/src/kernel/trap/trap.S b/src/kernel/trap/trap.S index 573248e..8bce53d 100644 --- a/src/kernel/trap/trap.S +++ b/src/kernel/trap/trap.S @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + .section .text .global kernelvec .global uservec diff --git a/src/lib/string.cc b/src/lib/string.cc index a302fc6..e8eccb3 100644 --- a/src/lib/string.cc +++ b/src/lib/string.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "lib/string.h" void *memset(void *dst, int c, uint n) diff --git a/src/ulib/assert.c b/src/ulib/assert.c index ca2da84..c60643a 100644 --- a/src/ulib/assert.c +++ b/src/ulib/assert.c @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "stdio.h" #include "stdlib.h" diff --git a/src/ulib/cxx.cc b/src/ulib/cxx.cc index 6c892ab..d8f510d 100644 --- a/src/ulib/cxx.cc +++ b/src/ulib/cxx.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdlib.h" void *operator new(unsigned long n) diff --git a/src/ulib/iostream.cpp b/src/ulib/iostream.cpp index d5394f9..4d721c1 100644 --- a/src/ulib/iostream.cpp +++ b/src/ulib/iostream.cpp @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/iostream" namespace std diff --git a/src/ulib/stdio.c b/src/ulib/stdio.c index f8e7a9a..e81f69a 100644 --- a/src/ulib/stdio.c +++ b/src/ulib/stdio.c @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/string.h" #include "ulib/stdlib.h" diff --git a/src/ulib/stdlib.c b/src/ulib/stdlib.c index 89d5a08..8b22b6f 100644 --- a/src/ulib/stdlib.c +++ b/src/ulib/stdlib.c @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdlib.h" #include "ulib/string.h" #include "ulib/ctypes.h" diff --git a/src/ulib/string.c b/src/ulib/string.c index 5fc1cbd..c3dbe9a 100644 --- a/src/ulib/string.c +++ b/src/ulib/string.c @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/string.h" #include "ulib/stdlib.h" diff --git a/src/user/cat.cc b/src/user/cat.cc index 67feb1c..b518d77 100644 --- a/src/user/cat.cc +++ b/src/user/cat.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "ulib/string.h" diff --git a/src/user/cp.cc b/src/user/cp.cc index 9f13bef..ca35e82 100644 --- a/src/user/cp.cc +++ b/src/user/cp.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "user/user.h" diff --git a/src/user/echo.cc b/src/user/echo.cc index ff4b8be..cc9dc2a 100644 --- a/src/user/echo.cc +++ b/src/user/echo.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "user/user.h" #include "ulib/stdio.h" #include "ulib/string.h" diff --git a/src/user/entry.S b/src/user/entry.S index 432211c..41e0964 100644 --- a/src/user/entry.S +++ b/src/user/entry.S @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + .section .text .global _start diff --git a/src/user/grep.cc b/src/user/grep.cc index 5ed61b4..1e1c42d 100644 --- a/src/user/grep.cc +++ b/src/user/grep.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "ulib/string.h" diff --git a/src/user/init.cc b/src/user/init.cc index 07ed97e..f1a6e29 100644 --- a/src/user/init.cc +++ b/src/user/init.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "ulib/string.h" diff --git a/src/user/kill.cc b/src/user/kill.cc index 18b7f02..d38cdd6 100644 --- a/src/user/kill.cc +++ b/src/user/kill.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "user/user.h" diff --git a/src/user/ln.cc b/src/user/ln.cc index 2370fdc..a21ddf9 100644 --- a/src/user/ln.cc +++ b/src/user/ln.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "user/user.h" diff --git a/src/user/ls.cc b/src/user/ls.cc index e472578..c44c799 100644 --- a/src/user/ls.cc +++ b/src/user/ls.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "ulib/string.h" diff --git a/src/user/mkdir.cc b/src/user/mkdir.cc index 8219109..6da8b49 100644 --- a/src/user/mkdir.cc +++ b/src/user/mkdir.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "user/user.h" diff --git a/src/user/mv.cc b/src/user/mv.cc index 2d30f01..a196145 100644 --- a/src/user/mv.cc +++ b/src/user/mv.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "user/user.h" diff --git a/src/user/rm.cc b/src/user/rm.cc index 82b04c5..4777ade 100644 --- a/src/user/rm.cc +++ b/src/user/rm.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "user/user.h" diff --git a/src/user/sh.cc b/src/user/sh.cc index 760f29e..1bf9ebb 100644 --- a/src/user/sh.cc +++ b/src/user/sh.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "ulib/string.h" diff --git a/src/user/touch.cc b/src/user/touch.cc index b978f52..2f9f9f6 100644 --- a/src/user/touch.cc +++ b/src/user/touch.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "user/user.h" diff --git a/src/user/user.ld b/src/user/user.ld index 8c9999a..f0a4b27 100644 --- a/src/user/user.ld +++ b/src/user/user.ld @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + OUTPUT_ARCH( "riscv" ) ENTRY( _start ) diff --git a/src/user/usys.S b/src/user/usys.S index 56cbb22..885d45c 100644 --- a/src/user/usys.S +++ b/src/user/usys.S @@ -1,3 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + #include "kernel/syscall.h" #define SYSCALL(name) \ diff --git a/src/user/wc.cc b/src/user/wc.cc index 654aac2..fbe9735 100644 --- a/src/user/wc.cc +++ b/src/user/wc.cc @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Richard QIn + */ #include "ulib/stdio.h" #include "ulib/stdlib.h" #include "ulib/string.h" diff --git a/stdlib/stb_sprintf.h b/stdlib/stb_sprintf.h deleted file mode 100644 index ca432a6..0000000 --- a/stdlib/stb_sprintf.h +++ /dev/null @@ -1,1906 +0,0 @@ -// stb_sprintf - v1.10 - public domain snprintf() implementation -// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 -// http://github.com/nothings/stb -// -// allowed types: sc uidBboXx p AaGgEef n -// lengths : hh h ll j z t I64 I32 I -// -// Contributors: -// Fabian "ryg" Giesen (reformatting) -// github:aganm (attribute format) -// -// Contributors (bugfixes): -// github:d26435 -// github:trex78 -// github:account-login -// Jari Komppa (SI suffixes) -// Rohit Nirmal -// Marcin Wojdyr -// Leonard Ritter -// Stefano Zanotti -// Adam Allison -// Arvid Gerstmann -// Markus Kolb -// -// LICENSE: -// -// See end of file for license information. - -#ifndef STB_SPRINTF_H_INCLUDE -#define STB_SPRINTF_H_INCLUDE - -/* -Single file sprintf replacement. - -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. - -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. - -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. - -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. - -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. - -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. - -API: -==== -int stbsp_sprintf( char * buf, char const * fmt, ... ) -int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. stbsp_snprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) -int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every STB_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least STB_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting - -void stbsp_set_separators( char comma, char period ) - Set the comma and period characters to use. - -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. - -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). - -If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT -and you'll save 4K of code space. - -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. - -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. - -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn -2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three -$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the -suffix, add "_" specifier: "%_$d" -> "2.53M". - -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. - -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#if defined(__clang__) - #if defined(__has_feature) && defined(__has_attribute) - #if __has_feature(address_sanitizer) - #if __has_attribute(__no_sanitize__) - #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) - #elif __has_attribute(__no_sanitize_address__) - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #elif __has_attribute(__no_address_safety_analysis__) - #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) - #endif - #endif - #endif -#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #endif -#endif - -#ifndef STBSP__ASAN -#define STBSP__ASAN -#endif - -#ifdef STB_SPRINTF_STATIC -#define STBSP__PUBLICDEC static -#define STBSP__PUBLICDEF static STBSP__ASAN -#else -#ifdef __cplusplus -#define STBSP__PUBLICDEC extern "C" -#define STBSP__PUBLICDEF extern "C" STBSP__ASAN -#else -#define STBSP__PUBLICDEC extern -#define STBSP__PUBLICDEF STBSP__ASAN -#endif -#endif - -#if defined(__has_attribute) - #if __has_attribute(format) - #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) - #endif -#endif - -#ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) -#endif - -#ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) -#else -#define STBSP__NOTUSED(v) (void)sizeof(v) -#endif - -#include <stdarg.h> // for va_arg(), va_list() -#include <stddef.h> // size_t, ptrdiff_t - -#ifndef STB_SPRINTF_MIN -#define STB_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); - -#ifndef STB_SPRINTF_DECORATE -#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names -#endif - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); - -#endif // STB_SPRINTF_H_INCLUDE - -#ifdef STB_SPRINTF_IMPLEMENTATION - -#define stbsp__uint32 unsigned int -#define stbsp__int32 signed int - -#ifdef _MSC_VER -#define stbsp__uint64 unsigned __int64 -#define stbsp__int64 signed __int64 -#else -#define stbsp__uint64 unsigned long long -#define stbsp__int64 signed long long -#endif -#define stbsp__uint16 unsigned short - -#ifndef stbsp__uintptr -#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) -#define stbsp__uintptr stbsp__uint64 -#else -#define stbsp__uintptr stbsp__uint32 -#endif -#endif - -#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define STB_SPRINTF_MSVC_MODE -#endif -#endif - -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses -#define STBSP__UNALIGNED(code) -#else -#define STBSP__UNALIGNED(code) code -#endif - -#ifndef STB_SPRINTF_NOFLOAT -// internal float utility functions -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); -#define STBSP__SPECIAL 0x7000 -#endif - -static char stbsp__period = '.'; -static char stbsp__comma = ','; -static struct -{ - short temp; // force next field to be 2-byte aligned - char pair[201]; -} stbsp__digitpair = -{ - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899" -}; - -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) -{ - stbsp__period = pperiod; - stbsp__comma = pcomma; -} - -#define STBSP__LEFTJUST 1 -#define STBSP__LEADINGPLUS 2 -#define STBSP__LEADINGSPACE 4 -#define STBSP__LEADING_0X 8 -#define STBSP__LEADINGZERO 16 -#define STBSP__INTMAX 32 -#define STBSP__TRIPLET_COMMA 64 -#define STBSP__NEGATIVE 128 -#define STBSP__METRIC_SUFFIX 256 -#define STBSP__HALFWIDTH 512 -#define STBSP__METRIC_NOSPACE 1024 -#define STBSP__METRIC_1024 2048 -#define STBSP__METRIC_JEDEC 4096 - -static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) -{ - sign[0] = 0; - if (fl & STBSP__NEGATIVE) { - sign[0] = 1; - sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { - sign[0] = 1; - sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { - sign[0] = 1; - sign[1] = '+'; - } -} - -static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) -{ - char const * sn = s; - - // get up to 4-byte alignment - for (;;) { - if (((stbsp__uintptr)sn & 3) == 0) - break; - - if (!limit || *sn == 0) - return (stbsp__uint32)(sn - s); - - ++sn; - --limit; - } - - // scan over 4 bytes at a time to find terminating 0 - // this will intentionally scan up to 3 bytes past the end of buffers, - // but becase it works 4B aligned, it will never cross page boundaries - // (hence the STBSP__ASAN markup; the over-read here is intentional - // and harmless) - while (limit >= 4) { - stbsp__uint32 v = *(stbsp__uint32 *)sn; - // bit hack to find if there's a 0 byte in there - if ((v - 0x01010101) & (~v) & 0x80808080UL) - break; - - sn += 4; - limit -= 4; - } - - // handle the last few characters to find actual size - while (limit && *sn) { - ++sn; - --limit; - } - - return (stbsp__uint32)(sn - s); -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) -{ - static char hex[] = "0123456789abcdefxp"; - static char hexu[] = "0123456789ABCDEFXP"; - char *bf; - char const *f; - int tlen = 0; - - bf = buf; - f = fmt; - for (;;) { - stbsp__int32 fw, pr, tz; - stbsp__uint32 fl; - - // macros for the callback buffer stuff - #define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } - #define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } - #define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer - #define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } - - // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { - schk1: - if (f[0] == '%') - goto scandd; - schk2: - if (f[0] == 0) - goto endfmt; - stbsp__chk_cb_buf(1); - *bf++ = f[0]; - ++f; - } - for (;;) { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v, c; - v = *(stbsp__uint32 *)f; - c = (~v) & 0x80808080; - if (((v ^ 0x25252525) - 0x01010101) & c) - goto schk1; - if ((v - 0x01010101) & c) - goto schk2; - if (callback) - if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) - goto schk1; - #ifdef STB_SPRINTF_NOUNALIGNED - if(((stbsp__uintptr)bf) & 3) { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } else - #endif - { - *(stbsp__uint32 *)bf = v; - } - bf += 4; - f += 4; - } - } - scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - fw = 0; - pr = -1; - fl = 0; - tz = 0; - - // flags - for (;;) { - switch (f[0]) { - // if we have left justify - case '-': - fl |= STBSP__LEFTJUST; - ++f; - continue; - // if we have leading plus - case '+': - fl |= STBSP__LEADINGPLUS; - ++f; - continue; - // if we have leading space - case ' ': - fl |= STBSP__LEADINGSPACE; - ++f; - continue; - // if we have leading 0x - case '#': - fl |= STBSP__LEADING_0X; - ++f; - continue; - // if we have thousand commas - case '\'': - fl |= STBSP__TRIPLET_COMMA; - ++f; - continue; - // if we have kilo marker (none->kilo->kibi->jedec) - case '$': - if (fl & STBSP__METRIC_SUFFIX) { - if (fl & STBSP__METRIC_1024) { - fl |= STBSP__METRIC_JEDEC; - } else { - fl |= STBSP__METRIC_1024; - } - } else { - fl |= STBSP__METRIC_SUFFIX; - } - ++f; - continue; - // if we don't want space between metric suffix and number - case '_': - fl |= STBSP__METRIC_NOSPACE; - ++f; - continue; - // if we have leading zero - case '0': - fl |= STBSP__LEADINGZERO; - ++f; - goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if (f[0] == '*') { - fw = va_arg(va, stbsp__uint32); - ++f; - } else { - while ((f[0] >= '0') && (f[0] <= '9')) { - fw = fw * 10 + f[0] - '0'; - f++; - } - } - // get the precision - if (f[0] == '.') { - ++f; - if (f[0] == '*') { - pr = va_arg(va, stbsp__uint32); - ++f; - } else { - pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) { - pr = pr * 10 + f[0] - '0'; - f++; - } - } - } - - // handle integer size overrides - switch (f[0]) { - // are we halfwidth? - case 'h': - fl |= STBSP__HALFWIDTH; - ++f; - if (f[0] == 'h') - ++f; // QUARTERWIDTH - break; - // are we 64-bit (unix style) - case 'l': - fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); - ++f; - if (f[0] == 'l') { - fl |= STBSP__INTMAX; - ++f; - } - break; - // are we 64-bit on intmax? (c99) - case 'j': - fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - case 't': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit (msft style) - case 'I': - if ((f[1] == '6') && (f[2] == '4')) { - fl |= STBSP__INTMAX; - f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { - f += 3; - } else { - fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); - ++f; - } - break; - default: break; - } - - // handle each replacement - switch (f[0]) { - #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - stbsp__uint32 l, n, cs; - stbsp__uint64 n64; -#ifndef STB_SPRINTF_NOFLOAT - double fv; -#endif - stbsp__int32 dp; - char const *sn; - - case 's': - // get the string - s = va_arg(va, char *); - if (s == 0) - s = (char *)"null"; - // get the length, limited to desired precision - // always limit to ~0u chars since our counts are 32b - l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - // copy the string in - goto scopy; - - case 'c': // char - // get the character - s = num + STBSP__NUMSZ - 1; - *s = (char)va_arg(va, int); - l = 1; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - - case 'n': // weird write-bytes specifier - { - int *d = va_arg(va, int *); - *d = tlen + (int)(bf - buf); - } break; - -#ifdef STB_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va, double); // eat it - s = (char *)"No float"; - l = 8; - lead[0] = 0; - tail[0] = 0; - pr = 0; - cs = 0; - STBSP__NOTUSED(dp); - goto scopy; -#else - case 'A': // hex float - case 'a': // hex float - h = (f[0] == 'A') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) - fl |= STBSP__NEGATIVE; - - s = num + 64; - - stbsp__lead_sign(fl, lead); - - if (dp == -1023) - dp = (n64) ? -1022 : 0; - else - n64 |= (((stbsp__uint64)1) << 52); - n64 <<= (64 - 56); - if (pr < 15) - n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); -// add leading chars - -#ifdef STB_SPRINTF_MSVC_MODE - *s++ = '0'; - *s++ = 'x'; -#else - lead[1 + lead[0]] = '0'; - lead[2 + lead[0]] = 'x'; - lead[0] += 2; -#endif - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - if (pr) - *s++ = stbsp__period; - sn = s; - - // print the bits - n = pr; - if (n > 13) - n = 13; - if (pr > (stbsp__int32)n) - tz = pr - n; - pr = 0; - while (n--) { - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - } - - // print the expo - tail[1] = h[17]; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; - n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - - dp = (int)(s - sn); - l = (int)(s - (num + 64)); - s = num + 64; - cs = 1 + (3 << 24); - goto scopy; - - case 'G': // float - case 'g': // float - h = (f[0] == 'G') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; - else if (pr == 0) - pr = 1; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) - fl |= STBSP__NEGATIVE; - - // clamp the precision and delete extra zeros after clamp - n = pr; - if (l > (stbsp__uint32)pr) - l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) { - --pr; - --l; - } - - // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { - if (pr > (stbsp__int32)l) - pr = l - 1; - else if (pr) - --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g semantics for %f - if (dp > 0) { - pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } else { - pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); - } - goto dofloatfromg; - - case 'E': // float - case 'e': // float - h = (f[0] == 'E') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) - fl |= STBSP__NEGATIVE; - doexpfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - // handle leading chars - *s++ = sn[0]; - - if (pr) - *s++ = stbsp__period; - - // handle after decimal - if ((l - 1) > (stbsp__uint32)pr) - l = pr + 1; - for (n = 1; n < l; n++) - *s++ = sn[n]; - // trailing zeros - tz = pr - (l - 1); - pr = 0; - // dump expo - tail[1] = h[0xe]; - dp -= 1; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; -#ifdef STB_SPRINTF_MSVC_MODE - n = 5; -#else - n = (dp >= 100) ? 5 : 4; -#endif - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - cs = 1 + (3 << 24); // how many tens - goto flt_lead; - - case 'f': // float - fv = va_arg(va, double); - doafloat: - // do kilos - if (fl & STBSP__METRIC_SUFFIX) { - double divisor; - divisor = 1000.0f; - if (fl & STBSP__METRIC_1024) - divisor = 1024.0; - while (fl < 0x4000000) { - if ((fv < divisor) && (fv > -divisor)) - break; - fv /= divisor; - fl += 0x1000000; - } - } - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) - fl |= STBSP__NEGATIVE; - dofloatfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - - // handle the three decimal varieties - if (dp <= 0) { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++ = '0'; - if (pr) - *s++ = stbsp__period; - n = -dp; - if ((stbsp__int32)n > pr) - n = pr; - i = n; - while (i) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - i -= 4; - } - while (i) { - *s++ = '0'; - --i; - } - if ((stbsp__int32)(l + n) > pr) - l = pr - n; - i = l; - while (i) { - *s++ = *sn++; - --i; - } - tz = pr - (n + l); - cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } else { - cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { - // handle xxxx000*000.0 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= l) - break; - } - } - if (n < (stbsp__uint32)dp) { - n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --n; - } - while (n >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - n -= 4; - } - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = '0'; - --n; - } - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) { - *s++ = stbsp__period; - tz = pr; - } - } else { - // handle xxxxx.xxxx000*000 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= (stbsp__uint32)dp) - break; - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) - *s++ = stbsp__period; - if ((l - dp) > (stbsp__uint32)pr) - l = pr + dp; - while (n < l) { - *s++ = sn[n]; - ++n; - } - tz = pr - (l - dp); - } - } - pr = 0; - - // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) { - char idx; - idx = 1; - if (fl & STBSP__METRIC_NOSPACE) - idx = 0; - tail[0] = idx; - tail[1] = ' '; - { - if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. - if (fl & STBSP__METRIC_1024) - tail[idx + 1] = "_KMGT"[fl >> 24]; - else - tail[idx + 1] = "_kMGT"[fl >> 24]; - idx++; - // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { - tail[idx + 1] = 'i'; - idx++; - } - tail[0] = idx; - } - } - }; - - flt_lead: - // get the length that we copied - l = (stbsp__uint32)(s - (num + 64)); - s = num + 64; - goto scopy; -#endif - - case 'B': // upper binary - case 'b': // lower binary - h = (f[0] == 'B') ? hexu : hex; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[0xb]; - } - l = (8 << 4) | (1 << 8); - goto radixnum; - - case 'o': // octal - h = hexu; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 1; - lead[1] = '0'; - } - l = (3 << 4) | (3 << 8); - goto radixnum; - - case 'p': // pointer - fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; - pr = sizeof(void *) * 2; - fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // fall through - to X - - case 'X': // upper hex - case 'x': // lower hex - h = (f[0] == 'X') ? hexu : hex; - l = (4 << 4) | (4 << 8); - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[16]; - } - radixnum: - // get the number - if (fl & STBSP__INTMAX) - n64 = va_arg(va, stbsp__uint64); - else - n64 = va_arg(va, stbsp__uint32); - - s = num + STBSP__NUMSZ; - dp = 0; - // clear tail, and clear leading if value is zero - tail[0] = 0; - if (n64 == 0) { - lead[0] = 0; - if (pr == 0) { - l = 0; - cs = 0; - goto scopy; - } - } - // convert to string - for (;;) { - *--s = h[n64 & ((1 << (l >> 8)) - 1)]; - n64 >>= (l >> 8); - if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) - break; - if (fl & STBSP__TRIPLET_COMMA) { - ++l; - if ((l & 15) == ((l >> 4) & 15)) { - l &= ~15; - *--s = stbsp__comma; - } - } - }; - // get the tens and the comma pos - cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - // copy it - goto scopy; - - case 'u': // unsigned - case 'i': - case 'd': // integer - // get the integer and abs it - if (fl & STBSP__INTMAX) { - stbsp__int64 i64 = va_arg(va, stbsp__int64); - n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { - n64 = (stbsp__uint64)-i64; - fl |= STBSP__NEGATIVE; - } - } else { - stbsp__int32 i = va_arg(va, stbsp__int32); - n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { - n64 = (stbsp__uint32)-i; - fl |= STBSP__NEGATIVE; - } - } - -#ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) { - if (n64 < 1024) - pr = 0; - else if (pr == -1) - pr = 1; - fv = (double)(stbsp__int64)n64; - goto doafloat; - } -#endif - - // convert to string - s = num + STBSP__NUMSZ; - l = 0; - - for (;;) { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char *o = s - 8; - if (n64 >= 100000000) { - n = (stbsp__uint32)(n64 % 100000000); - n64 /= 100000000; - } else { - n = (stbsp__uint32)n64; - n64 = 0; - } - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - do { - s -= 2; - *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - } while (n); - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = (char)(n % 10) + '0'; - n /= 10; - } - } - if (n64 == 0) { - if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) - ++s; - break; - } - while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = '0'; - } - } - - tail[0] = 0; - stbsp__lead_sign(fl, lead); - - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { - *--s = '0'; - l = 1; - } - cs = l + (3 << 24); - if (pr < 0) - pr = 0; - - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr < (stbsp__int32)l) - pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw < (stbsp__int32)n) - fw = n; - fw -= n; - pr -= l; - - // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) { - if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr - { - pr = (fw > pr) ? fw : pr; - fw = 0; - } else { - fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas - } - } - - // copy the spaces and/or zeros - if (fw + pr) { - stbsp__int32 i; - stbsp__uint32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) { - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = ' '; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leader - sn = lead + 1; - while (lead[0]) { - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leading zeros - c = cs >> 24; - cs &= 0xffffff; - cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) { - stbsp__cb_buf_clamp(i, pr); - pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - } - while (i) { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { - cs = 0; - *bf++ = stbsp__comma; - } else - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - } - - // copy leader if there is still one - sn = lead + 1; - while (lead[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy the string - n = l; - while (n) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, n); - n -= i; - STBSP__UNALIGNED(while (i >= 4) { - *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; - bf += 4; - s += 4; - i -= 4; - }) - while (i) { - *bf++ = *s++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy trailing zeros - while (tz) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tz); - tz -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy tail if there is one - sn = tail + 1; - while (tail[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tail[0]); - tail[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // handle the left justify - if (fl & STBSP__LEFTJUST) - if (fw > 0) { - while (fw) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i--) - *bf++ = ' '; - stbsp__chk_cb_buf(1); - } - } - break; - - default: // unknown, just copy code - s = num + STBSP__NUMSZ - 1; - *s = f[0]; - l = 1; - fw = fl = 0; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - } - ++f; - } -endfmt: - - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - -done: - return tlen + (int)(bf - buf); -} - -// cleanup -#undef STBSP__LEFTJUST -#undef STBSP__LEADINGPLUS -#undef STBSP__LEADINGSPACE -#undef STBSP__LEADING_0X -#undef STBSP__LEADINGZERO -#undef STBSP__INTMAX -#undef STBSP__TRIPLET_COMMA -#undef STBSP__NEGATIVE -#undef STBSP__METRIC_SUFFIX -#undef STBSP__NUMSZ -#undef stbsp__chk_cb_bufL -#undef stbsp__chk_cb_buf -#undef stbsp__flush_cb -#undef stbsp__cb_buf_clamp - -// ============================================================================ -// wrapper functions - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); - va_end(va); - return result; -} - -typedef struct stbsp__context { - char *buf; - int count; - int length; - char tmp[STB_SPRINTF_MIN]; -} stbsp__context; - -static char *stbsp__clamp_callback(const char *buf, void *user, int len) -{ - stbsp__context *c = (stbsp__context *)user; - c->length += len; - - if (len > c->count) - len = c->count; - - if (len) { - if (buf != c->buf) { - const char *s, *se; - char *d; - d = c->buf; - s = buf; - se = buf + len; - do { - *d++ = *s++; - } while (s < se); - } - c->buf += len; - c->count -= len; - } - - if (c->count <= 0) - return c->tmp; - return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can -} - -static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) -{ - stbsp__context * c = (stbsp__context*)user; - (void) sizeof(buf); - - c->length += len; - return c->tmp; // go direct into buffer if you can -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) -{ - stbsp__context c; - - if ( (count == 0) && !buf ) - { - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); - } - else - { - int l; - - c.buf = buf; - c.count = count; - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - } - - return c.length; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - - result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); - va_end(va); - - return result; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) -{ - return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); -} - -// ======================================================================= -// low level float utility functions - -#ifndef STB_SPRINTF_NOFLOAT - -// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest, src) \ - { \ - int cn; \ - for (cn = 0; cn < 8; cn++) \ - ((char *)&dest)[cn] = ((char *)&src)[cn]; \ - } - -// get float info -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) -{ - double d; - stbsp__int64 b = 0; - - // load value and round at the frac_digits - d = value; - - STBSP__COPYFP(b, d); - - *bits = b & ((((stbsp__uint64)1) << 52) - 1); - *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - - return (stbsp__int32)((stbsp__uint64) b >> 63); -} - -static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; -static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; -static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; -static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; -static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; -static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; -static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 -}; - -#if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; -#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) -#else -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; -#define stbsp__tento19th (1000000000000000000ULL) -#endif - -#define stbsp__ddmulthi(oh, ol, xh, yh) \ - { \ - double ahi = 0, alo, bhi = 0, blo; \ - stbsp__int64 bt; \ - oh = xh * yh; \ - STBSP__COPYFP(bt, xh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(ahi, bt); \ - alo = xh - ahi; \ - STBSP__COPYFP(bt, yh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(bhi, bt); \ - blo = yh - bhi; \ - ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ - } - -#define stbsp__ddtoS64(ob, xh, xl) \ - { \ - double ahi = 0, alo, vh, t; \ - ob = (stbsp__int64)xh; \ - vh = (double)ob; \ - ahi = (xh - vh); \ - t = (ahi - xh); \ - alo = (xh - (ahi - t)) - (vh + t); \ - ob += (stbsp__int64)(ahi + alo + xl); \ - } - -#define stbsp__ddrenorm(oh, ol) \ - { \ - double s; \ - s = oh + ol; \ - ol = ol - (s - oh); \ - oh = s; \ - } - -#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); - -#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); - -static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 -{ - double ph, pl; - if ((power >= 0) && (power <= 22)) { - stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { - stbsp__int32 e, et, eb; - double p2h, p2l; - - e = power; - if (power < 0) - e = -e; - et = (e * 0x2c9) >> 14; /* %23 */ - if (et > 13) - et = 13; - eb = e - (et * 23); - - ph = d; - pl = 0.0; - if (power < 0) { - if (eb) { - --eb; - stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); - stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); - ph = p2h; - pl = p2l; - } - } else { - if (eb) { - e = eb; - if (eb > 22) - eb = 22; - e -= eb; - stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { - stbsp__ddrenorm(ph, pl); - stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); - stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); - ph = p2h; - pl = p2l; - } - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); - ph = p2h; - pl = p2l; - } - } - } - stbsp__ddrenorm(ph, pl); - *ohi = ph; - *olo = pl; -} - -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) -{ - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; - - d = value; - STBSP__COPYFP(bits, d); - expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64) bits >> 63); - if (ng) - d = -d; - - if (expo == 2047) // is nan or inf? - { - *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if (expo == 0) // is zero or denormal - { - if (((stbsp__uint64) bits << 1) == 0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; - *len = 1; - return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { - --expo; - v >>= 1; - } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph, pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens = expo - 1023; - tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - - // get full as much precision from double-double as possible - stbsp__ddtoS64(bits, ph, pl); - - // check if we undershot - if (((stbsp__uint64)bits) >= stbsp__tento19th) - ++tens; - } - - // now do the rounding in integer land - frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { - stbsp__uint32 dg = 1; - if ((stbsp__uint64)bits >= stbsp__powten[9]) - dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { - ++dg; - if (dg == 20) - goto noround; - } - if (frac_digits < dg) { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ((stbsp__uint32)e >= 24) - goto noround; - r = stbsp__powten[e]; - bits = bits + (r / 2); - if ((stbsp__uint64)bits >= stbsp__powten[dg]) - ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if (bits) { - stbsp__uint32 n; - for (;;) { - if (bits <= 0xffffffff) - break; - if (bits % 1000) - goto donez; - bits /= 1000; - } - n = (stbsp__uint32)bits; - while ((n % 1000) == 0) - n /= 1000; - bits = n; - donez:; - } - - // convert to string - out += 64; - e = 0; - for (;;) { - stbsp__uint32 n; - char *o = out - 8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { - n = (stbsp__uint32)(bits % 100000000); - bits /= 100000000; - } else { - n = (stbsp__uint32)bits; - bits = 0; - } - while (n) { - out -= 2; - *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - e += 2; - } - if (bits == 0) { - if ((e) && (out[0] == '0')) { - ++out; - --e; - } - break; - } - while (out != o) { - *--out = '0'; - ++e; - } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef stbsp__ddmulthi -#undef stbsp__ddrenorm -#undef stbsp__ddmultlo -#undef stbsp__ddmultlos -#undef STBSP__SPECIAL -#undef STBSP__COPYFP - -#endif // STB_SPRINTF_NOFLOAT - -// clean up -#undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 -#undef stbsp__uint64 -#undef stbsp__int64 -#undef STBSP__UNALIGNED - -#endif // STB_SPRINTF_IMPLEMENTATION - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/stdlib/stdio.c b/stdlib/stdio.c deleted file mode 100644 index aa13e25..0000000 --- a/stdlib/stdio.c +++ /dev/null @@ -1,1127 +0,0 @@ -#include "stdio.h" - -/* Include STB Sprintf Implementation */ -#define STB_SPRINTF_IMPLEMENTATION -#include "stb_sprintf.h" - -/* Syscall Implementation */ - -const int64 STDIN_FD = 0; -const int64 STDOUT_FD = 1; -const int64 STDERR_FD = 2; - -#if defined(__x86_64__) - -const int64 SYS_read = 0; -const int64 SYS_write = 1; -const int64 SYS_open = 2; -const int64 SYS_close = 3; -const int64 SYS_lseek = 8; - -int64 write(int64 fd, const char *buf, uint64 count) -{ - int64 ret; - __asm__ volatile("syscall" : "=a"(ret) : "a"(SYS_write), "D"(fd), "S"(buf), "d"(count) : "rcx", "r11", "memory"); - return ret; -} -int64 read(int64 fd, char *buf, uint64 count) -{ - int64 ret; - __asm__ volatile("syscall" : "=a"(ret) : "a"(SYS_read), "D"(fd), "S"(buf), "d"(count) : "rcx", "r11", "memory"); - return ret; -} -int64 open(const char *path, int flags, int mode) -{ - int64 ret; - __asm__ volatile("syscall" : "=a"(ret) : "a"(SYS_open), "D"(path), "S"(flags), "d"(mode) : "rcx", "r11", "memory"); - return ret; -} -int64 close(int64 fd) -{ - int64 ret; - __asm__ volatile("syscall" : "=a"(ret) : "a"(SYS_close), "D"(fd) : "rcx", "r11", "memory"); - return ret; -} -int64 lseek(int64 fd, int64 offset, int whence) -{ - int64 ret; - __asm__ volatile("syscall" : "=a"(ret) : "a"(SYS_lseek), "D"(fd), "S"(offset), "d"(whence) : "rcx", "r11", "memory"); - return ret; -} - -#elif defined(__riscv) - -const int64 SYS_read = 63; -const int64 SYS_write = 64; -const int64 SYS_open = 56; // openat -const int64 SYS_close = 57; -const int64 SYS_lseek = 62; - -int64 write(int64 fd, const char *buf, uint64 count) -{ - register int64 a7 asm("a7") = SYS_write; - register int64 a0 asm("a0") = fd; - register int64 a1 asm("a1") = (int64)buf; - register int64 a2 asm("a2") = count; - __asm__ volatile("ecall" : "+r"(a0) : "r"(a7), "r"(a0), "r"(a1), "r"(a2) : "memory"); - return a0; -} -int64 read(int64 fd, char *buf, uint64 count) -{ - register int64 a7 asm("a7") = SYS_read; - register int64 a0 asm("a0") = fd; - register int64 a1 asm("a1") = (int64)buf; - register int64 a2 asm("a2") = count; - __asm__ volatile("ecall" : "+r"(a0) : "r"(a7), "r"(a0), "r"(a1), "r"(a2) : "memory"); - return a0; -} -int64 open(const char *path, int flags, int mode) -{ - register int64 a7 asm("a7") = SYS_open; - register int64 a0 asm("a0") = -100; // AT_FDCWD - register int64 a1 asm("a1") = (int64)path; - register int64 a2 asm("a2") = flags; - register int64 a3 asm("a3") = mode; - __asm__ volatile("ecall" : "+r"(a0) : "r"(a7), "r"(a0), "r"(a1), "r"(a2), "r"(a3) : "memory"); - return a0; -} -int64 close(int64 fd) -{ - register int64 a7 asm("a7") = SYS_close; - register int64 a0 asm("a0") = fd; - __asm__ volatile("ecall" : "+r"(a0) : "r"(a7), "r"(a0) : "memory"); - return a0; -} -int64 lseek(int64 fd, int64 offset, int whence) -{ - register int64 a7 asm("a7") = SYS_lseek; - register int64 a0 asm("a0") = fd; - register int64 a1 asm("a1") = offset; - register int64 a2 asm("a2") = whence; - __asm__ volatile("ecall" : "+r"(a0) : "r"(a7), "r"(a0), "r"(a1), "r"(a2) : "memory"); - return a0; -} - -#else -#error "Architecture not supported" -#endif - -/* Memory and String Functions */ - -void *memset(void *dst, int c, uint64 n) -{ - char *cdst = (char *)dst; - for (uint64 i = 0; i < n; i++) - cdst[i] = (char)c; - return dst; -} - -void *memmove(void *vdst, const void *vsrc, uint64 n) -{ - char *dst = (char *)vdst; - const char *src = (const char *)vsrc; - if (dst == src) - return vdst; - if (src > dst) - { - while (n--) - *dst++ = *src++; - } - else - { - dst += n; - src += n; - while (n-- > 0) - *--dst = *--src; - } - return vdst; -} - -void *memcpy(void *vdst, const void *vsrc, uint64 n) { return memmove(vdst, vsrc, n); } - -int memcmp(const void *s1, const void *s2, uint64 n) -{ - const unsigned char *p1 = (const unsigned char *)s1; - const unsigned char *p2 = (const unsigned char *)s2; - while (n--) - { - if (*p1 != *p2) - return *p1 - *p2; - p1++; - p2++; - } - return 0; -} - -uint64 strlen(const char *s) -{ - const char *p = s; - while (*p) - p++; - return (uint64)(p - s); -} - -char *strcpy(char *dst, const char *src) -{ - char *os = dst; - while ((*dst++ = *src++) != 0) - ; - return os; -} - -char *strcat(char *dst, const char *src) -{ - char *os = dst; - while (*dst) - dst++; - while ((*dst++ = *src++) != 0) - ; - return os; -} - -int strcmp(const char *p, const char *q) -{ - while (*p && *p == *q) - { - p++; - q++; - } - return (int)((unsigned char)*p - (unsigned char)*q); -} - -static int isspace(int c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; -} - -int64 strtoll(const char *str, char **endptr, int base) -{ - const char *s = str; - int64 acc = 0; - int c; - int neg = 0; - int any = 0; - - while (isspace(*s)) - s++; - if (*s == '-') - { - neg = 1; - s++; - } - else if (*s == '+') - { - s++; - } - - if ((base == 0 || base == 16) && *s == '0' && (s[1] == 'x' || s[1] == 'X')) - { - c = s[2]; - s += 2; - base = 16; - } - else if (base == 0 && *s == '0') - { - base = 8; - } - else if (base == 0) - { - base = 10; - } - - for (;; c = *s++) - { - c = *s; - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'A' && c <= 'Z') - c -= 'A' - 10; - else if (c >= 'a' && c <= 'z') - c -= 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > (0x7FFFFFFFFFFFFFFFLL / base)) - any = -1; - else - { - acc *= base; - acc += c; - any = 1; - } - } - if (endptr != 0) - *endptr = (char *)(any ? s : str); - return (neg ? -acc : acc); -} - -/* Core Formatting Implementation */ - -static int _ul_to_str_invert(char *buf, uint64 val, int base, int uppercase) -{ - int i = 0; - const char *digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef"; - if (val == 0) - { - buf[i++] = '0'; - return i; - } - while (val != 0) - { - buf[i++] = digits[val % base]; - val /= base; - } - return i; -} - -typedef struct -{ - char *buf; - uint64 limit; - uint64 written; - int fd; -} _OutContext; - -static void _out_char(_OutContext *ctx, char c) -{ - if (ctx->fd != -1) - { - write(ctx->fd, &c, 1); - ctx->written++; - } - else - { - if (ctx->limit > 0 && ctx->written < ctx->limit - 1) - { - ctx->buf[ctx->written] = c; - } - ctx->written++; - } -} - -static int _vprintf_core(_OutContext *ctx, const char *format, va_list ap) -{ - const char *p = format; - char num_buf[32]; - - while (*p) - { - if (*p != '%') - { - _out_char(ctx, *p++); - continue; - } - p++; - - int flag_left = 0, flag_zero = 0, flag_plus = 0, flag_space = 0, flag_hash = 0; - while (1) - { - if (*p == '-') - flag_left = 1; - else if (*p == '0') - flag_zero = 1; - else if (*p == '+') - flag_plus = 1; - else if (*p == ' ') - flag_space = 1; - else if (*p == '#') - flag_hash = 1; - else - break; - p++; - } - - int width = 0; - if (*p == '*') - { - width = va_arg(ap, int); - if (width < 0) - { - flag_left = 1; - width = -width; - } - p++; - } - else - { - while (*p >= '0' && *p <= '9') - { - width = width * 10 + (*p - '0'); - p++; - } - } - - int precision = -1; - if (*p == '.') - { - p++; - if (*p == '*') - { - precision = va_arg(ap, int); - p++; - } - else - { - precision = 0; - while (*p >= '0' && *p <= '9') - { - precision = precision * 10 + (*p - '0'); - p++; - } - } - } - - int len_mod = 0; - if (*p == 'l') - { - len_mod = 1; - p++; - if (*p == 'l') - { - len_mod = 2; - p++; - } - } - else if (*p == 'z') - { - len_mod = 2; - p++; - } - - char spec = *p++; - if (!spec) - break; - - if (spec == 'd' || spec == 'i' || spec == 'u' || spec == 'x' || spec == 'X' || spec == 'p') - { - uint64 val; - int is_signed = (spec == 'd' || spec == 'i'); - int base = (spec == 'x' || spec == 'X' || spec == 'p') ? 16 : 10; - - if (spec == 'p') - val = (uint64)va_arg(ap, void *); - else if (len_mod == 2) - val = is_signed ? (uint64)va_arg(ap, int64) : va_arg(ap, uint64); - else if (len_mod == 1) - val = is_signed ? (uint64)va_arg(ap, long) : (uint64)va_arg(ap, unsigned long); - else - val = is_signed ? (uint64)((int64)va_arg(ap, int)) : (uint64)va_arg(ap, uint32); - - char sign_char = 0; - if (is_signed) - { - int64 sval = (int64)val; - if (sval < 0) - { - sign_char = '-'; - val = (uint64)(-sval); - } - else if (flag_plus) - sign_char = '+'; - else if (flag_space) - sign_char = ' '; - } - - int digit_len = _ul_to_str_invert(num_buf, val, base, (spec == 'X')); - if (precision >= 0) - flag_zero = 0; - int prec_zeros = (precision > digit_len) ? precision - digit_len : 0; - if (precision == 0 && val == 0) - digit_len = 0; - - int prefix_len = sign_char ? 1 : 0; - char *prefix_str = NULL; - if (spec == 'p' || (flag_hash && val != 0 && (spec == 'x' || spec == 'X'))) - { - prefix_str = (spec == 'X') ? "0X" : "0x"; - prefix_len += 2; - } - - int padding = (width > prefix_len + prec_zeros + digit_len) ? width - (prefix_len + prec_zeros + digit_len) : 0; - - if (!flag_left && !flag_zero) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - if (sign_char) - _out_char(ctx, sign_char); - if (prefix_str) - { - _out_char(ctx, prefix_str[0]); - _out_char(ctx, prefix_str[1]); - } - int total_zeros = prec_zeros + ((flag_zero && !flag_left) ? padding : 0); - for (int i = 0; i < total_zeros; i++) - _out_char(ctx, '0'); - for (int i = digit_len - 1; i >= 0; i--) - _out_char(ctx, num_buf[i]); - if (flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - } - else if (spec == 'f' || spec == 'F' || spec == 'e' || spec == 'E' || spec == 'g' || spec == 'G') - { - char fmt_tmp[32]; - int f_idx = 0; - fmt_tmp[f_idx++] = '%'; - if (flag_left) - fmt_tmp[f_idx++] = '-'; - if (flag_zero) - fmt_tmp[f_idx++] = '0'; - if (flag_plus) - fmt_tmp[f_idx++] = '+'; - if (flag_space) - fmt_tmp[f_idx++] = ' '; - if (flag_hash) - fmt_tmp[f_idx++] = '#'; - if (width > 0) - f_idx += sprintf(&fmt_tmp[f_idx], "%d", width); - if (precision >= 0) - f_idx += sprintf(&fmt_tmp[f_idx], ".%d", precision); - fmt_tmp[f_idx++] = spec; - fmt_tmp[f_idx] = '\0'; - double f_val = va_arg(ap, double); - char f_buf[128]; - stbsp_snprintf(f_buf, sizeof(f_buf), fmt_tmp, f_val); - for (int i = 0; f_buf[i] != '\0'; i++) - _out_char(ctx, f_buf[i]); - } - else if (spec == 's') - { - const char *s = va_arg(ap, char *); - if (!s) - s = "(null)"; - int len = 0; - const char *tmp = s; - while (*tmp && (precision < 0 || len < precision)) - { - tmp++; - len++; - } - int padding = (width > len) ? width - len : 0; - if (!flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - for (int i = 0; i < len; i++) - _out_char(ctx, s[i]); - if (flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - } - else if (spec == 'c') - { - char c = (char)va_arg(ap, int); - int padding = (width > 1) ? width - 1 : 0; - if (!flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - _out_char(ctx, c); - if (flag_left) - for (int i = 0; i < padding; i++) - _out_char(ctx, ' '); - } - else - { - _out_char(ctx, '%'); - if (spec != '%') - _out_char(ctx, spec); - } - } - return (int)ctx->written; -} - -int vsnprintf(char *str, uint64 size, const char *format, va_list ap) -{ - _OutContext ctx; - ctx.buf = str; - ctx.limit = size; - ctx.written = 0; - ctx.fd = -1; - _vprintf_core(&ctx, format, ap); - if (size > 0) - { - if (ctx.written < size) - str[ctx.written] = '\0'; - else - str[size - 1] = '\0'; - } - return (int)ctx.written; -} -int snprintf(char *str, uint64 size, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - int ret = vsnprintf(str, size, format, ap); - va_end(ap); - return ret; -} -int sprintf(char *str, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - int ret = vsnprintf(str, (uint64)-1, format, ap); - va_end(ap); - return ret; -} -int printf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - _OutContext ctx; - ctx.buf = NULL; - ctx.limit = 0; - ctx.written = 0; - ctx.fd = STDOUT_FD; - _vprintf_core(&ctx, format, ap); - va_end(ap); - return (int)ctx.written; -} - -/* Core Function Implementation */ - -typedef struct -{ - const char *buf; - int fd; - uint64 pos; - int ungotten; -} _InContext; - -static int _in_char(_InContext *ctx) -{ - if (ctx->ungotten >= 0) - { - int c = ctx->ungotten; - ctx->ungotten = -1; - return c; - } - if (ctx->fd == -1) - { - if (ctx->buf[ctx->pos] == '\0') - return -1; - return (unsigned char)ctx->buf[ctx->pos++]; - } - char c; - if (read(ctx->fd, &c, 1) == 1) - return (unsigned char)c; - return -1; -} - -static void _unget_char(_InContext *ctx, int c) -{ - if (c != -1) - ctx->ungotten = c; -} -static void _skip_space(_InContext *ctx) -{ - int c; - while ((c = _in_char(ctx)) != -1) - { - if (!isspace(c)) - { - _unget_char(ctx, c); - break; - } - } -} - -static double _simple_strtod(const char *str, char **endptr) -{ - double val = 0.0; - int sign = 1; - if (*str == '-') - { - sign = -1; - str++; - } - else if (*str == '+') - str++; - while (*str >= '0' && *str <= '9') - { - val = val * 10.0 + (*str - '0'); - str++; - } - if (*str == '.') - { - str++; - double div = 10.0; - while (*str >= '0' && *str <= '9') - { - val += (*str - '0') / div; - div *= 10.0; - str++; - } - } - if (*str == 'e' || *str == 'E') - { - str++; - int esign = 1; - if (*str == '-') - { - esign = -1; - str++; - } - else if (*str == '+') - str++; - int eval = 0; - while (*str >= '0' && *str <= '9') - { - eval = eval * 10 + (*str - '0'); - str++; - } - double p = 1.0; - while (eval--) - p *= 10.0; - if (esign == 1) - val *= p; - else - val /= p; - } - if (endptr) - *endptr = (char *)str; - return sign * val; -} - -static int _vscanf_core(_InContext *ctx, const char *format, va_list ap) -{ - int assigned = 0; - const char *p = format; - while (*p) - { - if (isspace(*p)) - { - _skip_space(ctx); - while (isspace(*p)) - p++; - continue; - } - if (*p != '%') - { - _skip_space(ctx); - int c = _in_char(ctx); - if (c != *p) - { - _unget_char(ctx, c); - return assigned; - } - p++; - continue; - } - p++; - int suppress = 0; - if (*p == '*') - { - suppress = 1; - p++; - } - int width = -1; - while (*p >= '0' && *p <= '9') - { - if (width == -1) - width = 0; - width = width * 10 + (*p - '0'); - p++; - } - int len_mod = 0; - if (*p == 'l') - { - len_mod = 1; - p++; - if (*p == 'l') - { - len_mod = 2; - p++; - } - } - else if (*p == 'h') - { - p++; - if (*p == 'h') - p++; - } - char spec = *p++; - if (!spec) - break; - - if (spec == 'd' || spec == 'i' || spec == 'u' || spec == 'x') - { - _skip_space(ctx); - char num_buf[64]; - int i = 0, c = _in_char(ctx); - if (c == '-' || c == '+') - { - num_buf[i++] = (char)c; - c = _in_char(ctx); - } - int base = (spec == 'x') ? 16 : (spec == 'i' ? 0 : 10); - while (c != -1 && i < 63) - { - int digit = (c >= '0' && c <= '9'); - int hex = (base == 16 || base == 0) && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); - int x = (c == 'x' || c == 'X'); - if (base == 0 && i == 1 && num_buf[0] == '0' && x) - base = 16; - if (width > 0 && i >= width) - break; - if (digit || hex || x) - { - num_buf[i++] = (char)c; - c = _in_char(ctx); - } - else - break; - } - num_buf[i] = '\0'; - _unget_char(ctx, c); - if (i == 0) - return assigned; - if (!suppress) - { - int64 val = strtoll(num_buf, NULL, base); - if (len_mod == 2) - *va_arg(ap, int64 *) = val; - else if (len_mod == 1) - *va_arg(ap, long *) = (long)val; - else - *va_arg(ap, int *) = (int)val; - assigned++; - } - } - else if (spec == 'f' || spec == 'F' || spec == 'e' || spec == 'E' || spec == 'g' || spec == 'G') - { - _skip_space(ctx); - char num_buf[64]; - int i = 0, c = _in_char(ctx); - if (c == '-' || c == '+') - { - num_buf[i++] = (char)c; - c = _in_char(ctx); - } - while (c != -1 && i < 63) - { - if ((c >= '0' && c <= '9') || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-') - { - num_buf[i++] = (char)c; - c = _in_char(ctx); - } - else - break; - } - num_buf[i] = '\0'; - _unget_char(ctx, c); - if (i == 0) - return assigned; - if (!suppress) - { - double val = _simple_strtod(num_buf, NULL); - if (len_mod == 1) - *va_arg(ap, double *) = val; - else - *va_arg(ap, float *) = (float)val; - assigned++; - } - } - else if (spec == 's') - { - _skip_space(ctx); - char *buf = suppress ? NULL : va_arg(ap, char *); - int i = 0, c = _in_char(ctx); - while (c != -1 && !isspace(c)) - { - if (width > 0 && i >= width) - break; - if (!suppress) - buf[i] = (char)c; - i++; - c = _in_char(ctx); - } - if (!suppress) - buf[i] = '\0'; - _unget_char(ctx, c); - if (i > 0 && !suppress) - assigned++; - } - else if (spec == 'c') - { - int count = (width > 0) ? width : 1; - char *buf = suppress ? NULL : va_arg(ap, char *); - for (int i = 0; i < count; i++) - { - int c = _in_char(ctx); - if (c == -1) - return assigned; - if (!suppress) - buf[i] = (char)c; - } - if (!suppress) - assigned++; - } - } - return assigned; -} - -int sscanf(const char *str, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - _InContext ctx; - ctx.buf = str; - ctx.fd = -1; - ctx.pos = 0; - ctx.ungotten = -1; - int ret = _vscanf_core(&ctx, format, ap); - va_end(ap); - return ret; -} -int scanf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - _InContext ctx; - ctx.buf = NULL; - ctx.fd = STDIN_FD; - ctx.pos = 0; - ctx.ungotten = -1; - int ret = _vscanf_core(&ctx, format, ap); - va_end(ap); - return ret; -} - -/* FILE Stream Implementation */ - -#define O_RDONLY 00 -#define O_WRONLY 01 -#define O_RDWR 02 -#define O_CREAT 0100 -#define O_TRUNC 01000 -#define O_APPEND 02000 - -#define MAX_FILES 8 -static FILE _file_pool[MAX_FILES]; -static FILE _stdin = {.fd = 0, .used = 1}; -static FILE _stdout = {.fd = 1, .used = 1}; -static FILE _stderr = {.fd = 2, .used = 1}; - -FILE *stdin = &_stdin; -FILE *stdout = &_stdout; -FILE *stderr = &_stderr; - -FILE *fopen(const char *filename, const char *mode) -{ - int flags = 0; - if (strcmp(mode, "r") == 0) - flags = O_RDONLY; - else if (strcmp(mode, "w") == 0) - flags = O_WRONLY | O_CREAT | O_TRUNC; - else if (strcmp(mode, "a") == 0) - flags = O_WRONLY | O_CREAT | O_APPEND; - else if (strcmp(mode, "r+") == 0) - flags = O_RDWR; - else - return NULL; - - FILE *f = NULL; - for (int i = 0; i < MAX_FILES; i++) - if (!_file_pool[i].used) - { - f = &_file_pool[i]; - break; - } - if (!f) - return NULL; - - int64 fd = open(filename, flags, 0666); - if (fd < 0) - return NULL; - f->fd = (int)fd; - f->flags = flags; - f->error = 0; - f->eof = 0; - f->used = 1; - return f; -} - -int fclose(FILE *stream) -{ - if (!stream || !stream->used) - return -1; - if (stream == stdin || stream == stdout || stream == stderr) - return 0; - close(stream->fd); - stream->used = 0; - stream->fd = -1; - return 0; -} - -int fflush(FILE *stream) { return 0; } - -int fprintf(FILE *stream, const char *format, ...) -{ - if (!stream) - return -1; - va_list ap; - va_start(ap, format); - _OutContext ctx; - ctx.buf = NULL; - ctx.limit = 0; - ctx.written = 0; - ctx.fd = stream->fd; - _vprintf_core(&ctx, format, ap); - va_end(ap); - return (int)ctx.written; -} - -int fscanf(FILE *stream, const char *format, ...) -{ - if (!stream) - return -1; - va_list ap; - va_start(ap, format); - _InContext ctx; - ctx.buf = NULL; - ctx.fd = stream->fd; - ctx.pos = 0; - ctx.ungotten = -1; - int ret = _vscanf_core(&ctx, format, ap); - va_end(ap); - return ret; -} - -int fputc(int c, FILE *stream) -{ - if (!stream) - return -1; - char ch = (char)c; - write(stream->fd, &ch, 1); - return c; -} - -int fputs(const char *s, FILE *stream) -{ - if (!stream) - return -1; - write(stream->fd, s, strlen(s)); - return 0; -} - -int fgetc(FILE *stream) -{ - if (!stream) - return -1; - char c; - if (read(stream->fd, &c, 1) == 1) - return (unsigned char)c; - stream->eof = 1; - return -1; -} - -char *fgets(char *str, int n, FILE *stream) -{ - if (!stream || !stream->used || n <= 0) - return NULL; - int i = 0, c; - while (i < n - 1) - { - c = fgetc(stream); - if (c == -1) - { - if (i == 0) - return NULL; - break; - } - str[i++] = (char)c; - if (c == '\n') - break; - } - str[i] = '\0'; - return str; -} - -uint64 fread(void *ptr, uint64 size, uint64 nmemb, FILE *stream) -{ - if (!stream || !stream->used || !ptr || size == 0 || nmemb == 0) - return 0; - uint64 total = size * nmemb, read_bytes = 0; - char *p = (char *)ptr; - while (read_bytes < total) - { - int64 ret = read(stream->fd, p + read_bytes, total - read_bytes); - if (ret > 0) - read_bytes += ret; - else if (ret == 0) - { - stream->eof = 1; - break; - } - else - { - stream->error = 1; - break; - } - } - return read_bytes / size; -} - -uint64 fwrite(const void *ptr, uint64 size, uint64 nmemb, FILE *stream) -{ - if (!stream || !stream->used || !ptr || size == 0 || nmemb == 0) - return 0; - uint64 total = size * nmemb, written = 0; - const char *p = (const char *)ptr; - while (written < total) - { - int64 ret = write(stream->fd, p + written, total - written); - if (ret > 0) - written += ret; - else - { - stream->error = 1; - break; - } - } - return written / size; -} - -int fseek(FILE *stream, long offset, int whence) -{ - if (!stream || !stream->used) - return -1; - stream->eof = 0; - if (lseek(stream->fd, offset, whence) < 0) - { - stream->error = 1; - return -1; - } - return 0; -} -long ftell(FILE *stream) -{ - if (!stream || !stream->used) - return -1L; - int64 ret = lseek(stream->fd, 0, SEEK_CUR); - if (ret < 0) - { - stream->error = 1; - return -1L; - } - return (long)ret; -} -void rewind(FILE *stream) -{ - if (stream) - { - fseek(stream, 0, SEEK_SET); - stream->error = 0; - } -} - -int feof(FILE *stream) { return (stream && stream->used) ? stream->eof : 1; } -int ferror(FILE *stream) { return (stream && stream->used) ? stream->error : 1; } -void clearerr(FILE *stream) -{ - if (stream && stream->used) - { - stream->error = 0; - stream->eof = 0; - } -}
\ No newline at end of file diff --git a/stdlib/stdio.h b/stdlib/stdio.h deleted file mode 100644 index 1fd66b7..0000000 --- a/stdlib/stdio.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Standard I/O Library for Lume OS */ - -#ifndef _STDIO_H -#define _STDIO_H - -#include <stdarg.h> - -/*Type Definition (Adjusted According to Architecture)*/ -#ifndef NULL -#define NULL ((void *)0) -#endif - -/*Macro definition*/ -#define EOF (-1) - -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - -/* Basic integer types */ -typedef unsigned int uint; -typedef unsigned short ushort; -typedef unsigned char uchar; - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef unsigned long long uint64; - -typedef char int8; -typedef short int16; -typedef int int32; -typedef long long int64; -typedef long long intptr_t; - -/* FILE structure */ -typedef struct -{ - int fd; // File descriptor - int flags; // Status flag - int error; // Error flag - int eof; // EOF flag - int used; // Static pool occupancy flag -} FILE; - -/* standard stream object */ -extern FILE *stdin; -extern FILE *stdout; -extern FILE *stderr; - -/* Function Declaration */ - -/* File Operations */ -FILE *fopen(const char *filename, const char *mode); -int fclose(FILE *stream); -int fflush(FILE *stream); // Not implement - -/* Formatted input and output */ -int printf(const char *format, ...); -int scanf(const char *format, ...); -int sprintf(char *str, const char *format, ...); -int snprintf(char *str, uint64 size, const char *format, ...); -int vsnprintf(char *str, uint64 size, const char *format, va_list ap); -int sscanf(const char *str, const char *format, ...); - -int fprintf(FILE *stream, const char *format, ...); -int fscanf(FILE *stream, const char *format, ...); - -/* Character/String Read and Write */ -int fputc(int c, FILE *stream); -int fputs(const char *s, FILE *stream); -int fgetc(FILE *stream); -char *fgets(char *str, int n, FILE *stream); - -/* Common Macros/Wrapper Functions */ -#define getchar() fgetc(stdin) -#define putchar(c) fputc((c), stdout) - -/* Binary read and write */ -uint64 fread(void *ptr, uint64 size, uint64 nmemb, FILE *stream); -uint64 fwrite(const void *ptr, uint64 size, uint64 nmemb, FILE *stream); - -/* File location */ -int fseek(FILE *stream, long offset, int whence); -long ftell(FILE *stream); -void rewind(FILE *stream); - -/* Status Inquiry */ -int feof(FILE *stream); -int ferror(FILE *stream); -void clearerr(FILE *stream); - -/* Low-level system call */ -int64 open(const char *path, int flags, int mode); -int64 close(int64 fd); -int64 read(int64 fd, char *buf, uint64 count); -int64 write(int64 fd, const char *buf, uint64 count); -int64 lseek(int64 fd, int64 offset, int whence); - -#endif /* _STDIO_H */
\ No newline at end of file diff --git a/stdlib/string.c b/stdlib/string.c deleted file mode 100644 index e69de29..0000000 --- a/stdlib/string.c +++ /dev/null diff --git a/stdlib/string.h b/stdlib/string.h deleted file mode 100644 index aa87489..0000000 --- a/stdlib/string.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "common/types.h" - - -void *memset(void *dst, int c, uint n); -int memcmp(const void *v1, const void *v2, uint n); -void *memmove(void *dst, const void *src, uint n); -void *memcpy(void *dst, const void *src, uint n); - - -void strcpy(char *dst, const char *src); -int strlen(const char *s); -int strcmp(const char *s1, const char *s2);
\ No newline at end of file |
