Repository: SamyPesse/How-to-Make-a-Computer-Operating-System Branch: master Commit: eb30f8802fac Files: 430 Total size: 729.8 KB Directory structure: gitextract_39nrcw17/ ├── .gitignore ├── Chapter-1/ │ └── README.md ├── Chapter-2/ │ └── README.md ├── Chapter-3/ │ └── README.md ├── Chapter-4/ │ └── README.md ├── Chapter-5/ │ └── README.md ├── Chapter-6/ │ └── README.md ├── Chapter-7/ │ └── README.md ├── Chapter-8/ │ └── README.md ├── LICENSE ├── README.md ├── SUMMARY.md ├── chapter9/ │ └── README.md └── src/ ├── Makefile ├── Vagrantfile ├── kernel/ │ ├── Makefile │ ├── arch/ │ │ └── x86/ │ │ ├── Makefile │ │ ├── alloc.cc │ │ ├── architecture.cc │ │ ├── architecture.h │ │ ├── archprocess.h │ │ ├── config.make │ │ ├── io.cc │ │ ├── io.h │ │ ├── linker.ld │ │ ├── start.asm │ │ ├── switch.asm │ │ ├── vmm.cc │ │ ├── vmm.h │ │ ├── x86.cc │ │ ├── x86.h │ │ └── x86int.asm │ ├── config.h │ ├── core/ │ │ ├── Makefile │ │ ├── api/ │ │ │ ├── dev/ │ │ │ │ ├── clock.h │ │ │ │ ├── fb.h │ │ │ │ ├── ioctl.h │ │ │ │ ├── ipc.h │ │ │ │ ├── keyboard.h │ │ │ │ ├── proc.h │ │ │ │ └── tty.h │ │ │ └── kernel/ │ │ │ ├── syscall.h │ │ │ └── syscall_table.h │ │ ├── api.h │ │ ├── api_posix.cc │ │ ├── boot.h │ │ ├── class.cc │ │ ├── device.cc │ │ ├── device.h │ │ ├── elf_loader.cc │ │ ├── elf_loader.h │ │ ├── env.cc │ │ ├── env.h │ │ ├── file.cc │ │ ├── file.h │ │ ├── filesystem.cc │ │ ├── filesystem.h │ │ ├── kernel.cc │ │ ├── kernel.h │ │ ├── keyboard.h │ │ ├── modulelink.cc │ │ ├── modulelink.h │ │ ├── os.h │ │ ├── process.cc │ │ ├── process.h │ │ ├── signal.h │ │ ├── socket.cc │ │ ├── socket.h │ │ ├── syscalls.cc │ │ ├── syscalls.h │ │ ├── system.cc │ │ ├── system.h │ │ ├── user.cc │ │ └── user.h │ ├── modules/ │ │ ├── Makefile │ │ ├── bochsvbe.cc │ │ ├── bochsvbe.h │ │ ├── clock_x86.cc │ │ ├── clock_x86.h │ │ ├── dospartition.cc │ │ ├── dospartition.h │ │ ├── ext2.cc │ │ ├── ext2.h │ │ ├── ide.cc │ │ ├── ide.h │ │ ├── keys.cc │ │ ├── keys.h │ │ ├── module.cc │ │ ├── module.h │ │ ├── modules.conf │ │ ├── null.cc │ │ ├── null.h │ │ ├── stdtty.cc │ │ ├── stdtty.h │ │ ├── x86serial.cc │ │ └── x86serial.h │ └── runtime/ │ ├── Makefile │ ├── alloc.h │ ├── buffer.cc │ ├── buffer.h │ ├── cxx.cc │ ├── itoa.cc │ ├── libc.h │ ├── list.h │ ├── memory.cc │ ├── string.cc │ ├── string.h │ └── types.h ├── sdk/ │ ├── Makefile │ ├── bootdisk/ │ │ ├── bin/ │ │ │ └── .gitkeep │ │ └── boot/ │ │ └── grub/ │ │ ├── grub.conf │ │ ├── menu.lst │ │ ├── stage1 │ │ ├── stage2 │ │ └── stage2_eltorito │ ├── build.mak │ ├── diskimage.sh │ ├── include/ │ │ ├── _ansi.h │ │ ├── alloca.h │ │ ├── arpa/ │ │ │ └── inet.h │ │ ├── assert.h │ │ ├── ctype.h │ │ ├── dirent.h │ │ ├── endian.h │ │ ├── errno.h │ │ ├── fcntl.h │ │ ├── float.h │ │ ├── getopt.h │ │ ├── inttypes.h │ │ ├── limits.h │ │ ├── linker.ld │ │ ├── locale.h │ │ ├── math.h │ │ ├── netinet/ │ │ │ └── in.h │ │ ├── os.h │ │ ├── pwd.h │ │ ├── setjmp.h │ │ ├── signal.h │ │ ├── stdarg.h │ │ ├── stddef.h │ │ ├── stdint.h │ │ ├── stdio.h │ │ ├── stdlib.h │ │ ├── string.h │ │ ├── strings.h │ │ ├── sys/ │ │ │ ├── cdefs.h │ │ │ ├── ioctl.h │ │ │ ├── mman.h │ │ │ ├── mount.h │ │ │ ├── param.h │ │ │ ├── resource.h │ │ │ ├── select.h │ │ │ ├── socket.h │ │ │ ├── stat.h │ │ │ ├── time.h │ │ │ ├── types.h │ │ │ └── wait.h │ │ ├── termios.h │ │ ├── time.h │ │ ├── unistd.h │ │ └── utime.h │ ├── lib/ │ │ └── .gitkeep │ ├── qemu.sh │ └── src/ │ └── libc/ │ ├── Makefile │ ├── arch/ │ │ └── i386/ │ │ ├── getpagesize.c │ │ ├── longjmp.S │ │ ├── math/ │ │ │ ├── e_atan2.S │ │ │ ├── e_exp.S │ │ │ ├── e_fmod.S │ │ │ ├── e_hypot.S │ │ │ ├── e_log.S │ │ │ ├── e_log10.S │ │ │ ├── e_pow.S │ │ │ ├── s_ceil.S │ │ │ ├── s_cos.S │ │ │ ├── s_fabs.S │ │ │ ├── s_finite.S │ │ │ ├── s_floor.S │ │ │ ├── s_frexp.S │ │ │ ├── s_scalbn.S │ │ │ └── s_sin.S │ │ └── setjmp.S │ └── src/ │ ├── closedir.c │ ├── ctype/ │ │ ├── isalnum.c │ │ ├── isalpha.c │ │ ├── isascii.c │ │ ├── isblank.c │ │ ├── iscntrl.c │ │ ├── isdigit.c │ │ ├── isgraph.c │ │ ├── islower.c │ │ ├── isprint.c │ │ ├── ispunct.c │ │ ├── isspace.c │ │ ├── isupper.c │ │ ├── isxdigit.c │ │ ├── toascii.c │ │ ├── tolower.c │ │ └── toupper.c │ ├── fcntl/ │ │ ├── creat.c │ │ ├── fcntl.c │ │ └── open.c │ ├── getopt/ │ │ ├── getopt.c │ │ ├── getopt_int.h │ │ ├── getopt_long.c │ │ └── getopt_long_only.c │ ├── locale/ │ │ ├── localeconv.c │ │ └── setlocale.c │ ├── math/ │ │ ├── s_ldexp.c │ │ └── s_modf.c │ ├── network/ │ │ ├── inet_aton.c │ │ └── inet_ntoa.c │ ├── opendir.c │ ├── os/ │ │ ├── debug.c │ │ ├── ipc.c │ │ ├── module.c │ │ ├── os.c │ │ ├── region.c │ │ ├── semaphore.c │ │ ├── syscall.c │ │ ├── sysinfo.c │ │ └── thread.c │ ├── pwd/ │ │ ├── endpwent.c │ │ ├── getpwent.c │ │ ├── getpwnam.c │ │ ├── getpwuid.c │ │ └── setpwent.c │ ├── readdir.c │ ├── rewinddir.c │ ├── signal/ │ │ ├── kill.c │ │ ├── killpg.c │ │ ├── raise.c │ │ ├── sigaction.c │ │ ├── sigaddset.c │ │ ├── sigdelset.c │ │ ├── sigemptyset.c │ │ ├── sigfillset.c │ │ ├── sigismember.c │ │ ├── signal.c │ │ └── sigprocmask.c │ ├── sscanf.c │ ├── start.c │ ├── stdio/ │ │ ├── clearerr.c │ │ ├── fclose.c │ │ ├── fdopen.c │ │ ├── feof.c │ │ ├── ferror.c │ │ ├── fflush.c │ │ ├── fgetc.c │ │ ├── fgets.c │ │ ├── fileno.c │ │ ├── fopen.c │ │ ├── fpurge.c │ │ ├── fputc.c │ │ ├── fputs.c │ │ ├── fread.c │ │ ├── freopen.c │ │ ├── fseek.c │ │ ├── ftell.c │ │ ├── fwrite.c │ │ ├── getc.c │ │ ├── perror.c │ │ ├── putc.c │ │ ├── putchar.c │ │ ├── puts.c │ │ ├── remove.c │ │ ├── rename.c │ │ ├── rewind.c │ │ ├── setvbuf.c │ │ ├── stdio_internal.c │ │ ├── stdio_internal.h │ │ ├── streams.c │ │ ├── support_bufio.c │ │ ├── support_pf.c │ │ ├── support_supcon.c │ │ └── ungetc.c │ ├── stdlib/ │ │ ├── abort.c │ │ ├── abs.c │ │ ├── atof.c │ │ ├── atoi.c │ │ ├── atol.c │ │ ├── atoll.c │ │ ├── bsearch.c │ │ ├── getenv.c │ │ ├── labs.c │ │ ├── llabs.c │ │ ├── malloc.c │ │ ├── mkstemp.c │ │ ├── mktemp.c │ │ ├── qsort.c │ │ ├── rand.c │ │ ├── random.c │ │ ├── srand.c │ │ ├── srandom.c │ │ ├── strtod.c │ │ ├── strtol.c │ │ ├── strtoll.c │ │ ├── strtoul.c │ │ └── strtoull.c │ ├── string/ │ │ ├── memchr.c │ │ ├── memcmp.c │ │ ├── memcpy.c │ │ ├── memmove.c │ │ ├── memset.c │ │ ├── strcasecmp.c │ │ ├── strcat.c │ │ ├── strchr.c │ │ ├── strcmp.c │ │ ├── strcpy.c │ │ ├── strcspn.c │ │ ├── strdup.c │ │ ├── strerror.c │ │ ├── strlen.c │ │ ├── strncasecmp.c │ │ ├── strncat.c │ │ ├── strncmp.c │ │ ├── strncpy.c │ │ ├── strndup.c │ │ ├── strnlen.c │ │ ├── strpbrk.c │ │ ├── strrchr.c │ │ ├── strsignal.c │ │ ├── strspn.c │ │ ├── strstr.c │ │ ├── strtok.c │ │ └── strtok_r.c │ ├── sys/ │ │ ├── chmod.c │ │ ├── connect.c │ │ ├── fstat.c │ │ ├── ioctl.c │ │ ├── lstat.c │ │ ├── mkdir.c │ │ ├── mount.c │ │ ├── select.c │ │ ├── socket.c │ │ ├── stat.c │ │ ├── stime.c │ │ ├── umask.c │ │ ├── umount.c │ │ ├── utime.c │ │ ├── utimes.c │ │ ├── wait.c │ │ ├── wait3.c │ │ ├── wait4.c │ │ └── waitpid.c │ ├── termios/ │ │ ├── tcflow.c │ │ ├── tcflush.c │ │ ├── tcgetattr.c │ │ ├── tcgetpgrp.c │ │ ├── tcsetattr.c │ │ └── tcsetpgrp.c │ ├── time/ │ │ ├── asctime.c │ │ ├── asctime_r.c │ │ ├── ctime.c │ │ ├── ctime_r.c │ │ ├── gettimeofday.c │ │ ├── gmtime.c │ │ ├── gmtime_r.c │ │ ├── localtime.c │ │ ├── localtime_r.c │ │ ├── mktime.c │ │ ├── nanosleep.c │ │ ├── strftime.c │ │ ├── time.c │ │ ├── time_int.c │ │ ├── time_int.h │ │ └── tzset.c │ ├── trio/ │ │ ├── trio.c │ │ ├── trio.h │ │ ├── triodef.h │ │ ├── trionan.c │ │ ├── trionan.h │ │ ├── triop.h │ │ ├── triostr.c │ │ └── triostr.h │ ├── udivmoddi4.c │ └── unistd/ │ ├── access.c │ ├── alarm.c │ ├── chdir.c │ ├── chown.c │ ├── close.c │ ├── dup.c │ ├── dup2.c │ ├── execlp.c │ ├── execv.c │ ├── execve.c │ ├── execvp.c │ ├── exit.c │ ├── fchdir.c │ ├── fork.c │ ├── fpathconf.c │ ├── ftruncate.c │ ├── getcwd.c │ ├── getdents.c │ ├── getdtablesize.c │ ├── getegid.c │ ├── geteuid.c │ ├── getgid.c │ ├── gethostname.c │ ├── getpgid.c │ ├── getpgrp.c │ ├── getpid.c │ ├── getppid.c │ ├── gettid.c │ ├── getuid.c │ ├── isatty.c │ ├── link.c │ ├── lseek.c │ ├── mmap.c │ ├── pipe.c │ ├── pread.c │ ├── pwrite.c │ ├── read.c │ ├── readlink.c │ ├── rmdir.c │ ├── sbrk.c │ ├── setgid.c │ ├── setpgid.c │ ├── setpgrp.c │ ├── setregid.c │ ├── setreuid.c │ ├── setuid.c │ ├── sleep.c │ ├── symlink.c │ ├── ttyname.c │ ├── unlink.c │ └── write.c └── userland/ ├── Makefile └── helloworld/ ├── Makefile └── main.c ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Compiled Object files *.slo *.lo *.o # Compiled Dynamic libraries *.so *.dylib # Compiled Static libraries *.lai *.la *.a # Elf binaries *.elf # Vagrant /src/.vagrant/ # Other /src/userland/helloworld/hello # SDK binaries /src/sdk/bootdisk/bin/hello /src/sdk/c.img node_modules .grunt _book ================================================ FILE: Chapter-1/README.md ================================================ ## Chapter 1: Introduction to the x86 architecture and about our OS ### What is the x86 architecture? > The term x86 denotes a family of backward compatible instruction set architectures based on the Intel 8086 CPU. The x86 architecture is the most common instruction set architecture since its introduction in 1981 for the IBM PC. A large amount of software, including operating systems (OS's) such as DOS, Windows, Linux, BSD, Solaris and Mac OS X, function with x86-based hardware. In this course we are not going to design an operating system for the x86-64 architecture but for x86-32, thanks to backward compatibility, our OS will be compatible with our newer PCs (but take caution if you want to test it on your real machine). ### Our Operating System The goal is to build a very simple UNIX-based operating system in C++, but the goal is not to just build a "proof-of-concept". The OS should be able to boot, start a userland shell and be extensible. The OS will be built for the x86 architecture, running on 32 bits, and compatible with IBM PCs. **Specifications:** * Code in C++ * x86, 32 bit architecture * Boot with Grub * Kind of modular system for drivers * Kind of UNIX style * Multitasking * ELF executable in userland * Modules (accessible in userland using /dev/...) : * IDE disks * DOS partitions * Clock * EXT2 (read only) * Boch VBE * Userland : * API Posix * LibC * "Can" run a shell or some executables (e.g., lua) ================================================ FILE: Chapter-2/README.md ================================================ ## Chapter 2: Setup the development environment The first step is to setup a good and viable development environment. Using Vagrant and Virtualbox, you'll be able to compile and test your OS from all the OSs (Linux, Windows or Mac). ### Install Vagrant > Vagrant is free and open-source software for creating and configuring virtual development environments. It can be considered a wrapper around VirtualBox. Vagrant will help us create a clean virtual development environment on whatever system you are using. The first step is to download and install Vagrant for your system at http://www.vagrantup.com/. ### Install Virtualbox > Oracle VM VirtualBox is a virtualization software package for x86 and AMD64/Intel64-based computers. Vagrant needs Virtualbox to work, Download and install for your system at https://www.virtualbox.org/wiki/Downloads. ### Start and test your development environment Once Vagrant and Virtualbox are installed, you need to download the ubuntu lucid32 image for Vagrant: ``` vagrant box add lucid32 http://files.vagrantup.com/lucid32.box ``` Once the lucid32 image is ready, we need to define our development environment using a *Vagrantfile*, [create a file named *Vagrantfile*](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/Vagrantfile). This file defines what prerequisites our environment needs: nasm, make, build-essential, grub and qemu. Start your box using: ``` vagrant up ``` You can now access your box by using ssh to connect to the virtual box using: ``` vagrant ssh ``` The directory containing the *Vagrantfile* will be mounted by default in the */vagrant* directory of the guest VM (in this case, Ubuntu Lucid32): ``` cd /vagrant ``` #### Build and test our operating system The file [**Makefile**](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/Makefile) defines some basics rules for building the kernel, the user libc and some userland programs. Build: ``` make all ``` Test our operating system with qemu: ``` make run ``` The documentation for qemu is available at [QEMU Emulator Documentation](http://wiki.qemu.org/download/qemu-doc.html). You can exit the emulator using: Ctrl-a. ================================================ FILE: Chapter-3/README.md ================================================ ## Chapter 3: First boot with GRUB #### How the boot works? When an x86-based computer is turned on, it begins a complex path to get to the stage where control is transferred to our kernel's "main" routine (`kmain()`). For this course, we are only going to consider the BIOS boot method and not it's successor (UEFI). The BIOS boot sequence is: RAM detection -> Hardware detection/Initialization -> Boot sequence. The most important step for us is the "Boot sequence", where the BIOS is done with its initialization and tries to transfer control to the next stage of the bootloader process. During the "Boot sequence", the BIOS will try to determine a "boot device" (e.g. floppy disk, hard-disk, CD, USB flash memory device or network). Our Operating System will initially boot from the hard-disk (but it will be possible to boot it from a CD or a USB flash memory device in future). A device is considered bootable if the bootsector contains the valid signature bytes `0x55` and `0xAA` at offsets 511 and 512 respectively (called the magic bytes of the Master Boot Record, also known as the MBR). This signature is represented (in binary) as 0b1010101001010101. The alternating bit pattern was thought to be a protection against certain failures (drive or controller). If this pattern is garbled or 0x00, the device is not considered bootable. BIOS physically searches for a boot device by loading the first 512 bytes from the bootsector of each device into physical memory, starting at the address `0x7C00` (1 KiB below the 32 KiB mark). When the valid signature bytes are detected, BIOS transfers control to the `0x7C00` memory address (via a jump instruction) in order to execute the bootsector code. Throughout this process the CPU has been running in 16-bit Real Mode, which is the default state for x86 CPUs in order to maintain backwards compatibility. To execute the 32-bit instructions within our kernel, a bootloader is required to switch the CPU into Protected Mode. #### What is GRUB? > GNU GRUB (short for GNU GRand Unified Bootloader) is a boot loader package from the GNU Project. GRUB is the reference implementation of the Free Software Foundation's Multiboot Specification, which provides a user the choice to boot one of multiple operating systems installed on a computer or select a specific kernel configuration available on a particular operating system's partitions. To make it simple, GRUB is the first thing booted by the machine (a boot-loader) and will simplify the loading of our kernel stored on the hard-disk. #### Why are we using GRUB? * GRUB is very simple to use * Make it very simple to load 32bits kernels without needs of 16bits code * Multiboot with Linux, Windows and others * Make it easy to load external modules in memory #### How to use GRUB? GRUB uses the Multiboot specification, the executable binary should be 32bits and must contain a special header (multiboot header) in its 8192 first bytes. Our kernel will be a ELF executable file ("Executable and Linkable Format", a common standard file format for executables in most UNIX system). The first boot sequence of our kernel is written in Assembly: [start.asm](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/start.asm) and we use a linker file to define our executable structure: [linker.ld](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/linker.ld). This boot process also initializes some of our C++ runtime, it will be described in the next chapter. Multiboot header structure: ```cpp struct multiboot_info { u32 flags; u32 low_mem; u32 high_mem; u32 boot_device; u32 cmdline; u32 mods_count; u32 mods_addr; struct { u32 num; u32 size; u32 addr; u32 shndx; } elf_sec; unsigned long mmap_length; unsigned long mmap_addr; unsigned long drives_length; unsigned long drives_addr; unsigned long config_table; unsigned long boot_loader_name; unsigned long apm_table; unsigned long vbe_control_info; unsigned long vbe_mode_info; unsigned long vbe_mode; unsigned long vbe_interface_seg; unsigned long vbe_interface_off; unsigned long vbe_interface_len; }; ``` You can use the command ```mbchk kernel.elf``` to validate your kernel.elf file against the multiboot standard. You can also use the command ```nm -n kernel.elf``` to validate the offset of the different objects in the ELF binary. #### Create a disk image for our kernel and grub The script [diskimage.sh](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/sdk/diskimage.sh) will generate a hard disk image that can be used by QEMU. The first step is to create a hard-disk image (c.img) using qemu-img: ``` qemu-img create c.img 2M ``` We need now to partition the disk using fdisk: ```bash fdisk ./c.img # Switch to Expert commands > x # Change number of cylinders (1-1048576) > c > 4 # Change number of heads (1-256, default 16): > h > 16 # Change number of sectors/track (1-63, default 63) > s > 63 # Return to main menu > r # Add a new partition > n # Choose primary partition > p # Choose partition number > 1 # Choose first sector (1-4, default 1) > 1 # Choose last sector, +cylinders or +size{K,M,G} (1-4, default 4) > 4 # Toggle bootable flag > a # Choose first partition for bootable flag > 1 # Write table to disk and exit > w ``` We need now to attach the created partition to the loop-device using losetup. This allows a file to be access like a block device. The offset of the partition is passed as an argument and calculated using: **offset= start_sector * bytes_by_sector**. Using ```fdisk -l -u c.img```, you get: 63 * 512 = 32256. ```bash losetup -o 32256 /dev/loop1 ./c.img ``` We create a EXT2 filesystem on this new device using: ```bash mke2fs /dev/loop1 ``` We copy our files on a mounted disk: ```bash mount /dev/loop1 /mnt/ cp -R bootdisk/* /mnt/ umount /mnt/ ``` Install GRUB on the disk: ```bash grub --device-map=/dev/null << EOF device (hd0) ./c.img geometry (hd0) 4 16 63 root (hd0,0) setup (hd0) quit EOF ``` And finally we detach the loop device: ```bash losetup -d /dev/loop1 ``` #### See Also * [GNU GRUB on Wikipedia](http://en.wikipedia.org/wiki/GNU_GRUB) * [Multiboot specification](https://www.gnu.org/software/grub/manual/multiboot/multiboot.html) ================================================ FILE: Chapter-4/README.md ================================================ ## Chapter 4: Backbone of the OS and C++ runtime #### C++ kernel run-time A kernel can be written in C++ just as it can be in C, with the exception of a few pitfalls that come with using C++ (runtime support, constructors, etc). The compiler will assume that all the necessary C++ runtime support is available by default, but as we are not linking libsupc++ into your C++ kernel, we need to add some basic functions that can be found in the [cxx.cc](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/runtime/cxx.cc) file. **Caution:** The operators `new` and `delete` cannot be used before virtual memory and pagination have been initialized. #### Basic C/C++ functions The kernel code can't use functions from the standard libraries so we need to add some basic functions for managing memory and strings: ```cpp void itoa(char *buf, unsigned long int n, int base); void * memset(char *dst,char src, int n); void * memcpy(char *dst, char *src, int n); int strlen(char *s); int strcmp(const char *dst, char *src); int strcpy(char *dst,const char *src); void strcat(void *dest,const void *src); char * strncpy(char *destString, const char *sourceString,int maxLength); int strncmp( const char* s1, const char* s2, int c ); ``` These functions are defined in [string.cc](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/runtime/string.cc), [memory.cc](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/runtime/memory.cc), [itoa.cc](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/runtime/itoa.cc) #### C types In the next step, we're going to define different types we're going to use in our code. Most of our variable types are going to be unsigned. This means that all the bits are used to store the integer. Signed variables use their first bit to indicate their sign. ```cpp typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; typedef signed char s8; typedef signed short s16; typedef signed int s32; typedef signed long long s64; ``` #### Compile our kernel Compiling a kernel is not the same thing as compiling a linux executable, we can't use a standard library and should have no dependencies to the system. Our [Makefile](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/Makefile) will define the process to compile and link our kernel. For x86 architecture, the followings arguments will be used for gcc/g++/ld: ``` # Linker LD=ld LDFLAG= -melf_i386 -static -L ./ -T ./arch/$(ARCH)/linker.ld # C++ compiler SC=g++ FLAG= $(INCDIR) -g -O2 -w -trigraphs -fno-builtin -fno-exceptions -fno-stack-protector -O0 -m32 -fno-rtti -nostdlib -nodefaultlibs # Assembly compiler ASM=nasm ASMFLAG=-f elf -o ``` ================================================ FILE: Chapter-5/README.md ================================================ ## Chapter 5: Base classes for managing x86 architecture Now that we know how to compile our C++ kernel and boot the binary using GRUB, we can start to do some cool things in C/C++. #### Printing to the screen console We are going to use VGA default mode (03h) to display some text to the user. The screen can be directly accessed using the video memory at 0xB8000. The screen resolution is 80x25 and each character on the screen is defined by 2 bytes: one for the character code, and one for the style flag. This means that the total size of the video memory is 4000B (80B*25B*2B). In the IO class ([io.cc](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/io.cc)),: * **x,y**: define the cursor position on the screen * **real_screen**: define the video memory pointer * **putc(char c)**: print a unique character on the screen and manage cursor position * **printf(char* s, ...)**: print a string We add a method **putc** to the [IO Class](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/io.cc) to put a character on the screen and update the (x,y) position. ```cpp /* put a byte on screen */ void Io::putc(char c){ kattr = 0x07; unsigned char *video; video = (unsigned char *) (real_screen+ 2 * x + 160 * y); // newline if (c == '\n') { x = 0; y++; // back space } else if (c == '\b') { if (x) { *(video + 1) = 0x0; x--; } // horizontal tab } else if (c == '\t') { x = x + 8 - (x % 8); // carriage return } else if (c == '\r') { x = 0; } else { *video = c; *(video + 1) = kattr; x++; if (x > 79) { x = 0; y++; } } if (y > 24) scrollup(y - 24); } ``` We also add a useful and very known method: [printf](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/io.cc#L155) ```cpp /* put a string in screen */ void Io::print(const char *s, ...){ va_list ap; char buf[16]; int i, j, size, buflen, neg; unsigned char c; int ival; unsigned int uival; va_start(ap, s); while ((c = *s++)) { size = 0; neg = 0; if (c == 0) break; else if (c == '%') { c = *s++; if (c >= '0' && c <= '9') { size = c - '0'; c = *s++; } if (c == 'd') { ival = va_arg(ap, int); if (ival < 0) { uival = 0 - ival; neg++; } else uival = ival; itoa(buf, uival, 10); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; if (neg) print("-%s", buf); else print(buf); } else if (c == 'u') { uival = va_arg(ap, int); itoa(buf, uival, 10); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; print(buf); } else if (c == 'x' || c == 'X') { uival = va_arg(ap, int); itoa(buf, uival, 16); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; print("0x%s", buf); } else if (c == 'p') { uival = va_arg(ap, int); itoa(buf, uival, 16); size = 8; buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; print("0x%s", buf); } else if (c == 's') { print((char *) va_arg(ap, int)); } } else putc(c); } return; } ``` #### Assembly interface A large number of instructions are available in Assembly but there is not equivalent in C (like cli, sti, in and out), so we need an interface to these instructions. In C, we can include Assembly using the directive "asm()", gcc use gas to compile the assembly. **Caution:** gas uses the AT&T syntax. ```cpp /* output byte */ void Io::outb(u32 ad, u8 v){ asmv("outb %%al, %%dx" :: "d" (ad), "a" (v));; } /* output word */ void Io::outw(u32 ad, u16 v){ asmv("outw %%ax, %%dx" :: "d" (ad), "a" (v)); } /* output word */ void Io::outl(u32 ad, u32 v){ asmv("outl %%eax, %%dx" : : "d" (ad), "a" (v)); } /* input byte */ u8 Io::inb(u32 ad){ u8 _v; \ asmv("inb %%dx, %%al" : "=a" (_v) : "d" (ad)); \ return _v; } /* input word */ u16 Io::inw(u32 ad){ u16 _v; \ asmv("inw %%dx, %%ax" : "=a" (_v) : "d" (ad)); \ return _v; } /* input word */ u32 Io::inl(u32 ad){ u32 _v; \ asmv("inl %%dx, %%eax" : "=a" (_v) : "d" (ad)); \ return _v; } ``` ================================================ FILE: Chapter-6/README.md ================================================ ## Chapter 6: GDT Thanks to GRUB, your kernel is no longer in real-mode, but already in [protected mode](http://en.wikipedia.org/wiki/Protected_mode), this mode allows us to use all the possibilities of the microprocessor such as virtual memory management, paging and safe multi-tasking. #### What is the GDT? The [GDT](http://en.wikipedia.org/wiki/Global_Descriptor_Table) ("Global Descriptor Table") is a data structure used to define the different memory areas: the base address, the size and access privileges like execute and write. These memory areas are called "segments". We are going to use the GDT to define different memory segments: * *"code"*: kernel code, used to stored the executable binary code * *"data"*: kernel data * *"stack"*: kernel stack, used to stored the call stack during kernel execution * *"ucode"*: user code, used to stored the executable binary code for user program * *"udata"*: user program data * *"ustack"*: user stack, used to stored the call stack during execution in userland #### How to load our GDT? GRUB initializes a GDT but this GDT is does not correspond to our kernel. The GDT is loaded using the LGDT assembly instruction. It expects the location of a GDT description structure: ![GDTR](./gdtr.png) And the C structure: ```cpp struct gdtr { u16 limite; u32 base; } __attribute__ ((packed)); ``` **Caution:** the directive ```__attribute__ ((packed))``` signal to gcc that the structure should use as little memory as possible. Without this directive, gcc include some bytes to optimize the memory alignment and the access during execution. Now we need to define our GDT table and then load it using LGDT. The GDT table can be stored wherever we want in memory, its address should just be signaled to the process using the GDTR registry. The GDT table is composed of segments with the following structure: ![GDTR](./gdtentry.png) And the C structure: ```cpp struct gdtdesc { u16 lim0_15; u16 base0_15; u8 base16_23; u8 acces; u8 lim16_19:4; u8 other:4; u8 base24_31; } __attribute__ ((packed)); ``` #### How to define our GDT table? We need now to define our GDT in memory and finally load it using the GDTR registry. We are going to store our GDT at the address: ```cpp #define GDTBASE 0x00000800 ``` The function **init_gdt_desc** in [x86.cc](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/x86.cc) initialize a gdt segment descriptor. ```cpp void init_gdt_desc(u32 base, u32 limite, u8 acces, u8 other, struct gdtdesc *desc) { desc->lim0_15 = (limite & 0xffff); desc->base0_15 = (base & 0xffff); desc->base16_23 = (base & 0xff0000) >> 16; desc->acces = acces; desc->lim16_19 = (limite & 0xf0000) >> 16; desc->other = (other & 0xf); desc->base24_31 = (base & 0xff000000) >> 24; return; } ``` And the function **init_gdt** initialize the GDT, some parts of the below function will be explained later and are used for multitasking. ```cpp void init_gdt(void) { default_tss.debug_flag = 0x00; default_tss.io_map = 0x00; default_tss.esp0 = 0x1FFF0; default_tss.ss0 = 0x18; /* initialize gdt segments */ init_gdt_desc(0x0, 0x0, 0x0, 0x0, &kgdt[0]); init_gdt_desc(0x0, 0xFFFFF, 0x9B, 0x0D, &kgdt[1]); /* code */ init_gdt_desc(0x0, 0xFFFFF, 0x93, 0x0D, &kgdt[2]); /* data */ init_gdt_desc(0x0, 0x0, 0x97, 0x0D, &kgdt[3]); /* stack */ init_gdt_desc(0x0, 0xFFFFF, 0xFF, 0x0D, &kgdt[4]); /* ucode */ init_gdt_desc(0x0, 0xFFFFF, 0xF3, 0x0D, &kgdt[5]); /* udata */ init_gdt_desc(0x0, 0x0, 0xF7, 0x0D, &kgdt[6]); /* ustack */ init_gdt_desc((u32) & default_tss, 0x67, 0xE9, 0x00, &kgdt[7]); /* descripteur de tss */ /* initialize the gdtr structure */ kgdtr.limite = GDTSIZE * 8; kgdtr.base = GDTBASE; /* copy the gdtr to its memory area */ memcpy((char *) kgdtr.base, (char *) kgdt, kgdtr.limite); /* load the gdtr registry */ asm("lgdtl (kgdtr)"); /* initiliaz the segments */ asm(" movw $0x10, %ax \n \ movw %ax, %ds \n \ movw %ax, %es \n \ movw %ax, %fs \n \ movw %ax, %gs \n \ ljmp $0x08, $next \n \ next: \n"); } ``` ================================================ FILE: Chapter-7/README.md ================================================ ## Chapter 7: IDT and interrupts An interrupt is a signal to the processor emitted by hardware or software indicating an event that needs immediate attention. There are 3 types of interrupts: - **Hardware interrupts:** are sent to the processor from an external device (keyboard, mouse, hard disk, ...). Hardware interrupts were introduced as a way to reduce wasting the processor's valuable time in polling loops, waiting for external events. - **Software interrupts:** are initiated voluntarily by the software. It's used to manage system calls. - **Exceptions:** are used for errors or events occurring during program execution that are exceptional enough that they cannot be handled within the program itself (division by zero, page fault, ...) #### The keyboard example: When the user pressed a key on the keyboard, the keyboard controller will signal an interrupt to the Interrupt Controller. If the interrupt is not masked, the controller will signal the interrupt to the processor, the processor will execute a routine to manage the interrupt (key pressed or key released), this routine could, for example, get the pressed key from the keyboard controller and print the key to the screen. Once the character processing routine is completed, the interrupted job can be resumed. #### What is the PIC? The [PIC](http://en.wikipedia.org/wiki/Programmable_Interrupt_Controller) (Programmable interrupt controller)is a device that is used to combine several sources of interrupt onto one or more CPU lines, while allowing priority levels to be assigned to its interrupt outputs. When the device has multiple interrupt outputs to assert, it asserts them in the order of their relative priority. The best known PIC is the 8259A, each 8259A can handle 8 devices but most computers have two controllers: one master and one slave, this allows the computer to manage interrupts from 14 devices. In this chapter, we will need to program this controller to initialize and mask interrupts. #### What is the IDT? > The Interrupt Descriptor Table (IDT) is a data structure used by the x86 architecture to implement an interrupt vector table. The IDT is used by the processor to determine the correct response to interrupts and exceptions. Our kernel is going to use the IDT to define the different functions to be executed when an interrupt occurred. Like the GDT, the IDT is loaded using the LIDTL assembly instruction. It expects the location of a IDT description structure: ```cpp struct idtr { u16 limite; u32 base; } __attribute__ ((packed)); ``` The IDT table is composed of IDT segments with the following structure: ```cpp struct idtdesc { u16 offset0_15; u16 select; u16 type; u16 offset16_31; } __attribute__ ((packed)); ``` **Caution:** the directive ```__attribute__ ((packed))``` signal to gcc that the structure should use as little memory as possible. Without this directive, gcc includes some bytes to optimize the memory alignment and the access during execution. Now we need to define our IDT table and then load it using LIDTL. The IDT table can be stored wherever we want in memory, its address should just be signaled to the process using the IDTR registry. Here is a table of common interrupts (Maskable hardware interrupt are called IRQ): | IRQ | Description | |:-----:| -------------------------- | | 0 | Programmable Interrupt Timer Interrupt | | 1 | Keyboard Interrupt | | 2 | Cascade (used internally by the two PICs. never raised) | | 3 | COM2 (if enabled) | | 4 | COM1 (if enabled) | | 5 | LPT2 (if enabled) | | 6 | Floppy Disk | | 7 | LPT1 | | 8 | CMOS real-time clock (if enabled) | | 9 | Free for peripherals / legacy SCSI / NIC | | 10 | Free for peripherals / SCSI / NIC | | 11 | Free for peripherals / SCSI / NIC | | 12 | PS2 Mouse | | 13 | FPU / Coprocessor / Inter-processor | | 14 | Primary ATA Hard Disk | | 15 | Secondary ATA Hard Disk | #### How to initialize the interrupts? This is a simple method to define an IDT segment ```cpp void init_idt_desc(u16 select, u32 offset, u16 type, struct idtdesc *desc) { desc->offset0_15 = (offset & 0xffff); desc->select = select; desc->type = type; desc->offset16_31 = (offset & 0xffff0000) >> 16; return; } ``` And we can now initialize the interupts: ```cpp #define IDTBASE 0x00000000 #define IDTSIZE 0xFF idtr kidtr; ``` ```cpp void init_idt(void) { /* Init irq */ int i; for (i = 0; i < IDTSIZE; i++) init_idt_desc(0x08, (u32)_asm_schedule, INTGATE, &kidt[i]); // /* Vectors 0 -> 31 are for exceptions */ init_idt_desc(0x08, (u32) _asm_exc_GP, INTGATE, &kidt[13]); /* #GP */ init_idt_desc(0x08, (u32) _asm_exc_PF, INTGATE, &kidt[14]); /* #PF */ init_idt_desc(0x08, (u32) _asm_schedule, INTGATE, &kidt[32]); init_idt_desc(0x08, (u32) _asm_int_1, INTGATE, &kidt[33]); init_idt_desc(0x08, (u32) _asm_syscalls, TRAPGATE, &kidt[48]); init_idt_desc(0x08, (u32) _asm_syscalls, TRAPGATE, &kidt[128]); //48 kidtr.limite = IDTSIZE * 8; kidtr.base = IDTBASE; /* Copy the IDT to the memory */ memcpy((char *) kidtr.base, (char *) kidt, kidtr.limite); /* Load the IDTR registry */ asm("lidtl (kidtr)"); } ``` After intialization of our IDT, we need to activate interrupts by configuring the PIC. The following function will configure the two PICs by writting in their internal registries using the output ports of the processor ```io.outb```. We configure the PICs using the ports: * Master PIC: 0x20 and 0x21 * Slave PIC: 0xA0 and 0xA1 For a PIC, there are 2 types of registries: * ICW (Initialization Command Word): reinit the controller * OCW (Operation Control Word): configure the controller once initialized (used to mask/unmask the interrupts) ```cpp void init_pic(void) { /* Initialization of ICW1 */ io.outb(0x20, 0x11); io.outb(0xA0, 0x11); /* Initialization of ICW2 */ io.outb(0x21, 0x20); /* start vector = 32 */ io.outb(0xA1, 0x70); /* start vector = 96 */ /* Initialization of ICW3 */ io.outb(0x21, 0x04); io.outb(0xA1, 0x02); /* Initialization of ICW4 */ io.outb(0x21, 0x01); io.outb(0xA1, 0x01); /* mask interrupts */ io.outb(0x21, 0x0); io.outb(0xA1, 0x0); } ``` #### PIC ICW configurations details The registries have to be configured in order. **ICW1 (port 0x20 / port 0xA0)** ``` |0|0|0|1|x|0|x|x| | | +--- with ICW4 (1) or without (0) | +----- one controller (1), or cascade (0) +--------- triggering by level (level) (1) or by edge (edge) (0) ``` **ICW2 (port 0x21 / port 0xA1)** ``` |x|x|x|x|x|0|0|0| | | | | | +----------------- base address for interrupts vectors ``` **ICW2 (port 0x21 / port 0xA1)** For the master: ``` |x|x|x|x|x|x|x|x| | | | | | | | | +------------------ slave controller connected to the port yes (1), or no (0) ``` For the slave: ``` |0|0|0|0|0|x|x|x| pour l'esclave | | | +-------- Slave ID which is equal to the master port ``` **ICW4 (port 0x21 / port 0xA1)** It is used to define in which mode the controller should work. ``` |0|0|0|x|x|x|x|1| | | | +------ mode "automatic end of interrupt" AEOI (1) | | +-------- mode buffered slave (0) or master (1) | +---------- mode buffered (1) +------------ mode "fully nested" (1) ``` #### Why do idt segments offset our ASM functions? You should have noticed that when I'm initializing our IDT segments, I'm using offsets to segment the code in Assembly. The different functions are defined in [x86int.asm](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/x86int.asm) and are of the following scheme: ```asm %macro SAVE_REGS 0 pushad push ds push es push fs push gs push ebx mov bx,0x10 mov ds,bx pop ebx %endmacro %macro RESTORE_REGS 0 pop gs pop fs pop es pop ds popad %endmacro %macro INTERRUPT 1 global _asm_int_%1 _asm_int_%1: SAVE_REGS push %1 call isr_default_int pop eax ;;a enlever sinon mov al,0x20 out 0x20,al RESTORE_REGS iret %endmacro ``` These macros will be used to define the interrupt segment that will prevent corruption of the different registries, it will be very useful for multitasking. ================================================ FILE: Chapter-8/README.md ================================================ ## Chapter 8: Theory: physical and virtual memory In the chapter related to the GDT, we saw that using segmentation a physical memory address is calculated using a segment selector and an offset. In this chapter, we are going to implement paging, paging will translate a linear address from segmentation into a physical address. #### Why do we need paging? Paging will allow our kernel to: * use the hard-drive as a memory and not be limited by the machine ram memory limit * to have a unique memory space for each process * to allow and unallow memory space in a dynamic way In a paged system, each process may execute in its own 4gb area of memory, without any chance of effecting any other process's memory, or the kernel's. It simplifies multitasking. ![Processes memories](./processes.png) #### How does it work? The translation of a linear address to a physical address is done in multiple steps: 1. The processor use the registry `CR3` to know the physical address of the pages directory. 2. The first 10 bits of the linear address represent an offset (between 0 and 1023), pointing to an entry in the pages directory. This entry contains the physical address of a pages table. 3. the next 10 bits of the linear address represent an offset, pointing to an entry in the pages table. This entry is pointing to a 4ko page. 4. The last 12 bits of the linear address represent an offset (between 0 and 4095), which indicates the position in the 4ko page. ![Address translation](./paging_memory.png) #### Format for pages table and directory The two types of entries (table and directory) look like the same. Only the field in gray will be used in our OS. ![Page directory entry](./page_directory_entry.png) ![Page table entry](./page_table_entry.png) * `P`: indicate if the page or table is in physical memory * `R/W`: indicate if the page or table is accessible in writting (equals 1) * `U/S`: equals 1 to allow access to non-preferred tasks * `A`: indicate if the page or table was accessed * `D`: (only for pages table) indicate if the page was written * `PS` (only for pages directory) indicate the size of pages: * 0 = 4kb * 1 = 4mb **Note:** Physical addresses in the pages diretcory or pages table are written using 20 bits because these addresses are aligned on 4kb, so the last 12bits should be equal to 0. * A pages directory or pages table used 1024*4 = 4096 bytes = 4k * A pages table can address 1024 * 4k = 4 Mb * A pages directory can address 1024 * (1024 * 4k) = 4 Gb #### How to enable pagination? To enable pagination, we just need to set bit 31 of the `CR0`registry to 1: ```asm asm(" mov %%cr0, %%eax; \ or %1, %%eax; \ mov %%eax, %%cr0" \ :: "i"(0x80000000)); ``` But before, we need to initialize our pages directory with at least one pages table. #### Identity Mapping With the identity mapping model, the page will apply only to the kernel as the first 4 MB of virtual memory coincide with the first 4 MB of physical memory: ![Identity Mapping](identitymapping.png) This model is simple: the first virtual memory page coincide to the first page in physical memory, the second page coincide to the second page on physical memory and so on ... ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014 Samy Pessé Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ How to Make a Computer Operating System ======================================= Online book about how to write a computer operating system in C/C++ from scratch. **Caution**: This repository is a remake of my old course. It was written several years ago [as one of my first projects when I was in High School](https://github.com/SamyPesse/devos), I'm still refactoring some parts. The original course was in French and I'm not an English native. I'm going to continue and improve this course in my free-time. **Book**: An online version is available at [http://samypesse.gitbooks.io/how-to-create-an-operating-system/](http://samypesse.gitbooks.io/how-to-create-an-operating-system/) (PDF, Mobi and ePub). It was generated using [GitBook](https://www.gitbook.com/). **Source Code**: All the system source code will be stored in the [src](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/tree/master/src) directory. Each step will contain links to the different related files. **Contributions**: This course is open to contributions, feel free to signal errors with issues or directly correct the errors with pull-requests. **Questions**: Feel free to ask any questions by adding issues or commenting sections. You can follow me on Twitter [@SamyPesse](https://twitter.com/SamyPesse) or [GitHub](https://github.com/SamyPesse). ### What kind of OS are we building? The goal is to build a very simple UNIX-based operating system in C++, not just a "proof-of-concept". The OS should be able to boot, start a userland shell, and be extensible. ![Screen](./preview.png) ================================================ FILE: SUMMARY.md ================================================ # Summary * [Introduction](README.md) * [Introduction about the x86 architecture and about our OS](Chapter-1/README.md) * [Setup the development environment](Chapter-2/README.md) * [First boot with GRUB](Chapter-3/README.md) * [Backbone of the OS and C++ runtime](Chapter-4/README.md) * [Base classes for managing x86 architecture](Chapter-5/README.md) * [GDT](Chapter-6/README.md) * [IDT and interrupts](Chapter-7/README.md) * [Theory: physical and virtual memory](Chapter-8/README.md) * [Memory management: physical and virtual](chapter9/README.md) * Process management and multitasking * External program execution: ELF files * Userland and syscalls * Modular drivers * Some basics modules: console, keyboard * IDE Hard disks * DOS Partitions * EXT2 read-only filesystems * Standard C library (libC) * UNIX basic tools: sh, cat * Lua interpreter ================================================ FILE: chapter9/README.md ================================================ # Memory management: physical and virtual The kernel knows the size of the physical memory available thanks to [GRUB](../Chapter-3/README.md). In our implementation, the first 8 megabytes of physical memory will be reserved for use by the kernel and will contain: - The kernel - GDT, IDT et TSS - Kernel Stack - Some space reserved to hardware (video memory, ...) - Page directory and pages table for the kernel The rest of the physical memory is freely available to the kernel and applications. ![Physical Memory](physicalmemory.png) ### Virtual Memory Mapping The address space between the beginning of memory and `0x40000000` address is the kernel space, while the space between the address `0x40000000` and the end of the memory corresponds to user space: ![Virtual Memory](virtualmemory.png) The kernel space in virtual memory, which is using 1Gb of virtual memory, is common to all tasks (kernel and user). This is implemented by pointing the first 256 entries of the task page directory to the kernel page directory (In [vmm.cc](https://github.com/SamyPesse/How-to-Make-a-Computer-Operating-System/blob/master/src/kernel/arch/x86/vmm.cc#L204)): ```cpp /* * Kernel Space. v_addr < USER_OFFSET are addressed by the kernel pages table */ for (i=0; i<256; i++) pdir[i] = pd0[i]; ``` ================================================ FILE: src/Makefile ================================================ SDKDIR=./sdk help: @echo "Makefile for Building Dev Operating System." @echo "Usage: make [ all | clean | help | build | run] " @echo "" @echo all: @echo "Building Kernel" make -C ./kernel @echo "Building SDK" make -C ./sdk @echo "Building Userland" make -C ./userland build: zip -r devos-$(VERSION).zip ./ run: @echo "Running Dev Operating System." cd ./sdk && sudo bash ./diskimage.sh cd ./sdk && ./qemu.sh clean: make -C ./kernel clean make -C ./userland clean ================================================ FILE: src/Vagrantfile ================================================ # -*- mode: ruby -*- # vi: set ft=ruby : # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # All Vagrant configuration is done here. The most common configuration # options are documented and commented below. For a complete reference, # please see the online documentation at vagrantup.com. # Every Vagrant virtual environment requires a box to build off of. config.vm.box = "lucid32" # The url from where the 'config.vm.box' box will be fetched if it # doesn't already exist on the user's system. config.vm.box_url = "http://files.vagrantup.com/lucid32.box" # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing "localhost:8080" will access port 80 on the guest machine. # config.vm.network :forwarded_port, guest: 80, host: 8080 # Create a private network, which allows host-only access to the machine # using a specific IP. # config.vm.network :private_network, ip: "192.168.33.10" # Create a public network, which generally matched to bridged network. # Bridged networks make the machine appear as another physical device on # your network. # config.vm.network :public_network # If true, then any SSH connections made will enable agent forwarding. # Default value: false # config.ssh.forward_agent = true # Share an additional folder to the guest VM. The first argument is # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. # config.vm.synced_folder "../data", "/vagrant_data" # Provider-specific configuration so you can fine-tune various # backing providers for Vagrant. These expose provider-specific options. # Example for VirtualBox: # # config.vm.provider :virtualbox do |vb| # # Don't boot with headless mode # vb.gui = true # # # Use VBoxManage to customize the VM. For example to change memory: # vb.customize ["modifyvm", :id, "--memory", "1024"] # end # # View the documentation for the provider you're using for more # information on available options. # Enable provisioning with Puppet stand alone. Puppet manifests # are contained in a directory path relative to this Vagrantfile. # You will need to create the manifests directory and a manifest in # the file base.pp in the manifests_path directory. # # An example Puppet manifest to provision the message of the day: # # # group { "puppet": # # ensure => "present", # # } # # # # File { owner => 0, group => 0, mode => 0644 } # # # # file { '/etc/motd': # # content => "Welcome to your Vagrant-built virtual machine! # # Managed by Puppet.\n" # # } # # config.vm.provision :puppet do |puppet| # puppet.manifests_path = "manifests" # puppet.manifest_file = "init.pp" # end # Enable provisioning with chef solo, specifying a cookbooks path, roles # path, and data_bags path (all relative to this Vagrantfile), and adding # some recipes and/or roles. # # config.vm.provision :chef_solo do |chef| # chef.cookbooks_path = "../my-recipes/cookbooks" # chef.roles_path = "../my-recipes/roles" # chef.data_bags_path = "../my-recipes/data_bags" # chef.add_recipe "mysql" # chef.add_role "web" # # # You may also specify custom JSON attributes: # chef.json = { :mysql_password => "foo" } # end $script = %Q{ sudo apt-get update sudo apt-get install nasm make build-essential grub qemu zip -y } config.vm.provision :shell, :inline => $script # Enable provisioning with chef server, specifying the chef server URL, # and the path to the validation key (relative to this Vagrantfile). # # The Opscode Platform uses HTTPS. Substitute your organization for # ORGNAME in the URL and validation key. # # If you have your own Chef Server, use the appropriate URL, which may be # HTTP instead of HTTPS depending on your configuration. Also change the # validation key to validation.pem. # # config.vm.provision :chef_client do |chef| # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" # chef.validation_key_path = "ORGNAME-validator.pem" # end # # If you're using the Opscode platform, your validator client is # ORGNAME-validator, replacing ORGNAME with your organization name. # # If you have your own Chef Server, the default validation client name is # chef-validator, unless you changed the configuration. # # chef.validation_client_name = "ORGNAME-validator" end ================================================ FILE: src/kernel/Makefile ================================================ ARCH=x86 KERNEL=kernel.elf SDKDIR=../sdk INCDIR= -I ./ -I ./modules -I ./core -I ./arch/$(ARCH) include ./arch/$(ARCH)/config.make include ./runtime/Makefile include ./core/Makefile include ./modules/Makefile include ./arch/$(ARCH)/Makefile FLAG :=$(FLAG) -D__$(ARCH)__ PLATFORMS= `find ./arch/ -type d | sed "s/.*\///" | sort` all: $(KERNEL) $(KERNEL): $(OBJS) $(LD) $(LDFLAG) -o $@ $^ cp $(KERNEL) $(SDKDIR)/bootdisk/ help: @echo "Makefile for Kernel." @echo "Please see COPYING for licensing information." @echo "Output should be: "$(KERNEL) @echo "Usage: make [ all | clean] " @echo "Currently supported platforms:" @echo $(PLATFORMS) @echo tosdk: cp $(KERNEL) $(SDKDIR)/disk/ install: sudo cp $(KERNEL) /boot/ debug: $(NM) -n $(KERNEL) hinfo: $(OBJDUMP) -f $(KERNEL) dasm: $(OBJDUMP) -d $(KERNEL) > dasm.txt run: cd $(SDKDIR) && sh ./diskimage.sh cd $(SDKDIR) && sh ./qemu.sh geniso: cd $(SDKDIR) && sh ./cdrom.sh %.o: %.cc $(SC) $(FLAG) -c $< -o $@ %.o: %.S $(SC) $(FLAG) -c $< -o $@ %.o: %.asm $(ASM) $(ASMFLAG) -c $< -o $@ clean: rm -f $(OBJS) $(KERNEL) dasm.txt ================================================ FILE: src/kernel/arch/x86/Makefile ================================================ OBJS:= arch/$(ARCH)/start.o $(OBJS) arch/$(ARCH)/alloc.o arch/$(ARCH)/architecture.o \ arch/$(ARCH)/io.o arch/$(ARCH)/vmm.o arch/$(ARCH)/x86.o arch/$(ARCH)/switch.o arch/$(ARCH)/x86int.o ================================================ FILE: src/kernel/arch/x86/alloc.cc ================================================ #include extern "C" { /* change memory segment size */ void *ksbrk(int n) { struct kmalloc_header *chunk; char *p_addr; int i; if ((kern_heap + (n * PAGESIZE)) > (char *) KERN_HEAP_LIM) { io.print ("PANIC: ksbrk(): no virtual memory left for kernel heap !\n"); return (char *) -1; } chunk = (struct kmalloc_header *) kern_heap; /* Allocation d'une page libre */ for (i = 0; i < n; i++) { p_addr = get_page_frame(); if ((int)(p_addr) < 0) { io.print ("PANIC: ksbrk(): no free page frame available !\n"); return (char *) -1; } /* Ajout dans le repertoire de pages */ pd0_add_page(kern_heap, p_addr, 0); kern_heap += PAGESIZE; } /* Marquage pour kmalloc */ chunk->size = PAGESIZE * n; chunk->used = 0; return chunk; } /* allocate memory block */ void *kmalloc(unsigned long size) { if (size==0) return 0; unsigned long realsize; /* taille totale de l'enregistrement */ struct kmalloc_header *chunk, *other; if ((realsize = sizeof(struct kmalloc_header) + size) < KMALLOC_MINSIZE) realsize = KMALLOC_MINSIZE; /* * On recherche un bloc libre de 'size' octets en parcourant le HEAP * kernel a partir du debut */ chunk = (struct kmalloc_header *) KERN_HEAP; while (chunk->used || chunk->size < realsize) { if (chunk->size == 0) { io.print ("\nPANIC: kmalloc(): corrupted chunk on %x with null size (heap %x) !\nSystem halted\n", chunk, kern_heap); //error asm("hlt"); return 0; } chunk = (struct kmalloc_header *) ((char *) chunk + chunk->size); if (chunk == (struct kmalloc_header *) kern_heap) { if ((int)(ksbrk((realsize / PAGESIZE) + 1)) < 0) { io.print ("\nPANIC: kmalloc(): no memory left for kernel !\nSystem halted\n"); asm("hlt"); return 0; } } else if (chunk > (struct kmalloc_header *) kern_heap) { io.print ("\nPANIC: kmalloc(): chunk on %x while heap limit is on %x !\nSystem halted\n", chunk, kern_heap); asm("hlt"); return 0; } } /* * Found free block with size >= 'size' * We limit size block */ if (chunk->size - realsize < KMALLOC_MINSIZE) chunk->used = 1; else { other = (struct kmalloc_header *) ((char *) chunk + realsize); other->size = chunk->size - realsize; other->used = 0; chunk->size = realsize; chunk->used = 1; } kmalloc_used += realsize; /* Return a pointer to the memory area */ return (char *) chunk + sizeof(struct kmalloc_header); } /* free memory block */ void kfree(void *v_addr) { if (v_addr==(void*)0) return; struct kmalloc_header *chunk, *other; /* On libere le bloc alloue */ chunk = (struct kmalloc_header *) ((u32)v_addr - sizeof(struct kmalloc_header)); chunk->used = 0; kmalloc_used -= chunk->size; /* * Merge free block with next free block */ while ((other = (struct kmalloc_header *) ((char *) chunk + chunk->size)) && other < (struct kmalloc_header *) kern_heap && other->used == 0) chunk->size += other->size; } } ================================================ FILE: src/kernel/arch/x86/architecture.cc ================================================ #include #include /* Stack pointer */ extern u32 * stack_ptr; /* Current cpu name */ static char cpu_name[512] = "x86-noname"; /* Detect the type of processor */ char* Architecture::detect(){ cpu_vendor_name(cpu_name); return cpu_name; } /* Start and initialize the architecture */ void Architecture::init(){ io.print("Architecture x86, cpu=%s \n", detect()); io.print("Loading GDT \n"); init_gdt(); asm(" movw $0x18, %%ax \n \ movw %%ax, %%ss \n \ movl %0, %%esp"::"i" (KERN_STACK)); io.print("Loading IDT \n"); init_idt(); io.print("Configure PIC \n"); init_pic(); io.print("Loading Task Register \n"); asm(" movw $0x38, %ax; ltr %ax"); } /* Initialise the list of processus */ void Architecture::initProc(){ firstProc= new Process("kernel"); firstProc->setState(ZOMBIE); firstProc->addFile(fsm.path("/dev/tty"),0); firstProc->addFile(fsm.path("/dev/tty"),0); firstProc->addFile(fsm.path("/dev/tty"),0); plist=firstProc; pcurrent=firstProc; pcurrent->setPNext(NULL); process_st* current=pcurrent->getPInfo(); current->regs.cr3 = (u32) pd0; } /* Reboot the computer */ void Architecture::reboot(){ u8 good = 0x02; while ((good & 0x02) != 0) good = io.inb(0x64); io.outb(0x64, 0xFE); } /* Shutdown the computer */ void Architecture::shutdown(){ // todo } /* Install a interruption handler */ void Architecture::install_irq(int_handler h){ // todo } /* Add a process to the scheduler */ void Architecture::addProcess(Process* p){ p->setPNext(plist); plist=p; } /* Fork a process */ int Architecture::fork(process_st* info,process_st* father){ memcpy((char*)info,(char*)father,sizeof(process_st)); info->pd = pd_copy(father->pd); } /* Initialise a new process */ int Architecture::createProc(process_st* info, char* file, int argc, char** argv){ page *kstack; process_st *previous; process_st *current; char **param, **uparam; u32 stackp; u32 e_entry; int pid; int i; pid = 1; info->pid = pid; if (argc) { param = (char**) kmalloc(sizeof(char*) * (argc+1)); for (i=0 ; ipd = pd_create(); INIT_LIST_HEAD(&(info->pglist)); previous = arch.pcurrent->getPInfo(); current=info; asm("mov %0, %%eax; mov %%eax, %%cr3"::"m"((info->pd)->base->p_addr)); e_entry = (u32) load_elf(file,info); if (e_entry == 0) { for (i=0 ; ivinfo; current=arch.pcurrent->getPInfo(); asm("mov %0, %%eax ;mov %%eax, %%cr3"::"m" (current->regs.cr3)); pd_destroy(info->pd); return -1; } stackp = USER_STACK - 16; if (argc) { uparam = (char**) kmalloc(sizeof(char*) * argc); for (i=0 ; i=0 ; i--) { stackp -= sizeof(char*); *((char**) stackp) = uparam[i]; } stackp -= sizeof(char*); *((char**) stackp) = (char*) (stackp + 4); stackp -= sizeof(char*); *((int*) stackp) = argc; stackp -= sizeof(char*); for (i=0 ; iregs.ss = 0x33; info->regs.esp = stackp; info->regs.eflags = 0x0; info->regs.cs = 0x23; info->regs.eip = e_entry; info->regs.ds = 0x2B; info->regs.es = 0x2B; info->regs.fs = 0x2B; info->regs.gs = 0x2B; info->regs.cr3 = (u32) info->pd->base->p_addr; info->kstack.ss0 = 0x18; info->kstack.esp0 = (u32) kstack->v_addr + PAGESIZE - 16; info->regs.eax = 0; info->regs.ecx = 0; info->regs.edx = 0; info->regs.ebx = 0; info->regs.ebp = 0; info->regs.esi = 0; info->regs.edi = 0; info->b_heap = (char*) ((u32) info->e_bss & 0xFFFFF000) + PAGESIZE; info->e_heap = info->b_heap; info->signal = 0; for(i=0 ; i<32 ; i++) info->sigfn[i] = (char*) SIG_DFL; arch.pcurrent = (Process*) previous->vinfo; current=arch.pcurrent->getPInfo(); asm("mov %0, %%eax ;mov %%eax, %%cr3":: "m"(current->regs.cr3)); return 1; } // Destroy a process void Architecture::destroy_process(Process* pp){ disable_interrupt(); u16 kss; u32 kesp; u32 accr3; list_head *p, *n; page *pg; process_st *proccurrent=(arch.pcurrent)->getPInfo(); process_st *pidproc=pp->getPInfo(); // Switch page to the process to destroy asm("mov %0, %%eax ;mov %%eax, %%cr3"::"m" (pidproc->regs.cr3)); // Free process memory: // - pages used by the executable code // - user stack // - kernel stack // - pages directory // Free process memory list_for_each_safe(p, n, &pidproc->pglist) { pg = list_entry(p, struct page, list); release_page_frame(pg->p_addr); list_del(p); kfree(pg); } release_page_from_heap((char *) ((u32)pidproc->kstack.esp0 & 0xFFFFF000)); // Free pages directory asm("mov %0, %%eax; mov %%eax, %%cr3"::"m"(pd0)); pd_destroy(pidproc->pd); asm("mov %0, %%eax ;mov %%eax, %%cr3"::"m" (proccurrent->regs.cr3)); // Remove from the list if (plist==pp){ plist=pp->getPNext(); } else{ Process* l=plist; Process*ol=plist; while (l!=NULL){ if (l==pp){ ol->setPNext(pp->getPNext()); } ol=l; l=l->getPNext(); } } enable_interrupt(); } void Architecture::change_process_father(Process* pe, Process* pere){ Process* p=plist; Process* pn=NULL; while (p!=NULL){ pn=p->getPNext(); if (p->getPParent()==pe){ p->setPParent(pere); } p=pn; } } void Architecture::destroy_all_zombie(){ Process* p=plist; Process* pn=NULL; while (p!=NULL){ pn=p->getPNext(); if (p->getState()==ZOMBIE && p->getPid()!=1){ destroy_process(p); delete p; } p=pn; } } /* Set the syscall arguments */ void Architecture::setParam(u32 ret, u32 ret1, u32 ret2, u32 ret3,u32 ret4){ ret_reg[0]=ret; ret_reg[1]=ret1; ret_reg[2]=ret2; ret_reg[3]=ret3; ret_reg[4]=ret4; } /* Enable the interruption */ void Architecture::enable_interrupt(){ asm ("sti"); } /* Disable the interruption */ void Architecture::disable_interrupt(){ asm ("cli"); } /* Get a syscall argument */ u32 Architecture::getArg(u32 n){ if (n<5) return ret_reg[n]; else return 0; } /* Set the return value of syscall */ void Architecture::setRet(u32 ret){ stack_ptr[14] = ret; } ================================================ FILE: src/kernel/arch/x86/architecture.h ================================================ #ifndef ARCH_H #define ARCH_H #include #include /** Processor architecture class **/ class Architecture { public: /** architecture class functions **/ void init(); /* start the processor interface */ void reboot(); /* reboot the computer */ void shutdown(); /* shutdown the computer */ char* detect(); /* detect the type of processor */ void install_irq(int_handler h); /* install a interruption handler */ void addProcess(Process* p); /* add a process to the scheduler */ void enable_interrupt(); /* enable the interruption */ void disable_interrupt(); /* disable the interruption */ int createProc(process_st* info,char* file,int argc,char** argv); /* initialise a process */ void setParam(u32 ret,u32 ret1,u32 ret2, u32 ret3,u32 ret4); /* set the syscall arguments */ u32 getArg(u32 n); /* get a syscall argument */ void setRet(u32 ret); /* set the return value of syscall */ void initProc(); /* initialise the list of processes */ void destroy_process(Process* pp); /* destroy a processes */ void destroy_all_zombie(); void change_process_father(Process* p,Process* pere); int fork(process_st* info,process_st* father); /* fork a process */ /** architecture public class attributes */ Process* pcurrent; /* the current processes */ Process* plist; /* the chain list of processes */ private: /** architecture private attributes **/ u32 ret_reg[5]; Process* firstProc; }; /** standart starting architecture interface **/ extern Architecture arch; #endif ================================================ FILE: src/kernel/arch/x86/archprocess.h ================================================ #ifndef APROC_H #define APROC_H #include extern "C" { #define KERNELMODE 0 #define USERMODE 1 /** info processor structure for a process */ struct process_st { int pid; struct { u32 eax, ecx, edx, ebx; u32 esp, ebp, esi, edi; u32 eip, eflags; u32 cs:16, ss:16, ds:16, es:16, fs:16, gs:16; u32 cr3; } regs __attribute__ ((packed)); struct { u32 esp0; u16 ss0; } kstack __attribute__ ((packed)); // Caution: with task switch struct page_directory *pd; list_head pglist; char *b_exec; char *e_exec; char *b_bss; char *e_bss; char *b_heap; char *e_heap; u32 signal; void* sigfn[32]; void* vinfo; } __attribute__ ((packed)); } #endif ================================================ FILE: src/kernel/arch/x86/config.make ================================================ LDFLAG= -melf_i386 -static -L ./ -T ./arch/$(ARCH)/linker.ld SC=g++ FLAG= $(INCDIR) -g -O2 -w -trigraphs -fno-builtin -fno-exceptions -fno-stack-protector -O0 -m32 -fno-rtti -nostdlib -nodefaultlibs ASM=nasm ASMFLAG=-f elf -o LD=ld NM=nm OBJDUMP=objdump ================================================ FILE: src/kernel/arch/x86/io.cc ================================================ #include Io* Io::last_io=&io; /* definis la derniere io avant switch */ Io* Io::current_io=&io; /* interface actuel (clavier redirig vers celle ci) */ /* Video memory */ char* Io::vidmem = (char*)RAMSCREEN; /* Constructor */ Io::Io(){ real_screen = (char*)RAMSCREEN; } /* Destructor */ Io::Io(u32 flag){ real_screen=(char*)screen; } /* output byte */ void Io::outb(u32 ad,u8 v){ asmv("outb %%al, %%dx" :: "d" (ad), "a" (v));; } /* output word */ void Io::outw(u32 ad,u16 v){ asmv("outw %%ax, %%dx" :: "d" (ad), "a" (v)); } /* output word */ void Io::outl(u32 ad,u32 v){ asmv("outl %%eax, %%dx" : : "d" (ad), "a" (v)); } /* input byte */ u8 Io::inb(u32 ad){ u8 _v; \ asmv("inb %%dx, %%al" : "=a" (_v) : "d" (ad)); \ return _v; } /* input word */ u16 Io::inw(u32 ad){ u16 _v; \ asmv("inw %%dx, %%ax" : "=a" (_v) : "d" (ad)); \ return _v; } /* input word */ u32 Io::inl(u32 ad){ u32 _v; \ asmv("inl %%dx, %%eax" : "=a" (_v) : "d" (ad)); \ return _v; } /* renvoie la position x du curseur */ u32 Io::getX(){ return (u32)x; } /* renvoie la position y du curseur */ u32 Io::getY(){ return (u32)y; } /* x86 scroll up screen */ void Io::scrollup(unsigned int n) { unsigned char *video, *tmp; for (video = (unsigned char *) real_screen; video < (unsigned char *) SCREENLIM; video += 2) { tmp = (unsigned char *) (video + n * 160); if (tmp < (unsigned char *) SCREENLIM) { *video = *tmp; *(video + 1) = *(tmp + 1); } else { *video = 0; *(video + 1) = 0x07; } } y -= n; if (y < 0) y = 0; } /* sauvegarde la memoire video */ void Io::save_screen(){ memcpy(screen,(char*)RAMSCREEN,SIZESCREEN); real_screen=(char*)screen; } /* charge la memoire video */ void Io::load_screen(){ memcpy((char*)RAMSCREEN,screen,SIZESCREEN); real_screen=(char*)RAMSCREEN; } /* switch tty io */ void Io::switchtty(){ current_io->save_screen(); load_screen(); last_io=current_io; current_io=this; } /* put a byte on screen */ void Io::putc(char c){ kattr = 0x07; unsigned char *video; video = (unsigned char *) (real_screen+ 2 * x + 160 * y); if (c == 10) { x = 0; y++; } else if (c == 8) { if (x) { *(video + 1) = 0x0; x--; } } else if (c == 9) { x = x + 8 - (x % 8); } else if (c == 13) { x = 0; } else { *video = c; *(video + 1) = kattr; x++; if (x > 79) { x = 0; y++; } } if (y > 24) scrollup(y - 24); } /* change colors */ void Io::setColor(char fcol,char bcol){ fcolor=fcol; bcolor=bcol; } /* change cursor position */ void Io::setXY(char xc,char yc){ x=xc; y=yc; } /* clear screen */ void Io::clear(){ x=0; y=0; memset((char*)RAMSCREEN,0,SIZESCREEN); } /* put a string in screen */ void Io::print(const char *s, ...){ va_list ap; char buf[16]; int i, j, size, buflen, neg; unsigned char c; int ival; unsigned int uival; va_start(ap, s); while ((c = *s++)) { size = 0; neg = 0; if (c == 0) break; else if (c == '%') { c = *s++; if (c >= '0' && c <= '9') { size = c - '0'; c = *s++; } if (c == 'd') { ival = va_arg(ap, int); if (ival < 0) { uival = 0 - ival; neg++; } else uival = ival; itoa(buf, uival, 10); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; if (neg) print("-%s", buf); else print(buf); } else if (c == 'u') { uival = va_arg(ap, int); itoa(buf, uival, 10); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; print(buf); } else if (c == 'x' || c == 'X') { uival = va_arg(ap, int); itoa(buf, uival, 16); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; print("0x%s", buf); } else if (c == 'p') { uival = va_arg(ap, int); itoa(buf, uival, 16); size = 8; buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; print("0x%s", buf); } else if (c == 's') { print((char *) va_arg(ap, int)); } } else putc(c); } return; } /* put a byte on the console */ void Io::putctty(char c){ if (keystate==BUFFERED){ if (c == 8) { /* backspace */ if (keypos>0) { inbuf[keypos--] = 0; } } else if (c == 10) { /* newline */ inbuf[keypos++] = c; inbuf[keypos] = 0; inlock = 0; keypos = 0; } else { inbuf[keypos++] = c; } } else if (keystate==GETCHAR){ inbuf[0]=c; inbuf[1]=0; inlock = 0; keypos = 0; } } /* read a string in the console */ u32 Io::read(char* buf,u32 count){ if (count>1){ keystate=BUFFERED; } else{ //getchar keystate=GETCHAR; } asm("sti"); inlock=1; while (inlock == 1); asm("cli"); strncpy(buf,inbuf,count); return strlen(buf); } ================================================ FILE: src/kernel/arch/x86/io.h ================================================ #ifndef IO_H #define IO_H #include #define RAMSCREEN 0xB8000 /* debut de la memoire video */ #define SIZESCREEN 0xFA0 /* 4000, nombres d'octets d'une page texte */ #define SCREENLIM 0xB8FA0 /** Input/output class **/ class Io { public: Io(); Io(u32 flag); /** standart io color **/ enum Colour { Black =0, Blue =1, Green =2, Cyan =3, Red =4, Magenta =5, Orange =6, LightGrey =7, DarkGrey =8, LightBlue =9, LightGreen =10, LightCyan =11, LightRed =12, LightMagenta=13, Yellow =14, White =15 }; /** io class functions **/ void outb(u32 ad,u8 v); /* output byte */ void outw(u32 ad,u16 v); /* output word */ void outl(u32 ad,u32 v); /* output word */ u8 inb(u32 ad); /* input byte */ u16 inw(u32 ad); /* input word */ u32 inl(u32 ad); /* input word */ void putctty(char c); /* put a byte on the console */ u32 read(char* buf,u32 count); /* read a string in the console */ void putc(char c); /* put a byte on screen */ void setColor(char fcol,char bcol); /* change colors */ void setXY(char xc,char yc); /* change cursor position */ void clear(); /* clear screen */ void print(const char *s, ...); /* put a string in screen */ u32 getX(); u32 getY(); void switchtty(); /* change the io interface */ /** x86 functions **/ void scrollup(unsigned int n); void save_screen(); void load_screen(); enum ConsoleType { BUFFERED, GETCHAR }; static Io* current_io; static Io* last_io; private: /** x86 private attributes **/ char* real_screen; char screen[SIZESCREEN]; char inbuf[512]; /* console buffer */ int keypos; /* console read position */ int inlock; /* console state */ int keystate; /* console type keyboard */ char fcolor; /* console foreground color */ char bcolor; /* console background color */ char x; /* console x position */ char y; /* console y position */ char kattr; /* console attribut */ static char* vidmem; /* screen video memory */ }; /** standart starting io interface **/ extern Io io; #endif ================================================ FILE: src/kernel/arch/x86/linker.ld ================================================ OUTPUT_FORMAT(elf32-i386) OUTPUT_ARCH(i386) ENTRY (_start) SECTIONS{ . = 0x00100000; .text :{ *(.text) } .data ALIGN (0x1000) : { start_ctors = .; *(.ctor*) end_ctors = .; start_dtors = .; *(.dtor*) end_dtors = .; *(.data) } .rodata ALIGN (0x1000) : { *(.rodata) } .data ALIGN (0x1000) : { *(.data) } .bss : { sbss = .; *(COMMON) *(.bss) ebss = .; } } ================================================ FILE: src/kernel/arch/x86/start.asm ================================================ global _start, _kmain extern kmain, start_ctors, end_ctors, start_dtors, end_dtors %define MULTIBOOT_HEADER_MAGIC 0x1BADB002 %define MULTIBOOT_HEADER_FLAGS 0x00000003 %define CHECKSUM -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) ;-- Entry point _start: jmp start ;-- Multiboot header -- align 4 multiboot_header: dd MULTIBOOT_HEADER_MAGIC dd MULTIBOOT_HEADER_FLAGS dd CHECKSUM ;--/Multiboot header -- start: push ebx static_ctors_loop: mov ebx, start_ctors jmp .test .body: call [ebx] add ebx,4 .test: cmp ebx, end_ctors jb .body call kmain ; call kernel proper static_dtors_loop: mov ebx, start_dtors jmp .test .body: call [ebx] add ebx,4 .test: cmp ebx, end_dtors jb .body cli ; stop interrupts hlt ; halt the CPU ================================================ FILE: src/kernel/arch/x86/switch.asm ================================================ global do_switch do_switch: ; recuper l'adresse de *current mov esi, [esp] pop eax ; depile @current ; prepare les registres push dword [esi+4] ; eax push dword [esi+8] ; ecx push dword [esi+12] ; edx push dword [esi+16] ; ebx push dword [esi+24] ; ebp push dword [esi+28] ; esi push dword [esi+32] ; edi push dword [esi+48] ; ds push dword [esi+50] ; es push dword [esi+52] ; fs push dword [esi+54] ; gs ; enleve le mask du PIC mov al, 0x20 out 0x20, al ; charge table des pages mov eax, [esi+56] mov cr3, eax ; charge les registres pop gs pop fs pop es pop ds pop edi pop esi pop ebp pop ebx pop edx pop ecx pop eax ; retourne iret ================================================ FILE: src/kernel/arch/x86/vmm.cc ================================================ #include extern "C" { char *kern_heap; list_head kern_free_vm; u32 *pd0 = (u32 *) KERN_PDIR; /* kernel page directory */ char *pg0 = (char *) 0; /* kernel page 0 (4MB) */ char *pg1 = (char *) KERN_PG_1; /* kernel page 1 (4MB) 0x400000*/ char *pg1_end = (char *) KERN_PG_1_LIM; /* limite de la page 1 0x800000*/ u8 mem_bitmap[RAM_MAXPAGE / 8]; /* bitmap allocation de pages (1 Go) */ u32 kmalloc_used = 0; /* * Parcours le bitmap a la recherche d'une page libre et la marque * comme utilisee avant de retourner son adresse physique. */ char* get_page_frame(void) { int byte, bit; int page = -1; for (byte = 0; byte < RAM_MAXPAGE / 8; byte++) if (mem_bitmap[byte] != 0xFF) for (bit = 0; bit < 8; bit++) if (!(mem_bitmap[byte] & (1 << bit))) { page = 8 * byte + bit; set_page_frame_used(page); return (char *) (page * PAGESIZE); } return (char *) -1; } /* * Recherche une page virtuelle libre dans l'espace d'adresses virtuelles du * noyau. La fonction demande ensuite une page physique libre a associer. * NOTE: ces pages sont dans l'espace d'adressage du noyau. Celui-ci est mis a * jour. */ page* get_page_from_heap(void) { page *pg; vm_area *area; char *v_addr, *p_addr; /* Prend une page physique libre */ p_addr = get_page_frame(); if ((int)(p_addr) < 0) { io.print ("PANIC: get_page_from_heap(): no page frame available. System halted !\n"); } /* Verifie si il y a une page virtuelle libre */ if (list_empty(&kern_free_vm)) { io.print ("PANIC: get_page_from_heap(): not memory left in page heap. System halted !\n"); } /* Prend la premiere page virtuelle libre de disponible */ area = list_first_entry(&kern_free_vm, vm_area, list); v_addr = area->vm_start; /* Met a jour la liste de pages libres dans l'espace virtuel du noyau */ area->vm_start += PAGESIZE; if (area->vm_start == area->vm_end) { list_del(&area->list); kfree(area); } /* Met a jour l'espace d'adressage du noyau */ pd0_add_page(v_addr, p_addr, 0); /* Renvoie la page */ pg = (page*) kmalloc(sizeof(page)); pg->v_addr = v_addr; pg->p_addr = p_addr; pg->list.next = 0; pg->list.prev = 0; return pg; } int release_page_from_heap(char *v_addr) { struct vm_area *next_area, *prev_area, *new_area; char *p_addr; /* Retrouve la page frame associee a v_addr et la libere */ p_addr = get_p_addr(v_addr); if (p_addr) { release_page_frame(p_addr); } else { io.print("WARNING: release_page_from_heap(): no page frame associated with v_addr %x\n", v_addr); return 1; } /* Met a jour le repertoire de pages */ pd_remove_page(v_addr); /* Met a jour la liste d'adresses virtuelles libres */ list_for_each_entry(next_area, &kern_free_vm, list) { if (next_area->vm_start > v_addr) break; } prev_area = list_entry(next_area->list.prev, struct vm_area, list); if (prev_area->vm_end == v_addr) { prev_area->vm_end += PAGESIZE; if (prev_area->vm_end == next_area->vm_start) { prev_area->vm_end = next_area->vm_end; list_del(&next_area->list); kfree(next_area); } } else if (next_area->vm_start == v_addr + PAGESIZE) { next_area->vm_start = v_addr; } else if (next_area->vm_start > v_addr + PAGESIZE) { new_area = (struct vm_area*) kmalloc(sizeof(struct vm_area)); new_area->vm_start = v_addr; new_area->vm_end = v_addr + PAGESIZE; list_add(&new_area->list, &prev_area->list); } else { io.print ("\nPANIC: release_page_from_heap(): corrupted linked list. System halted !\n"); asm("hlt"); } return 0; } /* * Initialise le bitmap memoire et cree le repertoire de pages du kernel. * Utilise un identity mapping tel que vaddr = paddr sur 4Mo */ void Memory_init(u32 high_mem) { int pg, pg_limit; unsigned long i; struct vm_area *p; struct vm_area *pm; /* Numero de la derniere page */ pg_limit = (high_mem * 1024) / PAGESIZE; /* Initialisation du bitmap de pages physiques */ for (pg = 0; pg < pg_limit / 8; pg++) mem_bitmap[pg] = 0; for (pg = pg_limit / 8; pg < RAM_MAXPAGE / 8; pg++) mem_bitmap[pg] = 0xFF; /* Pages reservees pour le noyau */ for (pg = PAGE(0x0); pg < (int)(PAGE((u32) pg1_end)); pg++) { set_page_frame_used(pg); } /* Initialisation du repertoire de pages */ pd0[0] = ((u32) pg0 | (PG_PRESENT | PG_WRITE | PG_4MB)); pd0[1] = ((u32) pg1 | (PG_PRESENT | PG_WRITE | PG_4MB)); for (i = 2; i < 1023; i++) pd0[i] = ((u32) pg1 + PAGESIZE * i) | (PG_PRESENT | PG_WRITE); // Page table mirroring magic trick ! pd0[1023] = ((u32) pd0 | (PG_PRESENT | PG_WRITE)); /* Passe en mode pagination */ asm(" mov %0, %%eax \n \ mov %%eax, %%cr3 \n \ mov %%cr4, %%eax \n \ or %2, %%eax \n \ mov %%eax, %%cr4 \n \ mov %%cr0, %%eax \n \ or %1, %%eax \n \ mov %%eax, %%cr0"::"m"(pd0), "i"(PAGING_FLAG), "i"(PSE_FLAG)); /* Initialisation du heap du noyau utilise par kmalloc */ kern_heap = (char *) KERN_HEAP; ksbrk(1); /* Initialisation de la liste d'adresses virtuelles libres */ p = (struct vm_area*) kmalloc(sizeof(struct vm_area)); p->vm_start = (char*) KERN_PG_HEAP; p->vm_end = (char*) KERN_PG_HEAP_LIM; INIT_LIST_HEAD(&kern_free_vm); list_add(&p->list, &kern_free_vm); arch.initProc(); return; } /* * Cree et initialise un rep. de pages pour une tache */ struct page_directory *pd_create(void) { struct page_directory *pd; u32 *pdir; int i; /* Prend et initialise une page pour le Page Directory */ pd = (struct page_directory *) kmalloc(sizeof(struct page_directory)); pd->base = get_page_from_heap(); /* * Espace kernel. Les v_addr < USER_OFFSET sont adressees par la table * de pages du noyau (pd0[]). */ pdir = (u32 *) pd->base->v_addr; for (i = 0; i < 256; i++) pdir[i] = pd0[i]; /* Espace utilisateur */ for (i = 256; i < 1023; i++) pdir[i] = 0; /* Page table mirroring magic trick !... */ pdir[1023] = ((u32) pd->base->p_addr | (PG_PRESENT | PG_WRITE)); /* Mise a jour de la liste des tables de pages de l'espace utilisateur */ INIT_LIST_HEAD(&pd->pt); return pd; } void page_copy_in_pd(process_st* current,u32 virtadr){ struct page *pg; pg = (struct page *) kmalloc(sizeof(struct page)); pg->p_addr = get_page_frame(); /* todo copier le contenus de l'autre page */ pg->v_addr = (char *) (virtadr & 0xFFFFF000); list_add(&pg->list, ¤t->pglist); pd_add_page(pg->v_addr, pg->p_addr, PG_USER, current->pd); } /* * Cree et initialise un rep. de pages pour une tache en copie d'une autre (ne marche pas encore ) */ struct page_directory *pd_copy(struct page_directory * pdfather) { struct page_directory *pd; u32 *pdir; int i; /* Prend et initialise une page pour le Page Directory */ pd = (struct page_directory *) kmalloc(sizeof(struct page_directory)); pd->base = get_page_from_heap(); /* * Espace kernel. Les v_addr < USER_OFFSET sont adressees par la table * de pages du noyau (pd0[]). */ pdir = (u32 *) pd->base->v_addr; for (i = 0; i < 256; i++) pdir[i] = pd0[i]; /* Espace utilisateur */ for (i = 256; i < 1023; i++) pdir[i] = 0; /* Page table mirroring magic trick !... */ pdir[1023] = ((u32) pd->base->p_addr | (PG_PRESENT | PG_WRITE)); /* Mise a jour de la liste des tables de pages de l'espace utilisateur */ INIT_LIST_HEAD(&pd->pt); return pd; } int pd_destroy(struct page_directory *pd) { struct page *pg; struct list_head *p, *n; /* Libere les pages correspondant aux tables */ list_for_each_safe(p, n, &pd->pt) { pg = list_entry(p, struct page, list); release_page_from_heap(pg->v_addr); list_del(p); kfree(pg); } /* Libere la page correspondant au repertoire */ release_page_from_heap(pd->base->v_addr); kfree(pd); return 0; } /* * Met a jour l'espace d'adressage du noyau. * NOTE : cet espace est commun a tous les repertoires de pages. */ int pd0_add_page(char *v_addr, char *p_addr, int flags) { u32 *pde; u32 *pte; if (v_addr > (char *) USER_OFFSET) { io.print("ERROR: pd0_add_page(): %p is not in kernel space !\n", v_addr); return 0; } /* On verifie que la table de page est bien presente */ pde = (u32 *) (0xFFFFF000 | (((u32) v_addr & 0xFFC00000) >> 20)); if ((*pde & PG_PRESENT) == 0) { //error } /* Modification de l'entree dans la table de page */ pte = (u32 *) (0xFFC00000 | (((u32) v_addr & 0xFFFFF000) >> 10)); *pte = ((u32) p_addr) | (PG_PRESENT | PG_WRITE | flags); set_page_frame_used(p_addr); return 0; } /* * Met a jour le repertoire de pages courant * input: * v_addr : adresse lineaire de la page * p_addr : adresse physique de la page allouee * pd : structure qui doit etre mise a jour avec les pages allouees */ int pd_add_page(char *v_addr, char *p_addr, int flags, struct page_directory *pd) { u32 *pde; /* adresse virtuelle de l'entree du repertoire de pages */ u32 *pte; /* adresse virtuelle de l'entree de la table de pages */ u32 *pt; /* adresse virtuelle de la table de pages */ struct page *pg; int i; //// io.print("DEBUG: pd_add_page(%p, %p, %d)\n", v_addr, p_addr, flags); /* DEBUG */ /* * La derniere entree du PageDir pointe sur lui-meme. * Les adresses commencant par 0xFFC00000 utilisent cette entree et il * s'ensuite que : * - les 10 bits en 0x003FF000 sont un index dans le PageDir et designent une * PageTable. Les 12 derniers bits permettent de modifier une entree du PageTable * - l'adresse 0xFFFFF000 designe le PageDir lui-meme */ pde = (u32 *) (0xFFFFF000 | (((u32) v_addr & 0xFFC00000) >> 20)); /* * On cree la table de pages correspondante si elle n'est pas presente */ if ((*pde & PG_PRESENT) == 0) { /* * Allocation d'une page pour y mettre la table. */ pg = get_page_from_heap(); /* On initialise la nouvelle table de pages */ pt = (u32 *) pg->v_addr; for (i = 1; i < 1024; i++) pt[i] = 0; /* On ajoute l'entree correspondante dans le repertoire */ *pde = (u32) pg->p_addr | (PG_PRESENT | PG_WRITE | flags); /* On rajoute la nouvelle page dans la structure passee en parametre */ if (pd) list_add(&pg->list, &pd->pt); } pte = (u32 *) (0xFFC00000 | (((u32) v_addr & 0xFFFFF000) >> 10)); *pte = ((u32) p_addr) | (PG_PRESENT | PG_WRITE | flags); return 0; } int pd_remove_page(char *v_addr) { u32 *pte; if (get_p_addr(v_addr)) { pte = (u32 *) (0xFFC00000 | (((u32) v_addr & 0xFFFFF000) >> 10)); *pte = (*pte & (~PG_PRESENT)); asm("invlpg %0"::"m"(v_addr)); } return 0; } /* * Retourne l'adresse physique de la page associee a l'adresse virtuelle passee * en argument */ char *get_p_addr(char *v_addr) { u32 *pde; /* adresse virtuelle de l'entree du repertoire de pages */ u32 *pte; /* adresse virtuelle de l'entree de la table de pages */ pde = (u32 *) (0xFFFFF000 | (((u32) v_addr & 0xFFC00000) >> 20)); if ((*pde & PG_PRESENT)) { pte = (u32 *) (0xFFC00000 | (((u32) v_addr & 0xFFFFF000) >> 10)); if ((*pte & PG_PRESENT)) return (char *) ((*pte & 0xFFFFF000) + (VADDR_PG_OFFSET((u32) v_addr))); } return 0; } } void Vmm::kmap(u32 phy,u32 virt){ pd0_add_page((char*)phy,(char*)virt,PG_USER); } void Vmm::init(u32 high){ Memory_init(high); } ================================================ FILE: src/kernel/arch/x86/vmm.h ================================================ #ifndef VMM_H #define VMM_H #include #include #include #include extern "C" { struct page { char *v_addr; char *p_addr; list_head list; }; struct page_directory { page *base; list_head pt; }; struct vm_area { char *vm_start; char *vm_end; /* exclude */ list_head list; }; typedef page_directory proc_memory; /* Pointe sur le sommet du heap noyau */ extern char *kern_heap; /* Pointe sur le debut de la liste des pages libres du noyau */ extern list_head kern_free_vm; extern u32 *pd0; extern u8 mem_bitmap[]; extern u32 kmalloc_used; /* Marque une page comme utilisee / libre dans le bitmap */ #define set_page_frame_used(page) mem_bitmap[((u32) page)/8] |= (1 << (((u32) page)%8)) #define release_page_frame(p_addr) mem_bitmap[((u32) p_addr/PAGESIZE)/8] &= ~(1 << (((u32) p_addr/PAGESIZE)%8)) /* Selectionne une page libre dans le bitmap */ char *get_page_frame(void); /* Selectionne / libere une page libre dans le bitmap et l'associe a une page * virtuelle libre du heap */ struct page *get_page_from_heap(void); int release_page_from_heap(char *); /* Initialise les structures de donnees de gestion de la memoire */ void Memory_init(u32 high_mem); /* Cree un repertoire de page pour un processus */ struct page_directory *pd_create(void); int pd_destroy(struct page_directory *); struct page_directory *pd_copy(struct page_directory * pdfather); /* Ajoute une entree dans l'espace du noyau */ int pd0_add_page(char *, char *, int); /* Ajoute / enleve une entree dans le repertoire de pages courant */ int pd_add_page(char *, char *, int, struct page_directory *); int pd_remove_page(char *); /* Retourne l'adresse physique associee a une adresse virtuelle */ char *get_p_addr(char *); #define KMALLOC_MINSIZE 16 struct kmalloc_header { unsigned long size:31; /* taille totale de l'enregistrement */ unsigned long used:1; } __attribute__ ((packed)); } class Vmm { public: void init(u32 high); proc_memory* createPM(); /* Create page directory for a process */ void switchPM(proc_memory* ad); /* Switch page directory for a process */ void map(proc_memory* ad,u32 phy,u32 adr); /* map a physical page memory in virtual space */ void kmap(u32 phy,u32 virt); }; extern Vmm vmm; #endif ================================================ FILE: src/kernel/arch/x86/x86.cc ================================================ #include #include #include extern "C" { regs_t cpu_cpuid(int code) { regs_t r; asm volatile("cpuid":"=a"(r.eax),"=b"(r.ebx), "=c"(r.ecx),"=d"(r.edx):"0"(code)); return r; } u32 cpu_vendor_name(char *name) { regs_t r = cpu_cpuid(0x00); char line1[5]; line1[0] = ((char *) &r.ebx)[0]; line1[1] = ((char *) &r.ebx)[1]; line1[2] = ((char *) &r.ebx)[2]; line1[3] = ((char *) &r.ebx)[3]; line1[4] = '\0'; char line2[5]; line2[0] = ((char *) &r.ecx)[0]; line2[1] = ((char *) &r.ecx)[1]; line2[2] = ((char *) &r.ecx)[2]; line2[3] = ((char *) &r.ecx)[3]; line2[4] = '\0'; char line3[5]; line3[0] = ((char *) &r.edx)[0]; line3[1] = ((char *) &r.edx)[1]; line3[2] = ((char *) &r.edx)[2]; line3[3] = ((char *) &r.edx)[3]; line3[4] = '\0'; strcpy(name, line1); strcat(name, line3); strcat(name, line2); return 15; } void schedule(); idtdesc kidt[IDTSIZE]; /* IDT table */ int_desc intt[IDTSIZE]; /* Interruptions functions tables */ gdtdesc kgdt[GDTSIZE]; /* GDT */ tss default_tss; gdtr kgdtr; /* GDTR */ idtr kidtr; /* IDTR registry */ u32 * stack_ptr=0; /* * 'init_desc' initialize a segment descriptor in gdt or ldt. * 'desc' is a pointer to the address */ void init_gdt_desc(u32 base, u32 limite, u8 acces, u8 other,struct gdtdesc *desc) { desc->lim0_15 = (limite & 0xffff); desc->base0_15 = (base & 0xffff); desc->base16_23 = (base & 0xff0000) >> 16; desc->acces = acces; desc->lim16_19 = (limite & 0xf0000) >> 16; desc->other = (other & 0xf); desc->base24_31 = (base & 0xff000000) >> 24; return; } /* * This function initialize the GDT after the kernel is loaded. */ void init_gdt(void) { default_tss.debug_flag = 0x00; default_tss.io_map = 0x00; default_tss.esp0 = 0x1FFF0; default_tss.ss0 = 0x18; /* initialize gdt segments */ init_gdt_desc(0x0, 0x0, 0x0, 0x0, &kgdt[0]); init_gdt_desc(0x0, 0xFFFFF, 0x9B, 0x0D, &kgdt[1]); /* code */ init_gdt_desc(0x0, 0xFFFFF, 0x93, 0x0D, &kgdt[2]); /* data */ init_gdt_desc(0x0, 0x0, 0x97, 0x0D, &kgdt[3]); /* stack */ init_gdt_desc(0x0, 0xFFFFF, 0xFF, 0x0D, &kgdt[4]); /* ucode */ init_gdt_desc(0x0, 0xFFFFF, 0xF3, 0x0D, &kgdt[5]); /* udata */ init_gdt_desc(0x0, 0x0, 0xF7, 0x0D, &kgdt[6]); /* ustack */ init_gdt_desc((u32) & default_tss, 0x67, 0xE9, 0x00, &kgdt[7]); /* descripteur de tss */ /* initialize the gdtr structure */ kgdtr.limite = GDTSIZE * 8; kgdtr.base = GDTBASE; /* copy the gdtr to its memory area */ memcpy((char *) kgdtr.base, (char *) kgdt, kgdtr.limite); /* load the gdtr registry */ asm("lgdtl (kgdtr)"); /* initiliaz the segments */ asm(" movw $0x10, %ax \n \ movw %ax, %ds \n \ movw %ax, %es \n \ movw %ax, %fs \n \ movw %ax, %gs \n \ ljmp $0x08, $next \n \ next: \n"); } void init_idt_desc(u16 select, u32 offset, u16 type, struct idtdesc *desc) { desc->offset0_15 = (offset & 0xffff); desc->select = select; desc->type = type; desc->offset16_31 = (offset & 0xffff0000) >> 16; return; } extern void _asm_int_0(); extern void _asm_int_1(); extern void _asm_syscalls(); extern void _asm_exc_GP(void); extern void _asm_exc_PF(void); extern void _asm_schedule(); void do_syscalls(int num){ u32 ret,ret1,ret2,ret3,ret4; asm("mov %%ebx, %0": "=m"(ret):); asm("mov %%ecx, %0": "=m"(ret1):); asm("mov %%edx, %0": "=m"(ret2):); asm("mov %%edi, %0": "=m"(ret3):); asm("mov %%esi, %0": "=m"(ret4):); //io.print("syscall %d \n",num); /*io.print(" ebx : %x ",ret); io.print(" ecx : %x \n",ret1); io.print(" edx : %x ",ret2); io.print(" edi : %x \n",ret3);*/ arch.setParam(ret,ret1,ret2,ret3,ret4); asm("cli"); asm("mov %%ebp, %0": "=m"(stack_ptr):); syscall.call(num); asm("sti"); } void isr_kbd_int(void) { u8 i; static int lshift_enable; static int rshift_enable; static int alt_enable; static int ctrl_enable; do { i = io.inb(0x64); } while ((i & 0x01) == 0); i = io.inb(0x60); i--; if (i < 0x80) { /* touche enfoncee */ switch (i) { case 0x29: lshift_enable = 1; break; case 0x35: rshift_enable = 1; break; case 0x1C: ctrl_enable = 1; break; case 0x37: alt_enable = 1; break; default: if(alt_enable==1) { io.putctty(kbdmap[i * 4 + 2]); if (&io != io.current_io) io.current_io->putctty(kbdmap[i * 4 + 2]); } else if(lshift_enable == 1 || rshift_enable == 1) { io.putctty(kbdmap[i * 4 + 1]); if (&io != io.current_io) io.current_io->putctty(kbdmap[i * 4 + 1]); } else { io.putctty(kbdmap[i * 4]); if (&io != io.current_io) io.current_io->putctty(kbdmap[i * 4]); } break; //io.print("sancode: %x \n",i * 4 + (lshift_enable || rshift_enable)); /*io.putctty(kbdmap[i * 4 + (lshift_enable || rshift_enable)]); //replac depuis la 10.4.6 if (&io != io.current_io) io.current_io->putctty(kbdmap[i * 4 + (lshift_enable || rshift_enable)]);*/ break; } } else { /* touche relachee */ i -= 0x80; switch (i) { case 0x29: lshift_enable = 0; break; case 0x35: rshift_enable = 0; break; case 0x1C: ctrl_enable = 0; break; case 0x37: alt_enable = 0; break; } } io.outb(0x20,0x20); io.outb(0xA0,0x20); } void isr_default_int(int id) { static int tic = 0; static int sec = 0; switch (id){ case 1: isr_kbd_int(); break; default: return; } io.outb(0x20,0x20); io.outb(0xA0,0x20); } void isr_schedule_int() { static int tic = 0; static int sec = 0; tic++; if (tic % 100 == 0) { sec++; tic = 0; } schedule(); io.outb(0x20,0x20); io.outb(0xA0,0x20); } void isr_GP_exc(void) { io.print("\n General protection fault !\n"); if (arch.pcurrent!=NULL){ io.print("The processus %s have to be killed !\n\n",(arch.pcurrent)->getName()); (arch.pcurrent)->exit(); schedule(); } else{ io.print("The kernel have to be killed !\n\n"); asm("hlt"); } } void isr_PF_exc(void) { u32 faulting_addr, code; u32 eip; struct page *pg; u32 stack; asm(" movl 60(%%ebp), %%eax \n \ mov %%eax, %0 \n \ mov %%cr2, %%eax \n \ mov %%eax, %1 \n \ movl 56(%%ebp), %%eax \n \ mov %%eax, %2" : "=m"(eip), "=m"(faulting_addr), "=m"(code)); asm("mov %%ebp, %0": "=m"(stack):); //io.print("#PF : %x \n",faulting_addr); //for (;;); if (arch.pcurrent==NULL) return; process_st* current=arch.pcurrent->getPInfo(); if (faulting_addr >= USER_OFFSET && faulting_addr <= USER_STACK) { pg = (struct page *) kmalloc(sizeof(struct page)); pg->p_addr = get_page_frame(); pg->v_addr = (char *) (faulting_addr & 0xFFFFF000); list_add(&pg->list, ¤t->pglist); pd_add_page(pg->v_addr, pg->p_addr, PG_USER, current->pd); } else { io.print("\n"); io.print("No autorized memory acces on : %p (eip:%p,code:%p)\n", faulting_addr,eip, code); io.print("heap=%x, heap_limit=%x, stack=%x\n",kern_heap,KERN_HEAP_LIM,stack); if (arch.pcurrent!=NULL){ io.print("The processus %s have to be killed !\n\n",(arch.pcurrent)->getName()); (arch.pcurrent)->exit(); schedule(); } else{ io.print("The kernel have to be killed !\n\n"); asm("hlt"); } } } /* * Init IDT after kernel is loaded */ void init_idt(void) { /* Init irq */ int i; for (i = 0; i < IDTSIZE; i++) init_idt_desc(0x08, (u32)_asm_schedule, INTGATE, &kidt[i]); // /* Vectors 0 -> 31 are for exceptions */ init_idt_desc(0x08, (u32) _asm_exc_GP, INTGATE, &kidt[13]); /* #GP */ init_idt_desc(0x08, (u32) _asm_exc_PF, INTGATE, &kidt[14]); /* #PF */ init_idt_desc(0x08, (u32) _asm_schedule, INTGATE, &kidt[32]); init_idt_desc(0x08, (u32) _asm_int_1, INTGATE, &kidt[33]); init_idt_desc(0x08, (u32) _asm_syscalls, TRAPGATE, &kidt[48]); init_idt_desc(0x08, (u32) _asm_syscalls, TRAPGATE, &kidt[128]); //48 kidtr.limite = IDTSIZE * 8; kidtr.base = IDTBASE; /* Copy the IDT to the memory */ memcpy((char *) kidtr.base, (char *) kidt, kidtr.limite); /* Load the IDTR registry */ asm("lidtl (kidtr)"); } void init_pic(void) { /* Initialization of ICW1 */ io.outb(0x20, 0x11); io.outb(0xA0, 0x11); /* Initialization of ICW2 */ io.outb(0x21, 0x20); /* start vector = 32 */ io.outb(0xA1, 0x70); /* start vector = 96 */ /* Initialization of ICW3 */ io.outb(0x21, 0x04); io.outb(0xA1, 0x02); /* Initialization of ICW4 */ io.outb(0x21, 0x01); io.outb(0xA1, 0x01); /* mask interrupts */ io.outb(0x21, 0x0); io.outb(0xA1, 0x0); } #define DEBUG_REG(a) io.print(" %s : %x",#a,p->regs.a) void schedule(){ Process* pcurrent=arch.pcurrent; Process*plist=arch.plist; if (pcurrent==0) return; if (pcurrent->getPNext() == 0 && plist==pcurrent) //si le proc est seul return; process_st* current=pcurrent->getPInfo(); process_st *p; int i, newpid; /* Stocke dans stack_ptr le pointeur vers les registres sauvegardes */ asm("mov (%%ebp), %%eax; mov %%eax, %0": "=m"(stack_ptr):); //asm("mov (%%eip), %%eax; mov %%eax, %0": "=m"(current->regs.eip):); //io.print("stack_ptr : %x \n",stack_ptr); /* Sauver les registres du processus courant */ current->regs.eflags = stack_ptr[16]; current->regs.cs = stack_ptr[15]; current->regs.eip = stack_ptr[14]; current->regs.eax = stack_ptr[13]; current->regs.ecx = stack_ptr[12]; current->regs.edx = stack_ptr[11]; current->regs.ebx = stack_ptr[10]; current->regs.ebp = stack_ptr[8]; current->regs.esi = stack_ptr[7]; current->regs.edi = stack_ptr[6]; current->regs.ds = stack_ptr[5]; current->regs.es = stack_ptr[4]; current->regs.fs = stack_ptr[3]; current->regs.gs = stack_ptr[2]; /* * Sauvegarde le contenu des registres de pile (ss, esp) * au moment de l'interruption. Necessaire car le processeur * empile ou non ces valeurs selon le contexte de l'interruption. */ if (current->regs.cs != 0x08) { /* mode utilisateur */ current->regs.esp = stack_ptr[17]; current->regs.ss = stack_ptr[18]; } else { /* pendant un appel systeme */ current->regs.esp = stack_ptr[9] + 12; /* vaut : &stack_ptr[17] */ current->regs.ss = default_tss.ss0; } /* Sauver le TSS de l'ancien processus */ current->kstack.ss0 = default_tss.ss0; current->kstack.esp0 = default_tss.esp0; //io.print("schedule %s ",pcurrent->getName()); pcurrent=pcurrent->schedule(); p = pcurrent->getPInfo(); //io.print("to %s \n",pcurrent->getName()); /*DEBUG_REG(eax); DEBUG_REG(ebx); DEBUG_REG(ecx); DEBUG_REG(edx);*/ /*DEBUG_REG(esp); io.print("\t"); DEBUG_REG(ebp); io.print("\n");*/ //DEBUG_REG(esi); //DEBUG_REG(edi); //DEBUG_REG(eip); io.print("\t"); /*DEBUG_REG(eflags); DEBUG_REG(cs); DEBUG_REG(ss); DEBUG_REG(ds); DEBUG_REG(es); DEBUG_REG(fs); DEBUG_REG(gs); DEBUG_REG(cr3); io.print("\n");*/ /* Commutation */ if (p->regs.cs != 0x08) switch_to_task(p, USERMODE); else switch_to_task(p, KERNELMODE); } /* * switch_to_task(): Prepare la commutation de tache effectuee par do_switch(). * Le premier parametre indique le pid du processus a charger. * Le mode indique si ce processus etait en mode utilisateur ou en mode kernel * quand il a ete precedement interrompu par le scheduler. * L'empilement des registres sur la pile change selon le cas. */ void switch_to_task(process_st* current, int mode) { u32 kesp, eflags; u16 kss, ss, cs; int sig; /* Traite les signaux */ if ((sig = dequeue_signal(current->signal))) handle_signal(sig); /* Charge le TSS du nouveau processus */ default_tss.ss0 = current->kstack.ss0; default_tss.esp0 = current->kstack.esp0; /* * Empile les registres ss, esp, eflags, cs et eip necessaires a la * commutation. Ensuite, la fonction do_switch() restaure les * registres, la table de page du nouveau processus courant et commute * avec l'instruction iret. */ ss = current->regs.ss; cs = current->regs.cs; eflags = (current->regs.eflags | 0x200) & 0xFFFFBFFF; /* Prepare le changement de pile noyau */ if (mode == USERMODE) { kss = current->kstack.ss0; kesp = current->kstack.esp0; } else { /* KERNELMODE */ kss = current->regs.ss; kesp = current->regs.esp; } //io.print("switch to %x \n",current->regs.eip); asm(" mov %0, %%ss; \ mov %1, %%esp; \ cmp %[KMODE], %[mode]; \ je nextt; \ push %2; \ push %3; \ nextt: \ push %4; \ push %5; \ push %6; \ push %7; \ ljmp $0x08, $do_switch" :: \ "m"(kss), \ "m"(kesp), \ "m"(ss), \ "m"(current->regs.esp), \ "m"(eflags), \ "m"(cs), \ "m"(current->regs.eip), \ "m"(current), \ [KMODE] "i"(KERNELMODE), \ [mode] "g"(mode) ); } int dequeue_signal(int mask) { int sig; if (mask) { sig = 1; while (!(mask & 1)) { mask = mask >> 1; sig++; } } else sig = 0; return sig; } int handle_signal(int sig) { Process* pcurrent=arch.pcurrent; if (pcurrent==0) return 0; process_st* current=pcurrent->getPInfo(); u32 *esp; //io.print("signal> handle signal : signal %d for process %d\n", sig, pcurrent->getPid()); if (current->sigfn[sig] == (void*) SIG_IGN) { clear_signal(&(current->signal), sig); } else if (current->sigfn[sig] == (void*) SIG_DFL) { switch(sig) { case SIGHUP : case SIGINT : case SIGQUIT : asm("mov %0, %%eax; mov %%eax, %%cr3"::"m"(current->regs.cr3)); pcurrent->exit(); break; case SIGCHLD : break; default : clear_signal(&(current->signal), sig); } } else { esp = (u32*) current->regs.esp - 20; asm("mov %0, %%eax; mov %%eax, %%cr3"::"m"(current->regs.cr3)); // Code assembleur qui appelle sys_sigreturn() esp[19] = 0x0030CD00; esp[18] = 0x00000EB8; // Sauvegarde des registres esp[17] = current->kstack.esp0; esp[16] = current->regs.ss; esp[15] = current->regs.esp; esp[14] = current->regs.eflags; esp[13] = current->regs.cs; esp[12] = current->regs.eip; esp[11] = current->regs.eax; esp[10] = current->regs.ecx; esp[9] = current->regs.edx; esp[8] = current->regs.ebx; esp[7] = current->regs.ebp; esp[6] = current->regs.esi; esp[5] = current->regs.edi; esp[4] = current->regs.ds; esp[3] = current->regs.es; esp[2] = current->regs.fs; esp[1] = current->regs.gs; // Adresse de retour pour %eip esp[0] = (u32) &esp[18]; current->regs.esp = (u32) esp; current->regs.eip = (u32) current->sigfn[sig]; // Efface le signal et retablit le handler par defaut * current->sigfn[sig] = (void*) SIG_DFL; if (sig != SIGCHLD) clear_signal(&(current->signal), sig); } return 0; } } ================================================ FILE: src/kernel/arch/x86/x86.h ================================================ #ifndef __X86__ #define __X86__ #include #define IDTSIZE 0xFF /* nombre max. de descripteurs dans la table */ #define GDTSIZE 0xFF /* nombre max. de descripteurs dans la table */ #define IDTBASE 0x00000000 /* addr. physique ou doit resider la IDT */ #define GDTBASE 0x00000800 /* addr. physique ou doit resider la gdt */ #define INTGATE 0x8E00 /* utilise pour gerer les interruptions */ #define TRAPGATE 0xEF00 /* utilise pour faire des appels systemes */ #define KERN_PDIR 0x00001000 #define KERN_STACK 0x0009FFF0 #define KERN_BASE 0x00100000 #define KERN_PG_HEAP 0x00800000 #define KERN_PG_HEAP_LIM 0x10000000 #define KERN_HEAP 0x10000000 #define KERN_HEAP_LIM 0x40000000 #define USER_OFFSET 0x40000000 #define USER_STACK 0xE0000000 #define KERN_PG_1 0x400000 #define KERN_PG_1_LIM 0x800000 #define VADDR_PD_OFFSET(addr) ((addr) & 0xFFC00000) >> 22 #define VADDR_PT_OFFSET(addr) ((addr) & 0x003FF000) >> 12 #define VADDR_PG_OFFSET(addr) (addr) & 0x00000FFF #define PAGE(addr) (addr) >> 12 #define PAGING_FLAG 0x80000000 /* CR0 - bit 31 */ #define PSE_FLAG 0x00000010 /* CR4 - bit 4 */ #define PG_PRESENT 0x00000001 /* page directory / table */ #define PG_WRITE 0x00000002 #define PG_USER 0x00000004 #define PG_4MB 0x00000080 #define PAGESIZE 4096 #define RAM_MAXSIZE 0x100000000 #define RAM_MAXPAGE 0x100000 /* Descripteur de segment */ struct gdtdesc { u16 lim0_15; u16 base0_15; u8 base16_23; u8 acces; u8 lim16_19:4; u8 other:4; u8 base24_31; } __attribute__ ((packed)); /* Registre GDTR */ struct gdtr { u16 limite; u32 base; } __attribute__ ((packed)); struct tss { u16 previous_task, __previous_task_unused; u32 esp0; u16 ss0, __ss0_unused; u32 esp1; u16 ss1, __ss1_unused; u32 esp2; u16 ss2, __ss2_unused; u32 cr3; u32 eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; u16 es, __es_unused; u16 cs, __cs_unused; u16 ss, __ss_unused; u16 ds, __ds_unused; u16 fs, __fs_unused; u16 gs, __gs_unused; u16 ldt_selector, __ldt_sel_unused; u16 debug_flag, io_map; } __attribute__ ((packed)); /* Descripteur de segment */ struct idtdesc { u16 offset0_15; u16 select; u16 type; u16 offset16_31; } __attribute__ ((packed)); /* Registre IDTR */ struct idtr { u16 limite; u32 base; } __attribute__ ((packed)); typedef struct { u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; u32 ds, es, fs, gs; u32 which_int, err_code; u32 eip, cs, eflags, user_esp, user_ss; } __attribute__((packed)) regs_t; typedef void (*int_desc)(void); extern "C" { void init_gdt_desc(u32, u32, u8, u8, struct gdtdesc *); void init_gdt(void); void init_idt_desc(u16, u32, u16, struct idtdesc *); void init_idt(void); void init_pic(void); int install_irq(unsigned int num,unsigned int irq); void switch_to_task(process_st* current, int mode); extern tss default_tss; u32 cpu_vendor_name(char *name); int dequeue_signal(int); int handle_signal(int); } #endif ================================================ FILE: src/kernel/arch/x86/x86int.asm ================================================ extern isr_default_int, do_syscalls, isr_schedule_int %macro SAVE_REGS 0 pushad push ds push es push fs push gs push ebx mov bx,0x10 mov ds,bx pop ebx %endmacro %macro RESTORE_REGS 0 pop gs pop fs pop es pop ds popad %endmacro %macro INTERRUPT 1 global _asm_int_%1 _asm_int_%1: SAVE_REGS push %1 call isr_default_int pop eax ;;a enlever sinon mov al,0x20 out 0x20,al RESTORE_REGS iret %endmacro extern isr_GP_exc, isr_PF_exc global _asm_syscalls, _asm_exc_GP, _asm_exc_PF _asm_syscalls: SAVE_REGS push eax ; transmission du numero d'appel call do_syscalls pop eax cli sti RESTORE_REGS iret _asm_exc_GP: SAVE_REGS call isr_GP_exc RESTORE_REGS add esp,4 iret _asm_exc_PF: SAVE_REGS call isr_PF_exc RESTORE_REGS add esp,4 iret global _asm_schedule _asm_schedule: SAVE_REGS call isr_schedule_int mov al,0x20 out 0x20,al RESTORE_REGS iret INTERRUPT 1 INTERRUPT 2 ================================================ FILE: src/kernel/config.h ================================================ #ifndef CONFIG_H #define CONFIG_H #define KERNEL_NAME "devos" /* kernel name */ #define KERNEL_VERSION "1" /* kernel version */ #define KERNEL_DATE __DATE__ #define KERNEL_TIME __TIME__ #define KERNEL_LICENCE "Apache License" /* license */ #define KERNEL_COMPUTERNAME "test-pc" /* default name for the machine */ /* identifiant du processeur */ #ifdef __x86__ #define KERNEL_PROCESSOR_IDENTIFIER "x86" #else #define KERNEL_PROCESSOR_IDENTIFIER "(null)" #endif /* max open file */ #define CONFIG_MAX_FILE 32 #endif ================================================ FILE: src/kernel/core/Makefile ================================================ OBJS:= $(OBJS) core/class.o core/elf_loader.o core/file.o \ core/filesystem.o core/kernel.o core/api_posix.o\ core/process.o core/syscalls.o core/device.o core/system.o \ core/env.o core/user.o core/modulelink.o core/socket.o ================================================ FILE: src/kernel/core/api/dev/clock.h ================================================ #ifndef __API_CLOCK__ #define __API_CLOCK__ typedef unsigned int clock_d; struct clock_info{ clock_d h; clock_d m; clock_d s; clock_d day; clock_d month; clock_d year; }; #define API_CLOCK_GET_INFO 0x6122 #endif ================================================ FILE: src/kernel/core/api/dev/fb.h ================================================ #ifndef __API_FB__ #define __API_FB__ struct fb_info{ unsigned int w; //largeur unsigned int h; //hauteur char bpp; //bit per pixel char state; //etat de la carte unsigned int* vmem; //video memory }; enum{ FB_NOT_ACTIVE=0, FB_ACTIVE=1, }; #define API_FB_IS_AVAILABLE 0x801 #define API_FB_GET_INFO 0x802 //info actuel #define API_FB_GET_BINFO 0x803 //meilleur info #define API_FB_SET_INFO 0x804 #endif ================================================ FILE: src/kernel/core/api/dev/ioctl.h ================================================ #ifndef __API_IOCTL__ #define __API_IOCTL__ #define DEV_GET_TYPE 0x01 /* Renvoie le type de peripherique */ #define DEV_GET_STATE 0x02 /* renvoie l'etat du peripherique */ #define DEV_GET_FORMAT 0x03 /* renvoie le format du peripherique */ //Type de peripherique : #define DEV_TYPE_TTY 0x01 #define DEV_TYPE_DISK 0x02 #define DEV_TYPE_FB 0x03 #define DEV_TYPE_HID 0x04 //Added by NoMaitener (aka William). HID stand for Human Interface Device //Format du peripherique #define DEV_FORMAT_CHAR 0x01 #define DEV_FORMAT_BLOCK 0x02 #define DEV_FORMAT_FB 0x03 //Etat du peripherique #define DEV_STATE_OK 0x01 #define DEV_STATE_NOTREADY 0x02 //Added by NoMaitener (aka William). Discuss here of "NOTREADY" #endif ================================================ FILE: src/kernel/core/api/dev/ipc.h ================================================ #ifndef __API_IPC__ #define __API_IPC__ #define STDIPC_FILENO 3 #define SIGIPC SIGUSR1 //iotcl #define API_TTY_SWITCH_SCREEN 0xff52 #endif ================================================ FILE: src/kernel/core/api/dev/keyboard.h ================================================ #ifndef __API_KEYBOARD__ #define __API_KEYBOARD__ //keyboard enum { KEY_TAB = 7, KEY_BACKSPACE = 8, KEY_ENTER = 10, KEY_ESCAPE = 27, KEY_F1 = 255, KEY_F2 = 254, KEY_F3 = 253, KEY_F4 = 252, KEY_F5 = 251, KEY_F6 = 250, KEY_F7 = 249, KEY_F8 = 248, KEY_F9 = 247, KEY_F10 = 246, KEY_F11 = 245, KEY_F12 = 244 }; #define TABLE_KEYBOARD_SIZE 388 #define API_KEYBOARD_SET_TABLE 0x4122 #endif ================================================ FILE: src/kernel/core/api/dev/proc.h ================================================ #ifndef __API_PROC__ #define __API_PROC__ struct proc_info{ char name[32]; unsigned int pid; unsigned int tid; unsigned char state; unsigned int vmem; unsigned int pmem; }; enum{ PROC_STATE_RUN=0, PROC_STATE_ZOMBIE=1, PROC_STATE_THREAD=2, }; #define API_PROC_GET_PID 0x5200 #define API_PROC_GET_INFO 0x5201 #endif ================================================ FILE: src/kernel/core/api/dev/tty.h ================================================ #ifndef __API_TTY__ #define __API_TTY__ #include #define TTY_NAME_LEN 16 //tty info struct tty_info_static{ char name[TTY_NAME_LEN]; char state; char type; unsigned int flags; }; struct tty_info_moving{ unsigned int x; unsigned int y; unsigned int attrf; unsigned int attrb; }; //tty type enum { TTY_TYPE_IOSTD=0, TTY_TYPE_SERIAL=1, TTY_TYPE_SCREEN=2, TTY_TYPE_VIRTUAL=3, TTY_TYPE_GUI=4 }; //tty state enum { TTY_STATE_RUN=0, TTY_STATE_SWITCH=1, TTY_STATE_ERROR=2, TTY_STATE_PAUSE=3 }; enum TTY_Colour { Black =0, Blue =1, Green =2, Cyan =3, Red =4, Magenta =5, Orange =6, LightGrey =7, DarkGrey =8, LightBlue =9, LightGreen =10, LightCyan =11, LightRed =12, LightMagenta=13, Yellow =14, White =15 }; //iotcl #define API_TTY_SWITCH_SCREEN 0xff52 #define API_TTY_CLEAR_SCREEN 0xff53 #define API_TTY_GET_SINFO 0xff54 #define API_TTY_GET_MINFO 0xff55 #define API_TTY_SET_MINFO 0xff56 #endif ================================================ FILE: src/kernel/core/api/kernel/syscall.h ================================================ #ifndef _OS_SYSCALL_H_ #define _OS_SYSCALL_H_ int syscall0( int number ); int syscall1( int number, unsigned int p1 ); int syscall2( int number, unsigned int p1, unsigned int p2 ); int syscall3( int number, unsigned int p1, unsigned int p2, unsigned int p3 ); int syscall4( int number, unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4 ); int syscall5( int number, unsigned int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned int p5 ); #endif ================================================ FILE: src/kernel/core/api/kernel/syscall_table.h ================================================ #ifndef _OS_SYSCALL_TABLE_H_ #define _OS_SYSCALL_TABLE_H_ #define NOT_DEFINED 0 enum { SYS_rewinddir =NOT_DEFINED, SYS_sbrk =45, // (count) SYS_fork =NOT_DEFINED, SYS_write =4, // (fd,buffer,count) SYS_read =3, // (fd,buffer,count) SYS_open =5, // (filename,flag) SYS_close =6, // (fd) SYS_execve =11, // (filename,argv,envp ) SYS_dup =NOT_DEFINED, SYS_dup2 =38, SYS_pwrite =NOT_DEFINED, SYS_pread =NOT_DEFINED, SYS_exit =1, // (status) SYS_getdents =89, SYS_fchdir =NOT_DEFINED, SYS_isatty =NOT_DEFINED, SYS_lseek =19, SYS_unlink =17, SYS_link =18, SYS_readlink =19, SYS_sleep_thread =NOT_DEFINED, SYS_access =NOT_DEFINED, SYS_chdir =12, SYS_getpid =20, SYS_getuid =70, SYS_gettid =NOT_DEFINED, SYS_rmdir =NOT_DEFINED, SYS_symlink =9, // (oldname,newname) SYS_fcntl =NOT_DEFINED, SYS_get_system_time =NOT_DEFINED, SYS_stat =106, SYS_fstat =NOT_DEFINED, SYS_stime =NOT_DEFINED, SYS_mkdir =15, SYS_ioctl =54, // (fd,adress,buffer) SYS_select =NOT_DEFINED, SYS_mount =13, SYS_unmount =14, SYS_lstat =NOT_DEFINED, SYS_utime =NOT_DEFINED, SYS_wait4 =7, SYS_socket =NOT_DEFINED, SYS_connect =NOT_DEFINED, SYS_sigaction =67, SYS_kill =37, SYS_sigprocmask =NOT_DEFINED, SYS_dbprintf =NOT_DEFINED, SYS_create_semaphore =NOT_DEFINED, SYS_delete_semaphore =NOT_DEFINED, SYS_lock_semaphore =NOT_DEFINED, SYS_unlock_semaphore =NOT_DEFINED, SYS_create_thread =101, SYS_wake_up_thread =NOT_DEFINED, SYS_kill_thread =NOT_DEFINED, SYS_mmap =55, SYS_loadmod =71, SYS_login =72, SYS_newuser =73, }; #endif ================================================ FILE: src/kernel/core/api.h ================================================ #ifndef API_H #define API_H //posix void call_open(); void call_close(); void call_read(); void call_write(); void call_sbrk(); void call_ioctl(); void call_exit(); void call_execv(); void call_symlink(); void call_getdents(); void call_wait(); void call_dup2(); void call_fork(); void call_chdir(); void call_mmap(); #endif ================================================ FILE: src/kernel/core/api_posix.cc ================================================ #include /* * u32 open(char* name,u32 flag); */ void call_open(){ char*name=(char*)arch.getArg(0); u32 flag=arch.getArg(1); Process* p=arch.pcurrent; if (p==NULL){ arch.setRet((u32)-1); return; } File* fp=fsm.path(name); fp->open(flag); u32 fd=p->addFile(fp,flag); arch.setRet(fd); } /* * void close(u32 fd); */ void call_close(){ u32 fd=arch.getArg(0); Process* p=arch.pcurrent; if (p==NULL){ arch.setRet((u32)-1); return; } File* fp=p->getFile(fd); if (fp==NULL){ return; } fp->close(); p->deleteFile(fd); } /* * u32 read(u32 fd,char* buf,u32 size); */ void call_read(){ u32 fd=arch.getArg(0); u8*buf=(u8*)arch.getArg(1); u32 size=arch.getArg(2); Process* p=arch.pcurrent; if (p==NULL){ arch.setRet((u32)-1); return; } File* fp=p->getFile(fd); if (fp==NULL){ arch.setRet((u32)-1); return; } openfile* info = p->getFileInfo(fd); u32 ret=fp->read(info->ptr,buf,size); info->ptr=info->ptr + ret; arch.setRet(ret); } /* * u32 write(u32 fd,char* buf,u32 size); */ void call_write(){ u32 fd=arch.getArg(0); u8*buf=(u8*)arch.getArg(1); u32 size=arch.getArg(2); Process* p=arch.pcurrent; if (p==NULL){ arch.setRet((u32)-1); return; } File* fp=p->getFile(fd); if (fp==NULL){ arch.setRet(-1); return; } openfile* info = p->getFileInfo(fd); u32 ret=fp->write(info->ptr,buf,size); info->ptr=info->ptr + ret; arch.setRet(ret); } /* * u32 ioctl(u32 fd,u32 pos,char* buf); */ void call_ioctl(){ u32 fd=arch.getArg(0); u8*buf=(u8*)arch.getArg(2); u32 pos=arch.getArg(1); Process* p=arch.pcurrent; if (p==NULL){ arch.setRet((u32)-1); return; } File* fp=p->getFile(fd); if (fp==NULL){ arch.setRet(-1); return; } u32 ret=fp->ioctl(pos,buf); arch.setRet(ret); } /* * char* sbrk(int size); */ void call_sbrk(){ int size; size=arch.getArg(0); char *ret; Process* p=arch.pcurrent; process_st* current=p->getPInfo(); ret = current->e_heap; current->e_heap += size; arch.setRet((u32)ret); return; } /* * void exit(int code); */ void call_exit(){ int code; code=arch.getArg(0); Process* p=arch.pcurrent; p->exit(); return; } /* * int execv(const char* filename, char* const argv[], char* const envp[] ); */ void call_execv(){ char* filename,**argv,**envp; filename=(char*)arch.getArg(0); argv=(char**)arch.getArg(1); envp=(char**)arch.getArg(2); int argc; char **ap; ap = argv; argc = 0; while (*ap++) argc++; int ret=execv(filename,argc,argv); arch.setRet((u32)ret); return; } /* * int symlink(const char* oldpath, const char* newpath); */ void call_symlink(){ char* oldpath,*path; oldpath=(char*)arch.getArg(0); path=(char*)arch.getArg(1); int ret=fsm.link(oldpath,path); arch.setRet((u32)ret); return; } struct dirent { u64 d_ino; char d_name[256]; }; /* * int getdents(int fd,dirrent* entry,int size); */ void call_getdents(){ dirent nentry; u32 fd=arch.getArg(0); dirent* entry=(dirent*)arch.getArg(1); int size=arch.getArg(2); Process* p=arch.pcurrent; if (p==NULL){ arch.setRet((u32)0); return; } File* fp=p->getFile(fd); if (fp==NULL){ arch.setRet(0); return; } openfile* info = p->getFileInfo(fd); int i=0; File* child=fp->getChild(); while (child!=NULL){ if (i==(info->ptr)){ //io.print("readdir=%s - size=%d entry=%x\n",child->getName(),size,entry); nentry.d_ino=child->getInode(); strncpy(nentry.d_name,child->getName(),256); memcpy((char*)entry,(char*)&nentry,size); info->ptr++; arch.setRet(1); return; } i++; child=child->getNext(); } arch.setRet((u32)0); return; } /* * int wait(int* status); */ void call_wait(){ u32*status=(u32*)arch.getArg(1); *status=0; Process* p=arch.pcurrent; u32 ret=p->wait(); //arch.setRet(ret); } /* * int dup2( int old_fd, int new_fd ); */ void call_dup2(){ u32 oldfd=arch.getArg(0); u32 newfd=arch.getArg(1); //io.print("dup2 %d to %d\n",oldfd,newfd); u32 ret=newfd; Process* p=arch.pcurrent; p->setFile((u32)newfd,p->getFile(oldfd),0, 0); arch.setRet((u32)ret); } /* * int fork(); */ void call_fork(){ Process* p=arch.pcurrent; int ret=p->fork(); arch.setRet((u32)ret); } /* * int chdir(char* n); */ void call_chdir(){ char* n; n=(char*)arch.getArg(0); Process* p=arch.pcurrent; File*f=fsm.path(n); if (f==NULL){ arch.setRet((u32)-1); return; } p->setCurrentDir(f); arch.setRet((u32)1); return; } /* * void * mmap (void *addr,size_t len,int prot,int flags,int fd,off_t offset) */ void call_mmap(){ u32 fd=arch.getArg(3); u32 size=arch.getArg(0); u32 prot=0; u32 flags=0; u32 offset=0; Process* p=arch.pcurrent; if (p==NULL){ arch.setRet((u32)-1); return; } File* fp=p->getFile(fd); if (fp==NULL){ arch.setRet((u32)-1); return; } openfile* info = p->getFileInfo(fd); u32 ret=fp->mmap(size,flags,offset,prot); arch.setRet(ret); } ================================================ FILE: src/kernel/core/boot.h ================================================ #ifndef __MY_BOOT__ #define __MY_BOOT__ #include struct multiboot_info { u32 flags; u32 low_mem; u32 high_mem; u32 boot_device; u32 cmdline; u32 mods_count; u32 mods_addr; struct { u32 num; u32 size; u32 addr; u32 shndx; } elf_sec; unsigned long mmap_length; unsigned long mmap_addr; unsigned long drives_length; unsigned long drives_addr; unsigned long config_table; unsigned long boot_loader_name; unsigned long apm_table; unsigned long vbe_control_info; unsigned long vbe_mode_info; unsigned long vbe_mode; unsigned long vbe_interface_seg; unsigned long vbe_interface_off; unsigned long vbe_interface_len; }; /* VBE controller information. */ struct vbe_controller { unsigned char signature[4]; unsigned short version; unsigned long oem_string; unsigned long capabilities; unsigned long video_mode; unsigned short total_memory; unsigned short oem_software_rev; unsigned long oem_vendor_name; unsigned long oem_product_name; unsigned long oem_product_rev; unsigned char reserved[222]; unsigned char oem_data[256]; } __attribute__ ((packed)); /* VBE mode information. */ struct vbe_mode { unsigned short mode_attributes; unsigned char win_a_attributes; unsigned char win_b_attributes; unsigned short win_granularity; unsigned short win_size; unsigned short win_a_segment; unsigned short win_b_segment; unsigned long win_func; unsigned short bytes_per_scanline; /* >=1.2 */ unsigned short x_resolution; unsigned short y_resolution; unsigned char x_char_size; unsigned char y_char_size; unsigned char number_of_planes; unsigned char bits_per_pixel; unsigned char number_of_banks; unsigned char memory_model; unsigned char bank_size; unsigned char number_of_image_pages; unsigned char reserved0; /* direct color */ unsigned char red_mask_size; unsigned char red_field_position; unsigned char green_mask_size; unsigned char green_field_position; unsigned char blue_mask_size; unsigned char blue_field_position; unsigned char reserved_mask_size; unsigned char reserved_field_position; unsigned char direct_color_mode_info; /* >=2.0 */ unsigned long phys_base; unsigned long reserved1; unsigned short reversed2; /* >=3.0 */ unsigned short linear_bytes_per_scanline; unsigned char banked_number_of_image_pages; unsigned char linear_number_of_image_pages; unsigned char linear_red_mask_size; unsigned char linear_red_field_position; unsigned char linear_green_mask_size; unsigned char linear_green_field_position; unsigned char linear_blue_mask_size; unsigned char linear_blue_field_position; unsigned char linear_reserved_mask_size; unsigned char linear_reserved_field_position; unsigned long max_pixel_clock; unsigned char reserved3[189]; } __attribute__ ((packed)); #endif ================================================ FILE: src/kernel/core/class.cc ================================================ #include /* Static objects */ Io io; /* Input/Output interface */ Architecture arch; /* Cpu and architecture interface */ Vmm vmm; /* Virtual memory manager interface */ Filesystem fsm; /* Filesystem interface */ Module modm; /* Module manager */ Syscalls syscall; /* Syscalls manager */ System sys; /* System manager */ ================================================ FILE: src/kernel/core/device.cc ================================================ #include Device::~Device(){ } Device::Device(char* n) : File(n,TYPE_DEVICE) { fsm.addFile("/dev",this); } u32 Device::open(u32 flag){ return NOT_DEFINED; } u32 Device::close(){ return NOT_DEFINED; } u32 Device::read(u8* buffer,u32 size){ return NOT_DEFINED; } u32 Device::write(u8* buffer,u32 size){ return NOT_DEFINED; } u32 Device::ioctl(u32 id,u8* buffer){ return NOT_DEFINED; } u32 Device::remove(){ delete this; } void Device::scan(){ } ================================================ FILE: src/kernel/core/device.h ================================================ #ifndef DEVICE_H #define DEVICE_H #include #include class Device : public File { public: Device(char* n); ~Device(); virtual u32 open(u32 flag); virtual u32 close(); virtual u32 read(u8* buffer,u32 size); virtual u32 write(u8* buffer,u32 size); virtual u32 ioctl(u32 id,u8* buffer); virtual u32 remove(); virtual void scan(); protected: }; #endif ================================================ FILE: src/kernel/core/elf_loader.cc ================================================ #include /* Chargeur de module externe au format elf32 : pour le moment compil en static sans librairies partags */ char* __default_proc_name="_proc_"; /* nom par default avec en plus un nombre */ char nb_default='0'; /* * Teste si le fichier dont l'adresse est passee en argument * est au format ELF */ int is_elf(char *file) { Elf32_Ehdr *hdr; hdr = (Elf32_Ehdr *) file; if (hdr->e_ident[0] == 0x7f && hdr->e_ident[1] == 'E' && hdr->e_ident[2] == 'L' && hdr->e_ident[3] == 'F') return RETURN_OK; else return ERROR_PARAM; } /* * Charge le fichier elf dans la memoire virtuelle et renvoie l'adresse de depart */ u32 load_elf(char *file,process_st *proc) { char *p; u32 v_begin, v_end; Elf32_Ehdr *hdr; Elf32_Phdr *p_entry; Elf32_Scdr *s_entry; int i, pe; hdr = (Elf32_Ehdr *) file; p_entry = (Elf32_Phdr *) (file + hdr->e_phoff); s_entry= (Elf32_Scdr*) (file + hdr->e_shoff); if (is_elf(file)==ERROR_PARAM) { io.print("INFO: load_elf(): file not in ELF format !\n"); return 0; } for (pe = 0; pe < hdr->e_phnum; pe++, p_entry++) { /* Read each entry */ if (p_entry->p_type == PT_LOAD) { v_begin = p_entry->p_vaddr; v_end = p_entry->p_vaddr + p_entry->p_memsz; if (v_begin < USER_OFFSET) { io.print ("INFO: load_elf(): can't load executable below %p\n", USER_OFFSET); return 0; } if (v_end > USER_STACK) { io.print ("INFO: load_elf(): can't load executable above %p\n", USER_STACK); return 0; } // Description de la zone exec + rodata if (p_entry->p_flags == PF_X + PF_R) { proc->b_exec = (char*) v_begin; proc->e_exec = (char*) v_end; } // Description de la zone bss if (p_entry->p_flags == PF_W + PF_R) { proc->b_bss = (char*) v_begin; proc->e_bss = (char*) v_end; } //io.print("elf : %x to %x \n",(file + p_entry->p_offset),v_begin); memcpy((char *) v_begin, (char *) (file + p_entry->p_offset), p_entry->p_filesz); if (p_entry->p_memsz > p_entry->p_filesz) for (i = p_entry->p_filesz, p = (char *) p_entry->p_vaddr; i < (int)(p_entry->p_memsz); i++) p[i] = 0; } } /* Return program entry point */ return hdr->e_entry; } /* * Charge un fichier en creant un nouveau processus */ int execv(char* file,int argc,char** argv){ char* map_elf=NULL; File* fp=fsm.path(file); if (fp==NULL) return ERROR_PARAM; map_elf=(char*)kmalloc(fp->getSize()); fp->open(NO_FLAG); fp->read(0,(u8*)map_elf,fp->getSize()); fp->close(); char* name; __default_proc_name[strlen(__default_proc_name)-1]=nb_default; nb_default++; if (argc<=0) name=__default_proc_name; else name=argv[0]; //io.print("exec %s > %s\n",file,name); Process* proc=new Process(name); proc->create(map_elf,argc,argv); kfree(map_elf); return (int)proc->getPid(); } /* * Charge un module */ void execv_module(u32 entry,int argc,char** argv){ char* name; __default_proc_name[strlen(__default_proc_name)-1]=nb_default; nb_default++; if (argc<=0) name=__default_proc_name; else name=argv[0]; Process* proc=new Process(name); proc->create((char*)entry,argc,argv); } ================================================ FILE: src/kernel/core/elf_loader.h ================================================ #ifndef ELF_H #define ELF_H #include #include /* * ELF HEADER */ typedef struct { unsigned char e_ident[16]; /* ELF identification */ u16 e_type; /* 2 (exec file) */ u16 e_machine; /* 3 (intel architecture) */ u32 e_version; /* 1 */ u32 e_entry; /* starting point */ u32 e_phoff; /* program header table offset */ u32 e_shoff; /* section header table offset */ u32 e_flags; /* various flags */ u16 e_ehsize; /* ELF header (this) size */ u16 e_phentsize; /* program header table entry size */ u16 e_phnum; /* number of entries */ u16 e_shentsize; /* section header table entry size */ u16 e_shnum; /* number of entries */ u16 e_shstrndx; /* index of the section name string table */ } Elf32_Ehdr; /* * ELF identification */ #define EI_MAG0 0 #define EI_MAG1 1 #define EI_MAG2 2 #define EI_MAG3 3 #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 #define EI_PAD 7 /* EI_MAG */ #define ELFMAG0 0x7f #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' /* EI_CLASS */ #define ELFCLASSNONE 0 /* invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ /* EI_DATA */ #define ELFDATANONE 0 /* invalide data encoding */ #define ELFDATA2LSB 1 /* least significant byte first (0x01020304 is 0x04 0x03 0x02 0x01) */ #define ELFDATA2MSB 2 /* most significant byte first (0x01020304 is 0x01 0x02 0x03 0x04) */ /* EI_VERSION */ #define EV_CURRENT 1 #define ELFVERSION EV_CURRENT /* * PROGRAM HEADER */ typedef struct { u32 p_type; /* type of segment */ u32 p_offset; u32 p_vaddr; u32 p_paddr; u32 p_filesz; u32 p_memsz; u32 p_flags; u32 p_align; } Elf32_Phdr; /* p_type */ #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define PT_INTERP 3 #define PT_NOTE 4 #define PT_SHLIB 5 #define PT_PHDR 6 #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff /* p_flags */ #define PF_X 0x1 #define PF_W 0x2 #define PF_R 0x4 enum eElfSectionTypes { SHT_NULL, //0 SHT_PROGBITS, //1 SHT_SYMTAB, //2 SHT_STRTAB, //3 SHT_RELA, //4 SHT_HASH, //5 SHT_DYNAMIC, //6 SHT_NOTE, //7 SHT_NOBITS, //8 SHT_REL, //9 SHT_SHLIB, //A SHT_DYNSYM, //B SHT_LAST, //C SHT_LOPROC = 0x70000000, SHT_HIPROC = 0x7fffffff, SHT_LOUSER = 0x80000000, SHT_HIUSER = 0xffffffff }; typedef struct { u32 name; u32 type; u32 flags; u32 address; u32 offset; u32 size; u32 link; u32 info; u32 addralign; u32 entsize; } Elf32_Scdr; enum { R_386_NONE=0, // none R_386_32, // S+A R_386_PC32, // S+A-P R_386_GOT32, // G+A-P R_386_PLT32, // L+A-P R_386_COPY, // none R_386_GLOB_DAT, // S R_386_JMP_SLOT, // S R_386_RELATIVE, // B+A R_386_GOTOFF, // S+A-GOT R_386_GOTPC, // GOT+A-P R_386_LAST // none }; typedef struct { u16 d_tag; u32 d_val; //Also d_ptr } Elf32_dyn; enum { DT_NULL, //!< Marks End of list DT_NEEDED, //!< Offset in strtab to needed library DT_PLTRELSZ, //!< Size in bytes of PLT DT_PLTGOT, //!< Address of PLT/GOT DT_HASH, //!< Address of symbol hash table DT_STRTAB, //!< String Table address DT_SYMTAB, //!< Symbol Table address DT_RELA, //!< Relocation table address DT_RELASZ, //!< Size of relocation table DT_RELAENT, //!< Size of entry in relocation table DT_STRSZ, //!< Size of string table DT_SYMENT, //!< Size of symbol table entry DT_INIT, //!< Address of initialisation function DT_FINI, //!< Address of termination function DT_SONAME, //!< String table offset of so name DT_RPATH, //!< String table offset of library path DT_SYMBOLIC,//!< Reverse order of symbol searching for library, search libs first then executable DT_REL, //!< Relocation Entries (Elf32_Rel instead of Elf32_Rela) DT_RELSZ, //!< Size of above table (bytes) DT_RELENT, //!< Size of entry in above table DT_PLTREL, //!< Relocation entry of PLT DT_DEBUG, //!< Debugging Entry - Unknown contents DT_TEXTREL, //!< Indicates that modifcations to a non-writeable segment may occur DT_JMPREL, //!< Address of PLT only relocation entries DT_LOPROC = 0x70000000, //!< Low Definable DT_HIPROC = 0x7FFFFFFF //!< High Definable }; int is_elf(char *); u32 load_elf(char *,process_st *); int execv(char* file,int argc,char** argv); void execv_module(u32 entry,int argc,char** argv); #endif ================================================ FILE: src/kernel/core/env.cc ================================================ #include /* * Definis la structure d'une variable d'environnement * chaque variable est un fichier stoqu dans le dossier virtuel /sys/env */ /* * Destructeur de la variable */ Variable::~Variable(){ if (value!=NULL) kfree(value); } /* * Constructeur : * n : nom * v : valeur */ Variable::Variable(char* n,char* v) : File(n,TYPE_FILE) { fsm.addFile("/sys/env/",this); if (v!=NULL){ io.print("env: create %s (%s) \n",n,v); value=(char*)kmalloc(strlen(v)+1); memcpy(value,v,strlen(v)+1); setSize(strlen(v)+1); } else{ value=NULL; } } u32 Variable::open(u32 flag){ return RETURN_OK; } u32 Variable::close(){ return RETURN_OK; } /* lecture de la valeur dans buffer */ u32 Variable::read(u32 pos,u8* buffer,u32 size){ if (value==NULL) return NOT_DEFINED; else{ strncpy((char*)buffer,value,size); return size; } } /* ecriture de buffer dans la variable */ u32 Variable::write(u32 pos,u8* buffer,u32 size){ if (value!=NULL) kfree(value); value=(char*)kmalloc(size+1); memset((char*)value,0,size+1); memcpy(value,(char*)buffer,size+1); value[size]=0; //to make sure it's a string setSize(size+1); return size; } /* controle de la variable (TODO) */ u32 Variable::ioctl(u32 id,u8* buffer){ return NOT_DEFINED; } /* destruction de la variable */ u32 Variable::remove(){ delete this; return NOT_DEFINED; } /* seulement pour les dossiers */ void Variable::scan(){ } ================================================ FILE: src/kernel/core/env.h ================================================ #ifndef ENV_H #define ENV_H #include #include class Variable : public File { public: Variable(char* n,char* v); ~Variable(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); protected: char* value; }; #endif ================================================ FILE: src/kernel/core/file.cc ================================================ #include /* dans myos quasiment tous herite de cette classe */ /* * Remplace dans s tous les a par to */ static void strreplace(char* s,char a,char to){ if (s==NULL) return; while (*s){ if (*s==a) *s=to; s++; } } u32 File::inode_system=0; /* numero d'inode de depart */ /* constructeur */ File::File(char* n,u8 t){ name=(char*)kmalloc(strlen(n)+1); memset(name,0,strlen(n)); memcpy(name,n,strlen(n)); name[strlen(n)]=0; checkName(); master=arch.pcurrent; // la creation, le maitre est le processus courant inode=inode_system; inode_system++; size=0; type=t; parent=NULL; child=NULL; next=NULL; prec=NULL; link=NULL; map_memory=NULL; } /* destructeur */ File::~File(){ kfree(name); //on modifie la liste des frere if (prec==NULL){ parent->setChild(next); next->setPrec(NULL); } else if (next==NULL){ prec->setNext(NULL); } else if (next==NULL && prec==NULL){ parent->setChild(NULL); } else{ io.print("prec (%s) next is now %s\n",prec->getName(),next->getName()); io.print("next (%s) prec is now %s\n",next->getName(),prec->getName()); prec->setNext(next); next->setPrec(prec); } //on supprime les enfant (dossier) File* n=child; File* nn=NULL; while (n!=NULL){ //io.print("delete %s \n",n->getName()); nn=n->getNext(); delete n; n=nn; } } #define CAR_REPLACE '_' void File::checkName(){ //Adapte le nom strreplace(name,'/',CAR_REPLACE); strreplace(name,'\ ',CAR_REPLACE); strreplace(name,'?',CAR_REPLACE); strreplace(name,':',CAR_REPLACE); strreplace(name,'>',CAR_REPLACE); strreplace(name,'<',CAR_REPLACE); strreplace(name,'*',CAR_REPLACE); strreplace(name,'"',CAR_REPLACE); strreplace(name,':',CAR_REPLACE); } u32 File::addChild(File* n){ if (!n){ return PARAM_NULL; } n->setParent(this); n->setPrec(NULL); n->setNext(child); if (child != NULL) child->setPrec(n); child=n; return RETURN_OK; } File* File::createChild(char* n,u8 t){ File* fp=new File(n,t); addChild(fp); return fp; } File* File::getParent(){ return parent; } File* File::getChild(){ return child; } File* File::getNext(){ return next; } File* File::getPrec(){ return prec; } File* File::getLink(){ return link; } u32 File::getSize(){ return size; } u32 File::getInode(){ return inode; } void File::scan(){ } void File::setType(u8 t){ type=t; } void File::setSize(u32 t){ size=t; } void File::setParent(File* n){ parent=n; } void File::setLink(File* n){ link=n; } void File::setChild(File* n){ child=n; } void File::setNext(File* n){ next=n; } void File::setPrec(File* n){ prec=n; } void File::setName(char* n){ kfree(name); name=(char*)kmalloc(strlen(n)); memcpy(name,n,strlen(n)); checkName(); } u8 File::getType(){ return type; } char* File::getName(){ return name; } File* File::find(char* n){ File* fp=child; while (fp!=0){ if (!strcmp(fp->getName(),n)) return fp; fp=fp->next; } return NULL; } u32 File::open(u32 flag){ return NOT_DEFINED; } u32 File::close(){ return NOT_DEFINED; } u32 File::read(u32 pos,u8* buffer,u32 size){ return NOT_DEFINED; } u32 File::write(u32 pos,u8* buffer,u32 size){ return NOT_DEFINED; } u32 File::ioctl(u32 id,u8* buffer){ return NOT_DEFINED; } u32 File::remove(){ delete this; return NOT_DEFINED; } stat_fs File::stat(){ stat_fs st; return st; } u32 File::mmap(u32 sizee,u32 flags,u32 offset,u32 prot){ if (map_memory!=NULL){ int i=0; unsigned int adress; struct page *pg; process_st* current=(arch.pcurrent)->getPInfo(); for (i=0;ip_addr = (char*) (adress); pg->v_addr = (char *) (adress & 0xFFFFF000); list_add(&pg->list, ¤t->pglist); pd_add_page(pg->v_addr, pg->p_addr, PG_USER, current->pd); } return (u32)map_memory; } else{ return -1; } } ================================================ FILE: src/kernel/core/file.h ================================================ #ifndef FILE_H #define FILE_H #include enum{ TYPE_FILE, TYPE_DIRECTORY, TYPE_DEVICE, TYPE_PROCESS, TYPE_LINK }; class File { public: File(char* n,u8 t); ~File(); virtual u32 open(u32 flag); virtual u32 close(); virtual u32 read(u32 pos,u8* buffer,u32 size); virtual u32 write(u32 pos,u8* buffer,u32 size); virtual u32 ioctl(u32 id,u8* buffer); virtual u32 remove(); virtual void scan(); void checkName(); u32 addChild(File* n); File* createChild(char* n,u8 t); File* find(char* n); u32 mmap(u32 sizee,u32 flags,u32 offset,u32 prot); void setSize(u32 t); void setType(u8 t); void setParent(File* n); void setChild(File* n); void setNext(File* n); void setPrec(File* n); void setLink(File* n); void setName(char* n); char* getName(); File* getParent(); File* getChild(); File* getNext(); File* getPrec(); File* getLink(); u8 getType(); u32 getSize(); u32 getInode(); stat_fs stat(); protected: static u32 inode_system; char* map_memory; /* to mmap */ char* name; /* Nom du fichier */ u32 size; /* Taille du fichier */ u8 type; /* Type de fichier */ u32 inode; /* Inode du fichier */ File* dev; /* the master device, example : /dev/hda */ File* link; /* the real file, if this file is a link */ File* master; /* processus maitre ou NULL */ File* parent; File* child; File* next; File* prec; File* device; /* This file is the device master of the current file */ }; #endif ================================================ FILE: src/kernel/core/filesystem.cc ================================================ #include /* Cette classe organise les fichiers entre eux */ Filesystem::Filesystem(){ } void Filesystem::init(){ root=new File("/",TYPE_DIRECTORY); dev=root->createChild("dev",TYPE_DIRECTORY); //dossier contenant les peripherique root->createChild("proc",TYPE_DIRECTORY); //dossier contenant les processus tournant root->createChild("mnt",TYPE_DIRECTORY); //dossier contenant les points de montages des disques File* sysd=root->createChild("sys",TYPE_DIRECTORY); //dossier contenant toutes les infos du systemes var=sysd->createChild("env",TYPE_DIRECTORY); //dossier contenant toutes les variables d'environnement sysd->createChild("usr",TYPE_DIRECTORY); //dossier contenant tous les utilisateurs sysd->createChild("mods",TYPE_DIRECTORY); //dossier contenant tous les modules disponiles sysd->createChild("sockets",TYPE_DIRECTORY); //dossier contenant tous les sockets actuels } Filesystem::~Filesystem(){ delete root; } void Filesystem::mknod(char* module,char* name,u32 flag){ modm.createDevice(name,module,flag); } File* Filesystem::getRoot(){ return root; } File* Filesystem::path(char* p){ if (!p) return NULL; File* fp=root; char *name, *beg_p, *end_p; if (p[0]=='/') fp=root; else{ if (arch.pcurrent!=NULL) /* prend de le dossier actuel du fichier */ fp=(arch.pcurrent)->getCurrentDir(); } beg_p = p; while (*beg_p == '/') beg_p++; end_p = beg_p + 1; while (*beg_p != 0) { if (fp->getType() != TYPE_DIRECTORY){ return NULL; } while (*end_p != 0 && *end_p != '/') end_p++; name = (char *) kmalloc(end_p - beg_p + 1); memcpy(name, beg_p, end_p - beg_p); name[end_p - beg_p] = 0; if (strcmp("..", name) == 0) { // '..' fp = fp->getParent(); } else if (strcmp(".", name) == 0) { // '.' } else { fp->scan(); if (!(fp = fp->find(name))) { kfree(name); return 0; } if (fp->getType()==TYPE_LINK && (fp->getLink()!=NULL)){ fp=fp->getLink(); } } beg_p = end_p; while (*beg_p == '/') beg_p++; end_p = beg_p + 1; kfree(name); } return fp; } File* Filesystem::pivot_root(File* targetdir){ if (targetdir == NULL) return root; else { File* newRoot = new File("/",TYPE_DIRECTORY); File* mainChild = targetdir->getChild(); newRoot->addChild(mainChild); s8 i, ii = 0; File* tempChild = mainChild->getPrec(); //Est que File doit tre initialis ? ou pas ? do { if(tempChild == NULL) { i = 0; } else { newRoot->addChild(tempChild); tempChild = tempChild->getPrec(); } }while(i == 1); tempChild = mainChild->getNext(); i = 1; do { if(tempChild == NULL) i = 0; else { newRoot->addChild(tempChild); tempChild = tempChild->getNext(); } }while(i == 1); return newRoot; } } File* Filesystem::path_parent(char* p,char *fname){ if (!p) return NULL; File* ofp; File* fp=root; char *name, *beg_p, *end_p; if (p[0]=='/') fp=root; beg_p = p; while (*beg_p == '/') beg_p++; end_p = beg_p + 1; while (*beg_p != 0) { if (fp->getType() != TYPE_DIRECTORY) return NULL; while (*end_p != 0 && *end_p != '/') end_p++; name = (char *) kmalloc(end_p - beg_p + 1); memcpy(name, beg_p, end_p - beg_p); name[end_p - beg_p] = 0; if (strcmp("..", name) == 0) { // '..' fp = fp->getParent(); } else if (strcmp(".", name) == 0) { // '.' } else { ofp=fp; if (fp->getType()==TYPE_LINK && (fp->getLink()!=NULL)){ fp=fp->getLink(); } if (!(fp = fp->find(name))) { strcpy(fname,name); kfree(name); return ofp; } } beg_p = end_p; while (*beg_p == '/') beg_p++; end_p = beg_p + 1; kfree(name); } return fp; } u32 Filesystem::link(char* fname,char *newf){ File*tolink=path(fname); if (tolink==NULL) return -1; char* nname=(char*)kmalloc(255); File* par=path_parent(newf,nname); File* fp=new File(nname,TYPE_LINK); fp->setLink(tolink); par->addChild(fp); return RETURN_OK; } u32 Filesystem::addFile(char* dir,File* fp){ File* fdir=path(dir); if (fdir==NULL) return ERROR_PARAM; else{ return fdir->addChild(fp); } } ================================================ FILE: src/kernel/core/filesystem.h ================================================ #ifndef FILESYSTEM_H #define FILESYSTEM_H #include #include class Filesystem { public: Filesystem(); ~Filesystem(); void init(); void mknod(char* module,char* name,u32 flag); File* path(char* p); File* path_parent(char* p,char *fname); u32 link(char* fname,char *newf); u32 addFile(char* dir,File* fp); File* pivot_root(File* targetdir); File* getRoot(); private: File* root; File* dev; File* var; }; extern Filesystem fsm; #endif ================================================ FILE: src/kernel/core/kernel.cc ================================================ #include #include static char* init_argv[2]={"init","-i"}; /* charge les modules de depart */ static void load_modules(multiboot_info* mbi){ if (mbi->mods_count>0){ u32 initrd_location = *((u32*)mbi->mods_addr); u32 initrd_end = *(u32*)(mbi->mods_addr+4); u32 initrd_size=initrd_end-initrd_location; io.print(" >load module: location=%x, size=%d \n",initrd_location,initrd_end-initrd_location); int i=0; unsigned int adress; for (i=0;i<(initrd_size/4072)+1;i++){ adress=(initrd_location+i*4096); vmm.kmap(adress,adress); } execv_module(initrd_location,1,init_argv); } } /* le main du noyau */ extern "C" void kmain(multiboot_info* mbi){ io.clear(); io.print("%s - %s -- %s %s \n", KERNEL_NAME, KERNEL_VERSION, KERNEL_DATE, KERNEL_TIME); io.print("%s \n",KERNEL_LICENCE); arch.init(); io.print("Loading Virtual Memory Management \n"); vmm.init(mbi->high_mem); io.print("Loading FileSystem Management \n"); fsm.init(); io.print("Loading syscalls interface \n"); syscall.init(); io.print("Loading system \n"); sys.init(); io.print("Loading modules \n"); modm.init(); modm.initLink(); modm.install("hda0","module.dospartition",0,"/dev/hda"); modm.install("hda1","module.dospartition",1,"/dev/hda"); modm.install("hda2","module.dospartition",2,"/dev/hda"); modm.install("hda3","module.dospartition",3,"/dev/hda"); modm.mount("/dev/hda0","boot","module.ext2",NO_FLAG); arch.initProc(); io.print("Loading binary modules \n"); load_modules(mbi); fsm.link("/mnt/boot/bin/","/bin/"); io.print("\n"); io.print(" ==== System is ready (%s - %s) ==== \n",KERNEL_DATE,KERNEL_TIME); arch.enable_interrupt(); for (;;); arch.shutdown(); } ================================================ FILE: src/kernel/core/kernel.h ================================================ #ifndef KERNEL_H #define KERNEL_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif ================================================ FILE: src/kernel/core/keyboard.h ================================================ #ifndef __KBD__ #define __KBD__ #include char kbdmap_default[] = { KEY_ESCAPE, KEY_ESCAPE, KEY_ESCAPE, KEY_ESCAPE, /* esc (0x01) */ '1', '!', '1', '1', '2', '@', '2', '2', '3', '#', '3', '3', '4', '$', '4', '4', '5', '%', '5', '5', '6', ':', '6', '6', '7', '&', '7', '7', '8', '*', '8', '8', '9', '(', '9', '9', '0', ')', '0', '0', '-', '_', '-', '-', '=', '+', '=', '=', 0x08, 0x08, 0x7F, 0x08, /* backspace */ 0x09, 0x09, 0x09, 0x09, /* tab */ 'a', 'A', 'a', 'a', 'z', 'Z', 'z', 'z', 'e', 'E', 'e', 'e', 'r', 'R', 'r', 'r', 't', 'T', 't', 't', 'y', 'Y', 'y', 'y', 'u', 'U', 'u', 'u', 'i', 'I', 'i', 'i', 'o', 'O', 'o', 'o', 'p', 'P', 'p', 'p', '^', '"', '^', '^', '$', '£', ' ', '$', 0x0A, 0x0A, 0x0A, 0x0A, /* enter */ 0xFF, 0xFF, 0xFF, 0xFF, /* ctrl */ 'q', 'Q', 'q', 'q', 's', 'S', 's', 's', 'd', 'D', 'd', 'd', 'f', 'F', 'f', 'f', 'g', 'G', 'g', 'g', 'h', 'H', 'h', 'h', 'j', 'J', 'j', 'j', 'k', 'K', 'k', 'k', 'l', 'L', 'l', 'l', 'm', 'M', 'm', 'm', 0x27, 0x22, 0x27, 0x27, /* '" */ '*', '~', '`', '`', /* `~ */ 0xFF, 0xFF, 0xFF, 0xFF, /* Lshift (0x2a) */ '<', '>', '\\', '\\', 'w', 'W', 'w', 'w', 'x', 'X', 'x', 'x', 'c', 'C', 'c', 'c', 'v', 'V', 'v', 'v', 'b', 'B', 'b', 'b', 'n', 'N', 'n', 'n', ',', '?', ',', ',', 0x2C, 0x3C, 0x2C, 0x2C, /* ,< */ 0x2E, 0x3E, 0x2E, 0x2E, /* .> */ 0x2F, 0x3F, 0x2F, 0x2F, /* /? */ 0xFF, 0xFF, 0xFF, 0xFF, /* Rshift (0x36) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x37) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x38) */ ' ', ' ', ' ', ' ', /* space */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3a) */ KEY_F1, 0xFF, 0xFF, 0xFF, /* (0x3b) */ KEY_F2, 0xFF, 0xFF, 0xFF, /* (0x3c) */ KEY_F3, 0xFF, 0xFF, 0xFF, /* (0x3d) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3e) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3f) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x40) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x41) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x42) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x43) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x44) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x45) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x46) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x47) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x48) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x49) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4a) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4b) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4c) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4d) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4e) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4f) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x50) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x51) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x52) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x53) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x54) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x55) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x56) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x57) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x58) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x59) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5a) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5b) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5c) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5d) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5e) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5f) */ 0xFF, 0xFF, 0xFF, 0xFF, /* (0x60) */ 0xFF, 0xFF, 0xFF, 0xFF /* (0x61) */ }; char* kbdmap=kbdmap_default; #endif ================================================ FILE: src/kernel/core/modulelink.cc ================================================ #include ModLink::~ModLink(){ } ModLink::ModLink(char* n) : File(n,TYPE_FILE) { fsm.addFile("/sys/mods/",this); } u32 ModLink::open(u32 flag){ return RETURN_OK; } u32 ModLink::close(){ return RETURN_OK; } u32 ModLink::read(u8* buffer,u32 size){ return NOT_DEFINED; } u32 ModLink::write(u8* buffer,u32 size){ return NOT_DEFINED; } u32 ModLink::ioctl(u32 id,u8* buffer){ return NOT_DEFINED; } u32 ModLink::remove(){ delete this; } void ModLink::scan(){ } ================================================ FILE: src/kernel/core/modulelink.h ================================================ #ifndef MODLINK_H #define MODLINK_H #include #include class ModLink : public File { public: ModLink(char* n); ~ModLink(); u32 open(u32 flag); u32 close(); u32 read(u8* buffer,u32 size); u32 write(u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); protected: }; #endif ================================================ FILE: src/kernel/core/os.h ================================================ #ifndef OS_H #define OS_H #include #include typedef File* (*device_driver) (char* name,u32 flag,File* dev); struct module_class{ int module_type; char* module_name; char* class_name; device_driver drive; }; /* * Module Macro */ #define MODULE_DEVICE 0 #define MODULE_FILESYSTEM 1 #define module(name,type,classe,mknod) module_class classe##_module={type,\ name, \ #classe, \ (device_driver)mknod}; #define import_module(classe) extern module_class classe##_module #define run_module_builder module_class* module_builder[]= #define build_module(classe) &classe##_module #define end_module() NULL #define std_buildin_module void Module::init() #define run_module(n,m,f) createDevice(#m,#n,f); /* * Asm Macro */ #define asm __asm__ #define asmv __asm__ __volatile__ #endif ================================================ FILE: src/kernel/core/process.cc ================================================ #include #include /* Definis un process (/dev/proc) */ char* Process::default_tty="/dev/tty"; u32 Process::proc_pid=0; Process::~Process(){ delete ipc; arch.change_process_father(this,pparent); //on change le pere des enfants } Process::Process(char* n) : File(n,TYPE_PROCESS) { fsm.addFile("/proc/",this); pparent=arch.pcurrent; pid=proc_pid; proc_pid++; if (pparent!=NULL) cdir=pparent->getCurrentDir(); else cdir=fsm.getRoot(); arch.addProcess(this); info.vinfo=(void*)this; int i; for (i=0;iisEmpty()); ret=ipc->get(buffer,sizee); arch.disable_interrupt(); return ret; } u32 Process::write(u32 pos,u8* buffer,u32 sizee){ ipc->add(buffer,sizee); return size; } u32 Process::ioctl(u32 id,u8* buffer){ u32 ret; switch (id){ case API_PROC_GET_PID: ret= pid; break; case API_PROC_GET_INFO: reset_pinfo(); memcpy((char*)buffer,(char*)&ppinfo,sizeof(proc_info)); break; default: ret=NOT_DEFINED; break; } return ret; } int Process::fork(){ /*Process* p=new Process("fork_child"); return arch.fork(p->getPInfo(),&info);*/ if (pparent!=NULL) pparent->sendSignal(SIGCHLD); return 0; } u32 Process::wait(){ arch.enable_interrupt(); while (is_signal(info.signal, SIGCHLD)==0); clear_signal(&(info.signal), SIGCHLD); arch.destroy_all_zombie(); arch.disable_interrupt(); return 1; } u32 Process::remove(){ delete this; return RETURN_OK; } void Process::scan(){ } void Process::exit(){ setState(ZOMBIE); if (pparent!=NULL) pparent->sendSignal(SIGCHLD); } void Process::setPNext(Process* p){ pnext=p; } process_st* Process::getPInfo(){ return &info; } Process* Process::getPNext(){ return pnext; } u32 Process::create(char* file, int argc, char **argv){ int ret=arch.createProc(&info,file,argc,argv); if (ret==1) setState(CHILD); else setState(ZOMBIE); //stdin stdout et stderr du parent if (pparent!=NULL){ memcpy((char*)&openfp[0],(char*)pparent->getFileInfo(0),sizeof(openfile)); memcpy((char*)&openfp[1],(char*)pparent->getFileInfo(1),sizeof(openfile)); memcpy((char*)&openfp[2],(char*)pparent->getFileInfo(2),sizeof(openfile)); addFile(this,0); } else{ addFile(fsm.path(default_tty),0); addFile(fsm.path(default_tty),0); addFile(fsm.path(default_tty),0); } return RETURN_OK; } void Process::setFile(u32 fd,File* fp,u32 ptr, u32 mode){ if (fd<0 || fd>CONFIG_MAX_FILE) return; openfp[fd].fp=fp; openfp[fd].ptr=ptr; openfp[fd].mode=mode; } u32 Process::addFile(File* f,u32 m){ int i; for (i=0;igetName(),i); openfp[i].fp=f; openfp[i].mode=m; openfp[i].ptr=0; return i; } } } File* Process::getFile(u32 fd){ if (fd<0 || fd>CONFIG_MAX_FILE) return NULL; return openfp[fd].fp; } openfile* Process::getFileInfo(u32 fd){ if (fd<0 || fd>CONFIG_MAX_FILE) return NULL; return &openfp[fd]; } void Process::deleteFile(u32 fd){ if (fd<0 || fd>CONFIG_MAX_FILE) return; openfp[fd].fp=NULL; openfp[fd].mode=0; openfp[fd].ptr=0; } Process* Process::schedule(){ Process* n=this; int out=1; n=n->getPNext(); while (out){ if (n==NULL){ n=arch.plist; } //io.print("testing %s\n",n->getName()); if (n->getState() !=ZOMBIE){ out=0; } else{ n=n->getPNext(); } } arch.pcurrent=n; return n; } File* Process::getCurrentDir(){ return cdir; } void Process::setCurrentDir(File* f){ cdir=f; } void Process::setState(u8 st){ state=st; } u8 Process::getState(){ return state; } void Process::setPid(u32 st){ pid=st; } u32 Process::getPid(){ return pid; } void Process::sendSignal(int sig){ set_signal(&(info.signal),sig); } void Process::reset_pinfo(){ strncpy(ppinfo.name,name,32); ppinfo.pid=pid; ppinfo.tid=0; ppinfo.state=state; ppinfo.vmem=10*1024*1024; ppinfo.pmem=10*1024*1024; } ================================================ FILE: src/kernel/core/process.h ================================================ #ifndef PROC_H #define PROC_H #include #include #include /* definition de process_st */ #include #include #include #define ZOMBIE PROC_STATE_ZOMBIE #define CHILD PROC_STATE_RUN struct openfile { u32 mode; /* Mode d'ouverture */ u32 ptr; /* Pointeur de lecture/ecriture */ File* fp; /* Fichier ouvert */ }; class Process : public File { public: Process(char* n); ~Process(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); u32 create(char* file, int argc, char **argv); void sendSignal(int sig); u32 wait(); u32 addFile(File* fp,u32 m); File* getFile(u32 fd); void deleteFile(u32 fd); openfile* getFileInfo(u32 fd); void exit(); int fork(); void setState(u8 st); u8 getState(); void setFile(u32 fd,File* fp,u32 ptr, u32 mode); void setPid(u32 st); u32 getPid(); void setPNext(Process* p); Process* schedule(); Process* getPNext(); Process* getPParent(); process_st* getPInfo(); void setPParent(Process*p); void reset_pinfo(); process_st info; File* getCurrentDir(); void setCurrentDir(File* f); protected: static u32 proc_pid; u32 pid; u8 state; Process* pparent; Process* pnext; openfile openfp[CONFIG_MAX_FILE]; proc_info ppinfo; File* cdir; Buffer* ipc; static char* default_tty; }; #endif ================================================ FILE: src/kernel/core/signal.h ================================================ #ifndef SIGNAL_H #define SIGNAL_H #include #include #define SIGHUP 1 /* Hangup (POSIX). */ #define SIGINT 2 /* Interrupt (ANSI). */ #define SIGQUIT 3 /* Quit (POSIX). */ #define SIGILL 4 /* Illegal instruction (ANSI). */ #define SIGTRAP 5 /* Trace trap (POSIX). */ #define SIGABRT 6 /* Abort (ANSI). */ #define SIGIOT 6 /* IOT trap (4.2 BSD). */ #define SIGBUS 7 /* BUS error (4.2 BSD). */ #define SIGFPE 8 /* Floating-point exception (ANSI). */ #define SIGKILL 9 /* Kill, unblockable (POSIX). */ #define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ #define SIGSEGV 11 /* Segmentation violation (ANSI). */ #define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ #define SIGPIPE 13 /* Broken pipe (POSIX). */ #define SIGALRM 14 /* Alarm clock (POSIX). */ #define SIGTERM 15 /* Termination (ANSI). */ #define SIGSTKFLT 16 /* Stack fault. */ #define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ #define SIGCHLD 17 /* Child status has changed (POSIX). */ #define SIGCONT 18 /* Continue (POSIX). */ #define SIGSTOP 19 /* Stop, unblockable (POSIX). */ #define SIGTSTP 20 /* Keyboard stop (POSIX). */ #define SIGTTIN 21 /* Background read from tty (POSIX). */ #define SIGTTOU 22 /* Background write to tty (POSIX). */ #define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ #define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ #define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ #define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ #define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ #define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ #define SIGPOLL SIGIO /* Pollable event occurred (System V). */ #define SIGIO 29 /* I/O now possible (4.2 BSD). */ #define SIGPWR 30 /* Power failure restart (System V). */ #define SIGSYS 31 /* Bad system call. */ #define SIGEVENT SIGPOLL #define SIGIPC SIGUSR1 #define SIG_DFL 0 /* default signal handling */ #define SIG_IGN 1 /* ignore signal */ #define set_signal(mask, sig) *(mask) |= ((u32) 1 << (sig - 1)) #define clear_signal(mask, sig) *(mask) &= ~((u32) 1 << (sig - 1)) #define is_signal(mask, sig) (mask & ((u32) 1 << (sig - 1))) #endif ================================================ FILE: src/kernel/core/socket.cc ================================================ #include Socket::~Socket(){ } Socket::Socket(char* n) : File(n,TYPE_FILE) { fsm.addFile("/sys/sockets/",this); } u32 Socket::open(u32 flag){ return RETURN_OK; } u32 Socket::close(){ return RETURN_OK; } u32 Socket::read(u8* buffer,u32 size){ return NOT_DEFINED; } u32 Socket::write(u8* buffer,u32 size){ return NOT_DEFINED; } u32 Socket::ioctl(u32 id,u8* buffer){ return NOT_DEFINED; } u32 Socket::remove(){ delete this; } void Socket::scan(){ } ================================================ FILE: src/kernel/core/socket.h ================================================ #ifndef SOCKET_H #define SOCKET_H #include #include class Socket : public File { public: Socket(char* n); ~Socket(); u32 open(u32 flag); u32 close(); u32 read(u8* buffer,u32 size); u32 write(u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); protected: }; #endif ================================================ FILE: src/kernel/core/syscalls.cc ================================================ #include #include #include #define sysc(a,h) add(a,(syscall_handler)h) void Syscalls::init(){ int i; for (i=0;i #include #define NB_SYSCALLS 100 typedef void (*syscall_handler)(void); class Syscalls { public: void init(); void add(u32 num,syscall_handler h); void call(u32 num); protected: syscall_handler calls[NB_SYSCALLS]; }; extern Syscalls syscall; #endif ================================================ FILE: src/kernel/core/system.cc ================================================ #include /** * 10/04/06 (Samy Pess) : creation du fichier * ajout gestion login et variable d'environnement * 10/04/07 (Samy Pess) : la classe System gere maintenant une liste chain des utilisateur (User) **/ /* Cette classe organise le systeme en lui meme : utilisateur, variable, ... */ System::System(){ } System::~System(){ } void System::init(){ var=fsm.path("/sys/env/"); /** System user **/ root=new User("root"); root->setUType(USER_ROOT); actual=new User("liveuser"); /** Environnement variable **/ uservar=new Variable("USER","liveuser"); new Variable("OS_NAME",KERNEL_NAME); new Variable("OS_VERSION",KERNEL_VERSION); new Variable("OS_DATE",KERNEL_DATE); new Variable("OS_TIME",KERNEL_TIME); new Variable("OS_LICENCE",KERNEL_LICENCE); new Variable("COMPUTERNAME",KERNEL_COMPUTERNAME); new Variable("PROCESSOR_IDENTIFIER",KERNEL_PROCESSOR_IDENTIFIER); new Variable("PROCESSOR_NAME",arch.detect()); new Variable("PATH","/bin/"); new Variable("SHELL","/bin/sh"); } //fonction de login int System::login(User* us,char* pass){ if (us==NULL) return ERROR_PARAM; if (us->getPassword() != NULL){ //si il ya un password if (pass==NULL) //si on a pass un code return PARAM_NULL; // if (strncmp(pass,us->getPassword(),strlen(us->getPassword()))) //test password return RETURN_FAILURE; //io.print("login %s with %s (%s)\n",us->getName(),pass,us->getPassword()); } uservar->write(0,(u8*)us->getName(),strlen(us->getName())); actual=us; return RETURN_OK; } /* ne pas oubliez de faire un free de la variable */ char* System::getvar(char* name){ char* varin; File* temp=var->find(name); if (temp==NULL){ return NULL; } varin=(char*)kmalloc(temp->getSize()); memset(varin,0,temp->getSize()); temp->read(0,(u8*)varin,temp->getSize()); return varin; } User* System::getUser(char* nae){ User* us=listuser; while (us!=NULL){ //io.print("test '%s' with '%s'\n",nae,us->getName()); if (!strncmp(nae,us->getName(),strlen(us->getName()))) return us; us=us->getUNext(); } return NULL; } void System::addUserToList(User* us){ if (us==NULL) return; us->setUNext(listuser); listuser=us; } u32 System::isRoot(){ if (actual!=NULL){ if (actual->getUType() == USER_ROOT) return 1; else return 0; } else return 0; } ================================================ FILE: src/kernel/core/system.h ================================================ #ifndef SYSTEM_H #define SYSTEM_H #include #include #include class System { public: System(); ~System(); void init(); char* getvar(char* name); void addUserToList(User* us); User* getUser(char* nae); int login(User* us,char* pass); u32 isRoot(); //renvoie 1 si root private: User* listuser; File* var; User* actual; User* root; Variable* uservar; }; extern System sys; #endif ================================================ FILE: src/kernel/core/user.cc ================================================ #include User::~User(){ } User::User(char* n) : File(n,TYPE_FILE) { fsm.addFile("/sys/usr/",this); unext=0; sys.addUserToList(this); utype=USER_NORM; memset(password,0,512); } u32 User::open(u32 flag){ return RETURN_OK; } u32 User::close(){ return RETURN_OK; } u32 User::read(u8* buffer,u32 size){ return NOT_DEFINED; } u32 User::write(u8* buffer,u32 size){ return NOT_DEFINED; } u32 User::ioctl(u32 id,u8* buffer){ return NOT_DEFINED; } u32 User::remove(){ delete this; } void User::scan(){ } void User::setPassword(char *n){ if (n!=NULL) return; memset(password,0,512); strcpy(password,n); } char* User::getPassword(){ if (password[0]=0) return NULL; else return password; } User* User::getUNext(){ return unext; } void User::setUNext(User* us){ unext=us; } void User::setUType(u32 t){ utype=t; } u32 User::getUType(){ return utype; } ================================================ FILE: src/kernel/core/user.h ================================================ #ifndef USER_H #define USER_H #include #include enum { USER_ROOT, //root USER_NORM //utilisateur normal }; class User : public File { public: User(char* n); ~User(); u32 open(u32 flag); u32 close(); u32 read(u8* buffer,u32 size); u32 write(u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); void setPassword(char *n); char* getPassword(); User* getUNext(); void setUNext(User* us); void setUType(u32 t); u32 getUType(); protected: u32 utype; User* unext; char password[512]; }; #endif ================================================ FILE: src/kernel/modules/Makefile ================================================ OBJS:= $(OBJS) modules/module.o \ modules/null.o modules/stdtty.o modules/x86serial.o\ modules/ide.o modules/bochsvbe.o \ modules/ext2.o modules/dospartition.o \ modules/clock_x86.o modules/keys.o ================================================ FILE: src/kernel/modules/bochsvbe.cc ================================================ #include #include /* Driver video pour bios VBE/Bios */ static void BgaWriteRegister(unsigned short IndexValue, unsigned short DataValue) { io.outw(VBE_DISPI_IOPORT_INDEX, IndexValue); io.outw(VBE_DISPI_IOPORT_DATA, DataValue); } static unsigned short BgaReadRegister(unsigned short IndexValue) { io.outw(VBE_DISPI_IOPORT_INDEX, IndexValue); return io.inw(VBE_DISPI_IOPORT_DATA); } static int BgaIsAvailable(void) { return (BgaReadRegister(VBE_DISPI_INDEX_ID) == VBE_DISPI_ID4); } static void BgaSetVideoMode(unsigned int Width, unsigned int Height, unsigned int BitDepth, int UseLinearFrameBuffer, int ClearVideoMemory) { BgaWriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); BgaWriteRegister(VBE_DISPI_INDEX_XRES, Width); BgaWriteRegister(VBE_DISPI_INDEX_YRES, Height); BgaWriteRegister(VBE_DISPI_INDEX_BPP, BitDepth); BgaWriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | (UseLinearFrameBuffer ? VBE_DISPI_LFB_ENABLED : 0) | (ClearVideoMemory ? 0 : VBE_DISPI_NOCLEARMEM)); } static void BgaSetBank(unsigned short BankNumber) { BgaWriteRegister(VBE_DISPI_INDEX_BANK, BankNumber); } File* bochs_mknod(char* name,u32 flag,File* dev){ Bochs* cons=new Bochs(name); return cons; } module("module.bvbe",MODULE_DEVICE,Bochs,bochs_mknod) Bochs::~Bochs(){ } Bochs::Bochs(char* n) : Device(n) { fbinfo_best.w=1024; fbinfo_best.h=768; fbinfo_best.bpp=32; fbinfo_best.state=FB_ACTIVE; fbinfo_best.vmem=(unsigned int*)VBE_DISPI_LFB_PHYSICAL_ADDRESS; fbinfo.w=0; fbinfo.h=0; fbinfo.bpp=0; fbinfo.state=FB_NOT_ACTIVE; fbinfo.vmem=(unsigned int*)VBE_DISPI_LFB_PHYSICAL_ADDRESS; map_memory=(char*)VBE_DISPI_LFB_PHYSICAL_ADDRESS; } u32 Bochs::open(u32 flag){ return RETURN_OK; } u32 Bochs::read(u32 pos,u8* buffer,u32 size){ return NOT_DEFINED; } u32 Bochs::write(u32 pos,u8* buffer,u32 size){ return NOT_DEFINED; } u32 Bochs::close(){ return RETURN_OK; } void Bochs::scan(){ } u32 Bochs::ioctl(u32 id,u8* buffer){ u32 ret=0; switch (id){ case DEV_GET_TYPE: ret=DEV_TYPE_FB; break; case DEV_GET_STATE: ret=DEV_STATE_OK; break; case DEV_GET_FORMAT: ret=DEV_FORMAT_FB; break; case API_FB_IS_AVAILABLE: ret=(u32)BgaIsAvailable(); break; case API_FB_GET_INFO: memcpy((char*)buffer,(char*)&fbinfo,sizeof(fb_info)); break; case API_FB_SET_INFO: memcpy((char*)&fbinfo,(char*)buffer,sizeof(fb_info)); BgaSetVideoMode(fbinfo.w, fbinfo.h, (unsigned int)fbinfo.bpp/8, 1, 1); break; case API_FB_GET_BINFO: memcpy((char*)buffer,(char*)&fbinfo_best,sizeof(fb_info)); break; default: ret=NOT_DEFINED; break; } return ret; } u32 Bochs::remove(){ delete this; return RETURN_OK; } ================================================ FILE: src/kernel/modules/bochsvbe.h ================================================ #ifndef __BOCHS_VBE__ #define __BOCHS_VBE__ #include #include #include #include #include #define VBE_DISPI_ENABLED (0x01) #define VBE_DISPI_DISABLED (0x00) #define VBE_DISPI_INDEX_ENABLE (4) #define VBE_DISPI_ID4 (0xB0C4) #define VBE_DISPI_LFB_ENABLED (0x40) #define VBE_DISPI_NOCLEARMEM (0x80) #define VBE_DISPI_IOPORT_INDEX (0x01CE) #define VBE_DISPI_INDEX_ID (0) #define VBE_DISPI_INDEX_XRES (1) #define VBE_DISPI_INDEX_YRES (2) #define VBE_DISPI_INDEX_BPP (3) #define VBE_DISPI_INDEX_ENABLE (4) #define VBE_DISPI_INDEX_BANK (5) #define VBE_DISPI_INDEX_VIRT_WIDTH (6) #define VBE_DISPI_INDEX_VIRT_HEIGHT (7) #define VBE_DISPI_INDEX_X_OFFSET (8) #define VBE_DISPI_INDEX_Y_OFFSET (9) #define VBE_DISPI_IOPORT_DATA (0x01CF) #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 class Bochs : public Device { public: Bochs(char* n); ~Bochs(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); private: fb_info fbinfo_best; fb_info fbinfo; }; #endif ================================================ FILE: src/kernel/modules/clock_x86.cc ================================================ #include #include #include static void GetWeekday(unsigned int *Weekday) { unsigned int DataWeekday; io.outb(0x70, 0x95); io.outb(0x70, 6); DataWeekday = io.inb(0x71); if(DataWeekday<6) *Weekday = DataWeekday + 2; else *Weekday = DataWeekday - 5; } static void GetDate(unsigned int *Year, unsigned int *Month, unsigned int *Day) { unsigned int DataYear, DataMonth, DataDay; io.outb(0x70, 0x95); io.outb(0x70, 9); DataYear = io.inb(0x71); *Year = DataYear - ((unsigned int) DataYear/16) * 6; io.outb(0x70, 8); DataMonth = io.inb(0x71); *Month = DataMonth - ((unsigned int) DataMonth/16) * 6; io.outb(0x70, 7); DataDay = io.inb(0x71); *Day = DataDay - ((unsigned int) DataDay/16) * 6; } static void GetTime(unsigned int *Hour, unsigned int *Minute, unsigned int *Second) { unsigned int DataHour, DataMinute, DataSecond; io.outb(0x70, 0x95); io.outb(0x70, 4); DataHour = io.inb(0x71); *Hour = DataHour - ((unsigned int) DataHour/16) * 6; io.outb(0x70, 2); DataMinute = io.inb(0x71); *Minute = DataMinute - ((unsigned int) DataMinute/16) * 6; io.outb(0x70, 0); DataSecond = io.inb(0x71); *Second = DataSecond - ((unsigned int) DataSecond/16) * 6; } File* clockx86_mknod(char* name,u32 flag,File* dev){ Clock_x86* cons=new Clock_x86(name); return cons; } module("module.clock_x86",MODULE_DEVICE,Clock_x86,clockx86_mknod) Clock_x86::~Clock_x86(){ } Clock_x86::Clock_x86(char* n) : Device(n) { } void Clock_x86::scan(){ } u32 Clock_x86::close(){ return RETURN_OK; } u32 Clock_x86::open(u32 flag){ return RETURN_OK; } u32 Clock_x86::read(u32 pos,u8* buffer,u32 size){ return NOT_DEFINED; } u32 Clock_x86::write(u32 pos,u8* buffer,u32 size){ return NOT_DEFINED; } void Clock_x86::reset_info(){ GetDate(&(cinfo.year),&(cinfo.month), &(cinfo.day)); GetTime(&(cinfo.h),&(cinfo.m), &(cinfo.s)); } u32 Clock_x86::ioctl(u32 id,u8* buffer){ u32 ret=0; switch (id){ case DEV_GET_TYPE: ret=DEV_TYPE_TTY; break; case DEV_GET_STATE: ret=DEV_STATE_OK; break; case DEV_GET_FORMAT: ret=DEV_FORMAT_CHAR; break; case API_CLOCK_GET_INFO: reset_info(); memcpy((char*)buffer,(char*)&cinfo,sizeof(clock_info)); break; default: ret=NOT_DEFINED; } return ret; } u32 Clock_x86::remove(){ delete this; return RETURN_OK; } ================================================ FILE: src/kernel/modules/clock_x86.h ================================================ #ifndef __CLOCK__ #define __CLOCK__ #include #include #include #include class Clock_x86 : public Device { public: Clock_x86(char* n); ~Clock_x86(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); void reset_info(); private: clock_info cinfo; }; #endif ================================================ FILE: src/kernel/modules/dospartition.cc ================================================ #include #include /* * Flag indique le numero de partition */ File* dospartition_mount(char* name,u32 flag,File* dev){ DosPartition* dos=new DosPartition(name,dev,flag); return dos; } module("module.dospartition",MODULE_FILESYSTEM,DosPartition,dospartition_mount) DosPartition::~DosPartition(){ } DosPartition::DosPartition(char* n,File* dev,u32 num) : Device(n) { device=dev; numpart=num; partition_info=NULL; if (device!=NULL){ partition_info=(dos_partition*)kmalloc(sizeof(dos_partition)); device->read((u32)(DOS_PART_1+(u32)(numpart*sizeof(dos_partition))), (u8*)partition_info, sizeof(dos_partition)); } } void DosPartition::scan(){ } u32 DosPartition::close(){ if (partition_info!=NULL && device!=NULL){ return device->close(); } return ERROR_PARAM; } u32 DosPartition::open(u32 flag){ if (partition_info!=NULL && device!=NULL){ return device->open(flag); } return ERROR_PARAM; } u32 DosPartition::read(u32 pos,u8* buffer,u32 sizee){ if (partition_info!=NULL && device!=NULL){ return device->read(((partition_info->s_lba)*512)+pos,buffer,sizee); } return ERROR_PARAM; } u32 DosPartition::write(u32 pos,u8* buffer,u32 sizee){ if (partition_info!=NULL && device!=NULL){ return device->write((partition_info->s_lba*512)+pos,buffer,sizee); } return ERROR_PARAM; } u32 DosPartition::ioctl(u32 id,u8* buffer){ if (partition_info!=NULL && device!=NULL){ return device->ioctl(id,buffer); } return ERROR_PARAM; } u32 DosPartition::remove(){ delete this; return RETURN_OK; } ================================================ FILE: src/kernel/modules/dospartition.h ================================================ #ifndef __DOS_PARTITION__ #define __DOS_PARTITION__ #include #include #include #define DOS_PART_1 0x01BE #define DOS_PART_2 0x01CE #define DOS_PART_3 0x01DE #define DOS_PART_4 0x01EE struct dos_partition { u8 bootable; /* 0 = no, 0x80 = bootable */ u8 s_head; /* Starting head */ u16 s_sector:6; /* Starting sector */ u16 s_cyl:10; /* Starting cylinder */ u8 id; /* System ID */ u8 e_head; /* Ending Head */ u16 e_sector:6; /* Ending Sector */ u16 e_cyl:10; /* Ending Cylinder */ u32 s_lba; /* Starting LBA value */ u32 size; /* Total Sectors in partition */ } __attribute__ ((packed)); /* * Driver class */ class DosPartition : public Device { public: DosPartition(char* n,File* dev,u32 num); ~DosPartition(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 sizee); u32 write(u32 pos,u8* buffer,u32 sizee); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); private: u32 numpart; dos_partition* partition_info; }; #endif ================================================ FILE: src/kernel/modules/ext2.cc ================================================ #include #include File* ext2_mount(char* name,u32 flag,File* dev){ int ret=ext2_check_disk(dev); if (ret!=RETURN_OK){ io.print("ext2: can't mount %s in %s \n",dev->getName(),name); return NULL; } else{ io.print("ext2: mount %s in %s \n",dev->getName(),name); Ext2* ret=new Ext2(name); ret->ext2inode=EXT2_INUM_ROOT; ext2_get_disk_info(dev,ret); ret->scan(); return ret; } } module("module.ext2",MODULE_FILESYSTEM,Ext2,ext2_mount) Ext2::~Ext2(){ } Ext2::Ext2(char* n) : File(n,TYPE_DIRECTORY) { map=NULL; } void Ext2::scan(){ ext2_scan(this); } u32 Ext2::close(){ return NOT_DEFINED; } u32 Ext2::open(u32 flag){ ext2_inode *inodee=ext2_read_inode(disk,ext2inode); map=ext2_read_file(disk,inodee); kfree(inodee); return RETURN_OK; } u32 Ext2::read(u32 pos,u8* buffer,u32 sizee){ u32 bufsize=sizee; if ((pos + bufsize) > (size)) bufsize = (u32)(size) - pos; memcpy((char*)buffer, (char *) (map + pos), bufsize); return bufsize; } u32 Ext2::write(u32 pos,u8* buffer,u32 sizee){ return NOT_DEFINED; } u32 Ext2::ioctl(u32 id,u8* buffer){ return NOT_DEFINED; } u32 Ext2::remove(){ delete this; return RETURN_OK; } /* * EXT2 specification */ int ext2_read_sb(File* dev,ext2_super_block *sb) { if (dev!=NULL){ dev->read((u32)1024,(u8 *) sb,sizeof(ext2_super_block)); return RETURN_OK; } else return ERROR_PARAM; } int ext2_read_gd(File* fdev,ext2_group_desc *gd,ext2_disk* info) { if (fdev!=NULL){ u32 offset; offset = ((info->blocksize == 1024) ? 2048 : info->blocksize); int gd_size = (info->groups * ((int)sizeof(struct ext2_group_desc))); fdev->read(offset,(u8*) gd,gd_size); return RETURN_OK; } else return ERROR_PARAM; } void ext2_get_disk_info(File*dev,Ext2 *fp) { ext2_disk* info=(ext2_disk*)kmalloc(sizeof(ext2_disk)); info->sb=(ext2_super_block*)kmalloc(sizeof(ext2_super_block)); info->dev=dev; int i, j; ext2_read_sb(dev,info->sb); info->blocksize = 1024 << ((info->sb)->s_log_block_size); i = (info->sb->s_blocks_count / info->sb->s_blocks_per_group) + ((info->sb->s_blocks_count % info->sb->s_blocks_per_group) ? 1 : 0); j = (info->sb->s_inodes_count / info->sb->s_inodes_per_group) + ((info->sb->s_inodes_count % info->sb->s_inodes_per_group) ? 1 : 0); info->groups = (i > j) ? i : j; int gd_size = info->groups * ((int)sizeof(ext2_group_desc)); info->gd = (ext2_group_desc *) kmalloc(gd_size); ext2_read_gd(info->dev,info->gd,info); fp->disk=info; return; } int ext2_check_disk(File *dev) { ext2_super_block *sb=(ext2_super_block *)kmalloc(sizeof(ext2_super_block)); if (ext2_read_sb(dev,sb)!=RETURN_OK) return ERROR_PARAM; if (sb->s_magic==0xEF53){ kfree(sb); return RETURN_OK; } else{ kfree(sb); return ERROR_PARAM; } } ext2_inode *ext2_read_inode(ext2_disk* hd, int i_num) { int gr_num, index; u32 offset; ext2_inode *inode; ext2_group_desc * info=hd->gd; inode = (ext2_inode *) kmalloc((hd->sb)->s_inode_size);//sizeof(ext2_inode)); gr_num = (i_num - 1) / ((hd->sb)->s_inodes_per_group); index = (i_num - 1) % ((hd->sb)->s_inodes_per_group); offset = (info[gr_num].bg_inode_table * (hd->blocksize)) + (index * ((hd->sb)->s_inode_size)); if ((hd->dev)!=NULL){ (hd->dev)->read(offset,(u8*) inode,(hd->sb)->s_inode_size); } return inode; } int ext2_is_directory(Ext2 *fp) { ext2_inode *inod=ext2_read_inode(fp->disk,fp->ext2inode); int ret=(inod->i_mode & EXT2_S_IFDIR) ? 1 : 0; kfree(inod); return ret; } char *ext2_read_file(ext2_disk *hd,ext2_inode *inode) { File *dev=hd->dev; char *mmap_base, *mmap_head, *buf; int *p, *pp, *ppp; int i, j, k; int n, size; buf = (char *) kmalloc(hd->blocksize); p = (int *) kmalloc(hd->blocksize); pp = (int *) kmalloc(hd->blocksize); ppp = (int *) kmalloc(hd->blocksize); /* taille totale du fichier */ size = inode->i_size; mmap_head = mmap_base = (char*)kmalloc(size); /* direct block number */ for (i = 0; i < 12 && inode->i_block[i]; i++) { dev->read((u32)(inode->i_block[i] * hd->blocksize),(u8*) buf, (hd->blocksize)); n = ((size > (int)hd->blocksize) ? (int)hd->blocksize : size); memcpy(mmap_head, buf, n); mmap_head += n; size -= n; } /* indirect block number */ if (inode->i_block[12]) { dev->read((u32)(inode->i_block[12] * hd->blocksize), (u8*) p, (hd->blocksize)); for (i = 0; i < (int)hd->blocksize / 4 && p[i]; i++) { dev->read((u32)(p[i] * hd->blocksize),(u8*)buf, (hd->blocksize)); n = ((size > (int)hd->blocksize) ? (int)hd->blocksize : size); memcpy(mmap_head, buf, n); mmap_head += n; size -= n; } } /* bi-indirect block number */ if (inode->i_block[13]) { dev->read((u32)(inode->i_block[13] * hd->blocksize), (u8*) p, (hd->blocksize)); for (i = 0; i < (int)hd->blocksize / 4 && p[i]; i++) { dev->read((u32)(p[i] * (int)hd->blocksize), (u8*) pp,(hd->blocksize)); for (j = 0; j < (int)hd->blocksize / 4 && pp[j]; j++) { dev->read((u32)(pp[j] * hd->blocksize),(u8*)buf,(hd->blocksize)); n = ((size > (int)hd-> blocksize) ? (int)hd->blocksize : size); memcpy(mmap_head, buf, n); mmap_head += n; size -= n; } } } /* tri-indirect block number */ if (inode->i_block[14]) { dev->read((u32)(inode->i_block[14] * hd->blocksize), (u8*) p,(hd->blocksize)); for (i = 0; i < (int)hd->blocksize / 4 && p[i]; i++) { dev->read((u32)(p[i] * hd->blocksize), (u8*) pp,(hd->blocksize)); for (j = 0; j < (int)hd->blocksize / 4 && pp[j]; j++) { dev->read((u32)(pp[j] * hd->blocksize), (u8*) ppp,(hd->blocksize)); for (k = 0; k < (int)hd->blocksize / 4 && ppp[k]; k++) { dev->read((u32)(ppp[k] * hd->blocksize),(u8*)buf,(hd->blocksize)); n = ((size > (int)hd->blocksize) ? (int)hd->blocksize : size); memcpy(mmap_head, buf, n); mmap_head += n; size -= n; } } } } kfree(buf); kfree(p); kfree(pp); kfree(ppp);; return mmap_base; } int ext2_scan(Ext2 *dir) { ext2_directory_entry *dentry; Ext2 *leaf; u32 dsize; char *filename; int f_toclose; ext2_inode *inode = ext2_read_inode(dir->disk, dir->ext2inode); if (dir->getType()!=TYPE_DIRECTORY) { return ERROR_PARAM; } if (!dir->map) { dir->map = ext2_read_file(dir->disk, inode); f_toclose = 1; } else { f_toclose = 0; } dsize = inode->i_size; dentry = (ext2_directory_entry *) dir->map; while (inode && dsize) { filename = (char *) kmalloc(dentry->name_len + 1); memcpy(filename,(char*)&(dentry->name), dentry->name_len); filename[dentry->name_len] = 0; if (strcmp(".", filename) && strcmp("..", filename)) { if (dir->find(filename)==NULL) { leaf= new Ext2(filename); leaf->ext2inode = dentry->inode; leaf->disk=dir->disk; if (ext2_is_directory(leaf)) leaf->setType(TYPE_DIRECTORY); else leaf->setType(TYPE_FILE); dir->addChild(leaf); leaf->map = 0; ext2_inode *inod=ext2_read_inode((ext2_disk*)leaf->disk,leaf->ext2inode); leaf->setSize(inod->i_size); kfree(inod); } } kfree(filename); dsize -= dentry->rec_len; dentry = (ext2_directory_entry *) ((char *) dentry + dentry->rec_len); } kfree(inode); if (f_toclose == 1) { kfree(dir->map); dir->map = 0; } return 0; } ================================================ FILE: src/kernel/modules/ext2.h ================================================ #ifndef __EXT2__ #define __EXT2__ #include #include #include /* * Ext2 specification */ struct ext2_super_block { u32 s_inodes_count; /* Total number of inodes */ u32 s_blocks_count; /* Total number of blocks */ u32 s_r_blocks_count; /* Total number of blocks reserved for the super user */ u32 s_free_blocks_count; /* Total number of free blocks */ u32 s_free_inodes_count; /* Total number of free inodes */ u32 s_first_data_block; /* Id of the block containing the superblock structure */ u32 s_log_block_size; /* Used to compute block size = 1024 << s_log_block_size */ u32 s_log_frag_size; /* Used to compute fragment size */ u32 s_blocks_per_group; /* Total number of blocks per group */ u32 s_frags_per_group; /* Total number of fragments per group */ u32 s_inodes_per_group; /* Total number of inodes per group */ u32 s_mtime; /* Last time the file system was mounted */ u32 s_wtime; /* Last write access to the file system */ u16 s_mnt_count; /* How many `mount' since the last was full verification */ u16 s_max_mnt_count; /* Max count between mount */ u16 s_magic; /* = 0xEF53 */ u16 s_state; /* File system state */ u16 s_errors; /* Behaviour when detecting errors */ u16 s_minor_rev_level; /* Minor revision level */ u32 s_lastcheck; /* Last check */ u32 s_checkinterval; /* Max. time between checks */ u32 s_creator_os; /* = 5 */ u32 s_rev_level; /* = 1, Revision level */ u16 s_def_resuid; /* Default uid for reserved blocks */ u16 s_def_resgid; /* Default gid for reserved blocks */ u32 s_first_ino; /* First inode useable for standard files */ u16 s_inode_size; /* Inode size */ u16 s_block_group_nr; /* Block group hosting this superblock structure */ u32 s_feature_compat; u32 s_feature_incompat; u32 s_feature_ro_compat; u8 s_uuid[16]; /* Volume id */ char s_volume_name[16]; /* Volume name */ char s_last_mounted[64]; /* Path where the file system was last mounted */ u32 s_algo_bitmap; /* For compression */ u8 s_padding[820]; } __attribute__ ((packed)); struct ext2_group_desc { u32 bg_block_bitmap; /* Id of the first block of the "block bitmap" */ u32 bg_inode_bitmap; /* Id of the first block of the "inode bitmap" */ u32 bg_inode_table; /* Id of the first block of the "inode table" */ u16 bg_free_blocks_count; /* Total number of free blocks */ u16 bg_free_inodes_count; /* Total number of free inodes */ u16 bg_used_dirs_count; /* Number of inodes allocated to directories */ u16 bg_pad; /* Padding the structure on a 32bit boundary */ u32 bg_reserved[3]; /* Future implementation */ } __attribute__ ((packed)); struct ext2_inode { u16 i_mode; /* File type + access rights */ u16 i_uid; u32 i_size; u32 i_atime; u32 i_ctime; u32 i_mtime; u32 i_dtime; u16 i_gid; u16 i_links_count; u32 i_blocks; /* 512 bytes blocks ! */ u32 i_flags; u32 i_osd1; /* * [0] -> [11] : block number (32 bits per block) * [12] : indirect block number * [13] : bi-indirect block number * [14] : tri-indirect block number */ u32 i_block[15]; u32 i_generation; u32 i_file_acl; u32 i_dir_acl; u32 i_faddr; u8 i_osd2[12]; } __attribute__ ((packed)); struct ext2_directory_entry { u32 inode; /* inode number or 0 (unused) */ u16 rec_len; /* offset to the next dir. entry */ u8 name_len; /* name length */ u8 file_type; char name; } __attribute__ ((packed)); struct ext2_disk { ext2_super_block* sb; ext2_group_desc* gd; u32 blocksize; u16 groups; /* Total number of groups */ File* dev; }; /* super_block: s_errors */ #define EXT2_ERRORS_CONTINUE 1 #define EXT2_ERRORS_RO 2 #define EXT2_ERRORS_PANIC 3 #define EXT2_ERRORS_DEFAULT 1 /* inode: i_mode */ #define EXT2_S_IFMT 0xF000 /* format mask */ #define EXT2_S_IFSOCK 0xC000 /* socket */ #define EXT2_S_IFLNK 0xA000 /* symbolic link */ #define EXT2_S_IFREG 0x8000 /* regular file */ #define EXT2_S_IFBLK 0x6000 /* block device */ #define EXT2_S_IFDIR 0x4000 /* directory */ #define EXT2_S_IFCHR 0x2000 /* character device */ #define EXT2_S_IFIFO 0x1000 /* fifo */ #define EXT2_S_ISUID 0x0800 /* SUID */ #define EXT2_S_ISGID 0x0400 /* SGID */ #define EXT2_S_ISVTX 0x0200 /* sticky bit */ #define EXT2_S_IRWXU 0x01C0 /* user access rights mask */ #define EXT2_S_IRUSR 0x0100 /* read */ #define EXT2_S_IWUSR 0x0080 /* write */ #define EXT2_S_IXUSR 0x0040 /* execute */ #define EXT2_S_IRWXG 0x0038 /* group access rights mask */ #define EXT2_S_IRGRP 0x0020 /* read */ #define EXT2_S_IWGRP 0x0010 /* write */ #define EXT2_S_IXGRP 0x0008 /* execute */ #define EXT2_S_IRWXO 0x0007 /* others access rights mask */ #define EXT2_S_IROTH 0x0004 /* read */ #define EXT2_S_IWOTH 0x0002 /* write */ #define EXT2_S_IXOTH 0x0001 /* execute */ #define EXT2_INUM_ROOT 2 /* * Driver class */ class Ext2 : public File { public: Ext2(char* n); ~Ext2(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 sizee); u32 write(u32 pos,u8* buffer,u32 sizee); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); char* map; ext2_disk* disk; int ext2inode; private: }; int ext2_check_disk(File *dev); void ext2_get_disk_info(File*dev,Ext2 *fp); int ext2_read_gd(File* fdev,ext2_group_desc *gd,ext2_disk* info); int ext2_read_sb(File* dev,ext2_super_block *sb); ext2_inode* ext2_read_inode(ext2_disk* hd, int i_num); int ext2_is_directory(Ext2 *fp); int ext2_scan(Ext2 *dir); char * ext2_read_file(ext2_disk *hd,ext2_inode *inode); #endif ================================================ FILE: src/kernel/modules/ide.cc ================================================ #include #include #include /* * Cette fonction attend que le disque soit pret avant une operation */ int bl_wait(unsigned short base) { while(io.inb(base+0x206) & 0x80); return 0; } /* * Cette fonction permet de ce deplacer sur le disque */ int bl_common(int drive, int numblock, int count) { bl_wait(0x1F0); io.outb(0x1F1, 0x00); /* NULL byte to port 0x1F1 */ io.outb(0x1F2, count); /* Sector count */ io.outb(0x1F3, (unsigned char) numblock); /* Low 8 bits of the block address */ io.outb(0x1F4, (unsigned char) (numblock >> 8)); /* Next 8 bits of the block address */ io.outb(0x1F5, (unsigned char) (numblock >> 16)); /* Next 8 bits of the block address */ /* Drive indicator, magic bits, and highest 4 bits of the block address */ io.outb(0x1F6, 0xE0 | (drive << 4) | ((numblock >> 24) & 0x0F)); return 0; } /* * Cette fonction permet de lire un buffer sur le disque */ int bl_read(int drive, int numblock, int count, char *buf) { u16 tmpword; int idx; bl_common(drive, numblock, count); io.outb(0x1F7, 0x20); bl_wait(0x1F0); while (!(io.inb(0x1F7) & 0x08)); for (idx = 0; idx < 256 * count; idx++) { tmpword = io.inw(0x1F0); buf[idx * 2] = (unsigned char) tmpword; buf[idx * 2 + 1] = (unsigned char) (tmpword >> 8); } return count; } /* * Cette fonction permet d'ecrire un buffer sur le disque */ int bl_write(int drive, int numblock, int count, char *buf) { u16 tmpword; int idx; bl_common(drive, numblock, count); io.outb(0x1F7, 0x30); bl_wait(0x1F0); /* Wait for the drive to signal that it's ready: */ while (!(io.inb(0x1F7) & 0x08)); for (idx = 0; idx < 256 * count; idx++) { tmpword = (buf[idx * 2 + 1] << 8) | buf[idx * 2]; io.outw(0x1F0, tmpword); } return count; } File* ide_mknod(char* name,u32 flag,File* dev){ Ide* disk=new Ide(name); disk->setId(flag); return disk; } module("module.ide",MODULE_DEVICE,Ide,ide_mknod) Ide::~Ide(){ } Ide::Ide(char* n) : Device(n) { } u32 Ide::close(){ return RETURN_OK; } void Ide::scan(){ } u32 Ide::open(u32 flag){ return RETURN_OK; } u32 Ide::read(u32 pos,u8* buffer,u32 sizee){ int count=(int)sizee; if (buffer==NULL) return -1; int offset=(int)pos; int bl_begin, bl_end, blocks; bl_begin = (offset/512); bl_end = ((offset + count)/512); blocks = bl_end - bl_begin + 1; //io.print("%s> read at %d - %d size=%d begin=%d blocks=%d\n",getName(),offset,offset/512,count,bl_begin,blocks); char*bl_buffer = (char *) kmalloc(blocks * 512); bl_read(id, bl_begin, blocks,bl_buffer); memcpy((char*)buffer, (char *) ((int)bl_buffer + ((int)offset % (int)(512))), count); kfree(bl_buffer); return count; } u32 Ide::write(u32 pos,u8* buffer,u32 sizee){ return NOT_DEFINED; } u32 Ide::ioctl(u32 idd,u8* buffer){ u32 ret=0; switch (idd){ case DEV_GET_TYPE: ret=DEV_TYPE_DISK; break; case DEV_GET_STATE: ret=DEV_STATE_OK; break; case DEV_GET_FORMAT: ret=DEV_FORMAT_BLOCK; break; default: ret=NOT_DEFINED; break; } return ret; } u32 Ide::remove(){ delete this; return RETURN_OK; } void Ide::setId(u32 flag){ id=flag; } ================================================ FILE: src/kernel/modules/ide.h ================================================ #ifndef __IDE__ #define __IDE__ #include #include #include class Ide : public Device { public: Ide(char* n); ~Ide(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); void setId(u32 flag); private: u32 id; }; #endif ================================================ FILE: src/kernel/modules/keys.cc ================================================ #include #include #include extern char* kbdmap; File* keys_mknod(char* name,u32 flag,File* dev){ Keyboard* cons=new Keyboard(name); return cons; } module("module.keyboard",MODULE_DEVICE,Keyboard,keys_mknod) Keyboard::~Keyboard(){ } Keyboard::Keyboard(char* n) : Device(n) { } void Keyboard::scan(){ } u32 Keyboard::close(){ return RETURN_OK; } u32 Keyboard::open(u32 flag){ return RETURN_OK; } u32 Keyboard::read(u32 pos,u8* buffer,u32 sizee){ return NOT_DEFINED; } u32 Keyboard::write(u32 pos,u8* buffer,u32 sizee){ return NOT_DEFINED; } u32 Keyboard::ioctl(u32 id,u8* buffer){ u32 ret=0; switch (id){ case DEV_GET_TYPE: ret=DEV_TYPE_TTY; break; case DEV_GET_STATE: ret=DEV_STATE_OK; break; case DEV_GET_FORMAT: ret=DEV_FORMAT_CHAR; break; case API_KEYBOARD_SET_TABLE: memcpy(scantable,(char*)buffer,TABLE_KEYBOARD_SIZE); kbdmap=scantable; ret=TABLE_KEYBOARD_SIZE; break; default: ret=NOT_DEFINED; } return ret; } u32 Keyboard::remove(){ delete this; return RETURN_OK; } ================================================ FILE: src/kernel/modules/keys.h ================================================ #ifndef __KEYS__ #define __KEYS__ #include #include #include #include class Keyboard : public Device { public: Keyboard(char* n); ~Keyboard(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); private: char scantable[TABLE_KEYBOARD_SIZE]; }; #endif ================================================ FILE: src/kernel/modules/module.cc ================================================ #include #include #include #include #include #include /* Inclusion de la liste des modules */ #include "modules.conf" Module::Module(){ } Module::~Module(){ } void Module::initLink(){ int i=0; ModLink* mod; while (module_builder[i] != 0){ mod=new ModLink(module_builder[i]->module_name); i=i++; } } File* Module::createDevice(char* name,char* module,u32 flag){ int i=0; File* fp; while (module_builder[i] != 0){ if (!strcmp(module_builder[i]->module_name,module)){ if (module_builder[i]->module_type==MODULE_DEVICE){ fp=module_builder[i]->drive(name,flag,NULL); return fp; } } i=i++; } return NULL; } File* Module::mount(char* dev,char* dir,char* module,u32 flag){ File* fdev=fsm.path(dev); if (fdev==NULL) return NULL; int i=0; File* fp; while (module_builder[i] != 0){ if (!strcmp(module_builder[i]->module_name,module)){ fp=module_builder[i]->drive(dir,flag,fdev); if (module_builder[i]->module_type==MODULE_FILESYSTEM && fp!=NULL){ fsm.addFile("/mnt/",fp); fp->setType(TYPE_DIRECTORY); return fp; } else return NULL; } i=i++; } return NULL; } File* Module::install(char* dir,char* module,u32 flag,char* dev){ File* fdev=fsm.path(dev); if (fdev==NULL) return NULL; int i=0; File* fp; while (module_builder[i] != 0){ if (!strcmp(module_builder[i]->module_name,module)){ if (module_builder[i]->module_type==MODULE_FILESYSTEM){ return module_builder[i]->drive(dir,flag,fdev); } } i=i++; } return NULL; } ================================================ FILE: src/kernel/modules/module.h ================================================ #ifndef __MODULE__ #define __MODULE__ #include #include #include #define NO_FLAG 0 class Module { public: Module(); ~Module(); void initLink(); void init(); File* createDevice(char* name,char* module,u32 flag); File* mount(char* dev,char* dir,char* module,u32 flag); File* install(char* dir,char* module,u32 flag,char* dev); }; extern Module modm; #endif ================================================ FILE: src/kernel/modules/modules.conf ================================================ import_module(Console); import_module(Null); import_module(Ide); import_module(Bochs); import_module(Ext2); import_module(DosPartition); import_module(Keyboard); #ifdef __x86__ import_module(Clock_x86); import_module(X86Serial); #endif run_module_builder{ build_module(Console), build_module(Null), build_module(Ide), build_module(Bochs), build_module(X86Serial), build_module(Ext2), build_module(DosPartition), build_module(Clock_x86), build_module(Keyboard), end_module() }; std_buildin_module{ run_module(module.keyboard,key,NO_FLAG) run_module(module.stdio,tty,1) run_module(module.stdio,tty0,NO_FLAG) run_module(module.stdio,tty1,NO_FLAG) run_module(module.stdio,tty2,NO_FLAG) run_module(module.stdio,tty3,NO_FLAG) #ifdef __x86__ run_module(module.clock_x86,clock,NO_FLAG) /* clock info */ run_module(module.x86serial,ttyS,NO_FLAG) /* serial console */ run_module(module.ide,hda,0) /* hard disk 0 */ run_module(module.ide,hdb,1) /* hard disk 1 */ run_module(module.bvbe,fb0,0) /* BOCHS emulation vbe bios */ #endif run_module(module.null,null,0) run_module(module.zero,zero,0) } ================================================ FILE: src/kernel/modules/null.cc ================================================ #include #include #include File* null_mknod(char* name,u32 flag,File* dev){ Null* cons=new Null(name); return cons; } module("module.null",MODULE_DEVICE,Null,null_mknod) Null::~Null(){ } Null::Null(char* n) : Device(n) { } void Null::scan(){ } u32 Null::close(){ return RETURN_OK; } u32 Null::open(u32 flag){ return RETURN_OK; } u32 Null::read(u32 pos,u8* buffer,u32 size){ memset((char*)buffer,0,size); return size; } u32 Null::write(u32 pos,u8* buffer,u32 size){ return size; } u32 Null::ioctl(u32 id,u8* buffer){ u32 ret=0; switch (id){ case DEV_GET_TYPE: ret=DEV_TYPE_TTY; break; case DEV_GET_STATE: ret=DEV_STATE_OK; break; case DEV_GET_FORMAT: ret=DEV_FORMAT_CHAR; break; default: ret=NOT_DEFINED; } return ret; } u32 Null::remove(){ delete this; return RETURN_OK; } ================================================ FILE: src/kernel/modules/null.h ================================================ #ifndef __NULL__ #define __NULL__ #include #include #include class Null : public Device { public: Null(char* n); ~Null(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); }; #endif ================================================ FILE: src/kernel/modules/stdtty.cc ================================================ #include #include File* console_mknod(char* name,u32 flag,File* dev){ Console* cons=new Console(name,flag); return cons; } module("module.stdio",MODULE_DEVICE,Console,console_mknod) Console::~Console(){ if (iotty!=&io) delete iotty; } Console::Console(char* n,u32 flag) : Device(n) { if (flag==0) iotty=new Io(flag); else iotty=&io; } void Console::reset_info(){ //static info strncpy(sinfo.name,name,TTY_NAME_LEN); sinfo.state=TTY_STATE_RUN; sinfo.type=TTY_TYPE_IOSTD; sinfo.flags=0; //moving info minfo.x=iotty->getX(); minfo.y=iotty->getY(); minfo.attrf=White; minfo.attrb=Black; } void Console::scan(){ } u32 Console::open(u32 flag){ return RETURN_OK; } u32 Console::close(){ return RETURN_OK; } u32 Console::read(u32 pos,u8* buffer,u32 sizee){ return iotty->read((char*)buffer,sizee); } u32 Console::write(u32 pos,u8* buffer,u32 size){ int i; for (i=0;iputc(*buffer); buffer++; } return size; } u32 Console::ioctl(u32 id,u8* buffer){ u32 ret=0; reset_info(); switch (id){ case DEV_GET_TYPE: ret=DEV_TYPE_TTY; break; case DEV_GET_STATE: ret=DEV_STATE_OK; break; case DEV_GET_FORMAT: ret=DEV_FORMAT_CHAR; break; case API_TTY_SWITCH_SCREEN: iotty->switchtty(); break; case API_TTY_CLEAR_SCREEN: iotty->clear(); break; case API_TTY_GET_SINFO: memcpy((char*)buffer,(char*)&sinfo,sizeof(tty_info_static)); break; case API_TTY_GET_MINFO: memcpy((char*)buffer,(char*)&minfo,sizeof(tty_info_moving)); break; case API_TTY_SET_MINFO: break; default: ret=NOT_DEFINED; break; } return ret; } u32 Console::remove(){ delete this; return RETURN_OK; } ================================================ FILE: src/kernel/modules/stdtty.h ================================================ #ifndef __CONSOLE__ #define __CONSOLE__ #include #include #include #include #include class Console : public Device { public: Console(char* n,u32 flag); ~Console(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); void reset_info(); private: tty_info_static sinfo; tty_info_moving minfo; Io* iotty; }; #endif ================================================ FILE: src/kernel/modules/x86serial.cc ================================================ #include #include #include #include u8 X86Serial::init_serial=0; File* x86serial_mknod(char* name,u32 flag,File* dev){ X86Serial* cons=new X86Serial(name); return cons; } module("module.x86serial",MODULE_DEVICE,X86Serial,x86serial_mknod) X86Serial::~X86Serial(){ } X86Serial::X86Serial(char* n) : Device(n) { } void X86Serial::putc(char c){ while(io.inb(COM1 + 5) & 0x20 == 0 ); io.outb(COM1,c); } char X86Serial::getc(){ while(io.inb(COM1 + 5) & 0x1 == 0 ); return (char)io.inb(COM1); } u32 X86Serial::open(u32 flag){ if (init_serial==0){ io.outb( COM1 + 1, 0x00 ); io.outb( COM1 + 3, 0x80 ); io.outb( COM1, 0x03 ); io.outb( COM1 + 1, 0x00 ); io.outb( COM1 + 3, 0x03 ); io.outb( COM1 + 2, 0xC7 ); io.outb( COM1 + 4, 0x0B ); init_serial=1; } return RETURN_OK; } u32 X86Serial::close(){ return RETURN_OK; } void X86Serial::scan(){ } u32 X86Serial::read(u32 pos,u8* buffer,u32 sizee){ int i; for (i=0;i #include #include #define COM1 0x3F8 #define IRQ_COM1 4 #define COM2 2F8 #define IRQ_COM2 3 #define COM3 3E8 #define IRQ_COM3 4 #define COM4 2E8 #define IRQ_COM4 3 class X86Serial : public Device { public: X86Serial(char* n); ~X86Serial(); void putc(char c); char getc(); u32 open(u32 flag); u32 close(); u32 read(u32 pos,u8* buffer,u32 size); u32 write(u32 pos,u8* buffer,u32 size); u32 ioctl(u32 id,u8* buffer); u32 remove(); void scan(); private: static u8 init_serial; }; #endif ================================================ FILE: src/kernel/runtime/Makefile ================================================ OBJS:= $(OBJS) runtime/cxx.o runtime/itoa.o runtime/buffer.o \ runtime/memory.o runtime/string.o ================================================ FILE: src/kernel/runtime/alloc.h ================================================ #ifndef ALLOC_H #define ALLOC_H extern "C" { void *ksbrk(int); void *kmalloc(unsigned long); void kfree(void *); } #endif ================================================ FILE: src/kernel/runtime/buffer.cc ================================================ #include #include Buffer::Buffer(char* n,u32 siz){ map=(char*)kmalloc(siz); size=siz; memcpy(map,n,siz); } Buffer::Buffer(){ size=0; map=NULL; } Buffer::~Buffer(){ if (map!=NULL) kfree(map); } void Buffer::add(u8* c,u32 s){ char* old=map; map=(char*)kmalloc(size+s); memcpy(map,old,size); kfree(old); memcpy((char*)(map+size),(char*)c,s); size=size+s; } u32 Buffer::get(u8* c,u32 s){ if( s>size) s=size; memcpy((char*)c,(char*)(map+(size-s)),s); char*old=map; map=(char*)kmalloc(size-s); memcpy(map,old,(size-s)); kfree(old); size=size-s; return s; } u32 Buffer::isEmpty(){ if (size==0) return 1; else return 0; } void Buffer::clear(){ size=0; if (map!=NULL) kfree(map); } Buffer &Buffer::operator>>(char *c) { memcpy(c,map,size); return *this; } ================================================ FILE: src/kernel/runtime/buffer.h ================================================ #ifndef BUFFER_H #define BUFFER_H class Buffer { public: Buffer(char* n,u32 siz); Buffer(); ~Buffer(); void add(u8* c,u32 s); u32 get(u8* c,u32 s); void clear(); u32 isEmpty(); Buffer &operator>>(char *c); u32 size; char* map; }; #endif ================================================ FILE: src/kernel/runtime/cxx.cc ================================================ #include extern "C" { int __cxa_atexit(void (*Destructor) (void *), void *Parameter, void *HomeDSO); void __cxa_finalize(void *); void __cxa_pure_virtual(); void __stack_chk_guard_setup(); void __attribute__((noreturn)) __stack_chk_fail(); void _Unwind_Resume(); } void *__dso_handle; void *__stack_chk_guard(0); namespace __cxxabiv1 { __extension__ typedef int __guard __attribute__((mode(__DI__))); extern "C" { int __cxa_guard_acquire(__guard *Guard) { return ! *(char *) (Guard); } void __cxa_guard_release(__guard *Guard) { *(char *) Guard = 1; } void __cxa_guard_abort(__guard *) { } } } int __cxa_atexit(void (*) (void *), void *, void *) { return 0; } void _Unwind_Resume(){ } void __cxa_finalize(void *) { } void __cxa_pure_virtual() { } void __stack_chk_guard_setup() { unsigned char *Guard; Guard = (unsigned char *) &__stack_chk_guard; Guard[sizeof(__stack_chk_guard) - 1] = 255; Guard[sizeof(__stack_chk_guard) - 2] = '\n'; Guard[0] = 0; } struct IntRegs; void __attribute__((noreturn)) __stack_chk_fail() { io.print("Buffer Overflow (SSP Signal)\n"); for(;;) ; } void operator delete(void *ptr) { kfree(ptr); } #ifndef __arm__ void* operator new(size_t len) { return (void*)kmalloc(len); } void operator delete[](void *ptr) { ::operator delete(ptr); } void* operator new[](size_t len) { return ::operator new(len); } #else void* operator new(size_t len) { return (void*)kmalloc(len); } void operator delete[](void *ptr) { ::operator delete(ptr); } void* operator new[](size_t len) { return ::operator new(len); } #endif void *__gxx_personality_v0=(void*)0xDEADBEAF; ================================================ FILE: src/kernel/runtime/itoa.cc ================================================ #include /* * Convertit un nombre en chaine de caractre */ extern "C" { void itoa(char *buf, unsigned long int n, int base) { unsigned long int tmp; int i, j; tmp = n; i = 0; do { tmp = n % base; buf[i++] = (tmp < 10) ? (tmp + '0') : (tmp + 'a' - 10); } while (n /= base); buf[i--] = 0; for (j = 0; j < i; j++, i--) { tmp = buf[j]; buf[j] = buf[i]; buf[i] = tmp; } } } ================================================ FILE: src/kernel/runtime/libc.h ================================================ #ifndef LIBC_H #define LIBC_H #include extern "C" { void itoa(char *buf, unsigned long int n, int base); void * memset(char *dst,char src, int n); void * memcpy(char *dst, char *src, int n); int strlen(char *s); int strcmp(const char *dst, char *src); int strcpy(char *dst,const char *src); void strcat(void *dest,const void *src); char * strncpy(char *destString, const char *sourceString,int maxLength); int strncmp( const char* s1, const char* s2, int c ); } #endif ================================================ FILE: src/kernel/runtime/list.h ================================================ #ifndef __LIST__ #define __LIST__ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } static inline void list_add(struct list_head *neww, struct list_head *head) { neww->next = head->next; neww->prev = head; (head->next)->prev = neww; head->next = neww; } static inline void list_del(struct list_head *p) { (p->next)->prev = p->prev; (p->prev)->next = p->next; p->next = 0; p->prev = 0; } static inline int list_empty(const struct list_head *head) { return head->next == head; } #define list_entry(ptr, type, member) \ (type*) ((char*) ptr - (char*) &((type*)0)->member) #define list_first_entry(head, type, member) \ list_entry((head)->next, type, member) #define list_for_each(p, head) \ for (p = (head)->next; p != (head); p = p->next) #define list_for_each_safe(p, n, head) \ for (p = (head)->next, n = p->next; p != (head); p = n, n = n->next) #define list_for_each_entry(p, head, member) \ for (p = list_entry((head)->next, typeof(*p), member); \ &p->member != (head); \ p = list_entry(p->member.next, typeof(*p), member)) \ #endif /* __LIST__ */ ================================================ FILE: src/kernel/runtime/memory.cc ================================================ #include extern "C" { /* * La fonction memcpy permet de copier n octets de src vers dest. * Les adresses sont lineaires. */ void *memcpy(char *dst, char *src, int n) { char *p = dst; while (n--) *dst++ = *src++; return p; } /* * Met un ensemble memoire (dst>>n) la valeur src */ void *memset(char *dst,char src, int n) { char *p = dst; while (n--) *dst++ = src; return p; } } ================================================ FILE: src/kernel/runtime/string.cc ================================================ #include extern "C" { int strlen(char *s) { int i = 0; while (*s++) i++; return i; } char *strncpy(char *destString, const char *sourceString,int maxLength) { unsigned count; if ((destString == (char *) NULL) || (sourceString == (char *) NULL)) { return (destString = NULL); } if (maxLength > 255) maxLength = 255; for (count = 0; (int)count < (int)maxLength; count ++) { destString[count] = sourceString[count]; if (sourceString[count] == '\0') break; } if (count >= 255) { return (destString = NULL); } return (destString); } int strcmp(const char *dst, char *src) { int i = 0; while ((dst[i] == src[i])) { if (src[i++] == 0) return 0; } return 1; } int strcpy(char *dst,const char *src) { int i = 0; while ((dst[i] = src[i++])); return i; } void strcat(void *dest,const void *src) { memcpy((char*)((int)dest+(int)strlen((char*)dest)),(char*)src,strlen((char*)src)); } int strncmp( const char* s1, const char* s2, int c ) { int result = 0; while ( c ) { result = *s1 - *s2++; if ( ( result != 0 ) || ( *s1++ == 0 ) ) { break; } c--; } return result; } } ================================================ FILE: src/kernel/runtime/string.h ================================================ #ifndef STRING_H #define STRING_H #endif ================================================ FILE: src/kernel/runtime/types.h ================================================ #ifndef TYPES_H #define TYPES_H /* * General C-Types */ typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; typedef signed char s8; typedef signed short s16; typedef signed int s32; typedef signed long long s64; typedef unsigned char u_char; typedef unsigned int size_t; typedef int pid_t; typedef s64 ino_t; typedef s64 off_t; typedef int dev_t; typedef int mode_t; typedef int nlink_t; typedef int uid_t; typedef int gid_t; typedef int blksize_t; typedef s64 blkcnt_t; #define time_t s64 struct stat_fs { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; blksize_t st_blksize; blkcnt_t st_blocks; time_t st_atime; time_t st_mtime; time_t st_ctime; }; /* * Return code */ enum{ RETURN_OK=0, NOT_DEFINED=-1, //If not implemented ERROR_MEMORY=-2, PARAM_NULL=-3, ERROR_PARAM=-4, RETURN_FAILURE=-128 //Added by NoMaintener aka William. In case of error }; /* * Interruption handler */ typedef void (*int_handler)(void); #define NULL 0 #define true 1 #define false 0 #endif ================================================ FILE: src/sdk/Makefile ================================================ all: @echo "Building LibC" make -C ./src/libc clean: make -C ./src/libc clean ================================================ FILE: src/sdk/bootdisk/bin/.gitkeep ================================================ ================================================ FILE: src/sdk/bootdisk/boot/grub/grub.conf ================================================ default=0 timeout=30 root (hd0,0) title=Dev Operating System (with init) kernel /kernel.elf module /bin/hello boot title=Dev Operating System kernel /kernel.elf boot ================================================ FILE: src/sdk/bootdisk/boot/grub/menu.lst ================================================ default=0 timeout=30 root (cd) title=Dev Operating System (with init) kernel /kernel.elf module /bin/hello boot title=Dev Operating System kernel /kernel.elf boot ================================================ FILE: src/sdk/build.mak ================================================ CP = cp RM = rm MKDIR = mkdir TRUE = true CC = gcc CXX = g++ AS = nasm LD = ld AR = ar RANLIB = ranlib STRIP = strip INCDIR = $(SDKDIR)/include LIBDIR = $(SDKDIR)/lib DEFS:= $(DEFS) CFLAGS = -I $(INCDIR) -Wall -fno-builtin -g -O2 -w -trigraphs -fno-exceptions -fno-stack-protector -O0 -m32 -fno-rtti $(DEFS) CXXFLAGS = $(CFLAGS) ASFLAGS = $(CFLAGS) ifeq ($(CRT_FILE),) CRT_FILE = crt_c.o endif LDFLAGS = -melf_i386 -L $(INCDIR) -T ./linker.ld --entry=_start -nostdlib -L $(LIBDIR) -lc $(LIBS) MYOS_VERSION=500 all: $(TARGET) $(TARGET): $(OBJS) $(LD) -o $@ $^ $(SDKDIR)/lib/$(CRT_FILE) $(LDFLAGS) cp $(TARGET) $(SDKDIR)/bootdisk/bin/$(TARGET) install: cp $(TARGET) $(SDKDIR)/bootdisk/bin/$(TARGET) run: cd $(SDKDIR) && sh ./diskimage.sh cd $(SDKDIR) && sh ./qemu.sh %.o: %.c $(CC) $(CFLAGS) -c $< %.o: %.cpp $(CXX) $(CXXFLAGS) -c $< %.o: %.cc $(CXX) $(CXXFLAGS) -c $< .PHONY: clean clean: rm -rf *.o $(TARGET) ================================================ FILE: src/sdk/diskimage.sh ================================================ #!/bin/bash qemu-img create c.img 2M fdisk ./c.img << EOF x c 4 h 16 s 63 r n p 1 1 4 a 1 w EOF fdisk -l -u ./c.img losetup -o 32256 /dev/loop1 ./c.img mke2fs /dev/loop1 mount /dev/loop1 /mnt/ cp -R bootdisk/* /mnt/ umount /mnt/ grub --device-map=/dev/null << EOF device (hd0) ./c.img geometry (hd0) 4 16 63 root (hd0,0) setup (hd0) quit EOF losetup -d /dev/loop1 ================================================ FILE: src/sdk/include/_ansi.h ================================================ #ifndef _ANSIDECL_H_ #define _ANSIDECL_H_ /* ISO C++. */ #ifdef __cplusplus #if !(defined(_BEGIN_STD_C) && defined(_END_STD_C)) #ifdef _HAVE_STD_CXX #define _BEGIN_STD_C namespace std { extern "C" { #define _END_STD_C } } #else #define _BEGIN_STD_C extern "C" { #define _END_STD_C } #endif #if defined(__GNUC__) && \ ( (__GNUC__ >= 4) || \ ( (__GNUC__ >= 3) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 3) ) ) #define _NOTHROW __attribute__ ((nothrow)) #else #define _NOTHROW throw() #endif #endif #else #define _BEGIN_STD_C #define _END_STD_C #define _NOTHROW #endif #endif /* _ANSIDECL_H_ */ ================================================ FILE: src/sdk/include/alloca.h ================================================ #ifndef _ALLOCA_H_ #define _ALLOCA_H_ #undef alloca #define alloca(size) __builtin_alloca(size) #endif /* _ALLOCA_H_ */ ================================================ FILE: src/sdk/include/arpa/inet.h ================================================ #ifndef _ARPA_INET_H_ #define _ARPA_INET_H_ #include /* struct in_addr */ int inet_aton( const char* cp, struct in_addr* inp ); in_addr_t inet_addr( const char* cp ); in_addr_t inet_network( const char* cp ); char* inet_ntoa( struct in_addr in ); struct in_addr inet_makeaddr( int net, int host ); in_addr_t inet_lnaof( struct in_addr in ); in_addr_t inet_netof( struct in_addr in ); #endif /* _ARPA_INET_H_ */ ================================================ FILE: src/sdk/include/assert.h ================================================ #undef assert #ifdef NDEBUG #define assert(expr) ((void)0) #else #define assert(expr) \ if ( !(expr) ) { __assert_fail( #expr, __FILE__, __LINE__ ); } #endif /* NDEBUG */ #ifndef _ASSERT_H_ #define _ASSERT_H_ #include #include static inline void __assert_fail( const char* expr, const char* file, int line ) { printf( "Assertion (%s) failed at %s:%d\n", expr, file, line ); abort(); } #endif /* _ASSERT_H_ */ ================================================ FILE: src/sdk/include/ctype.h ================================================ #ifndef _CTYPE_H_ #define _CTYPE_H_ int isupper( int c ); int islower( int c ); int isalpha( int c ); int isdigit( int c ); int isxdigit( int c ); int isalnum( int c ); int isblank( int c ); int isspace( int c ); int isprint( int c ); int iscntrl( int c ); int isgraph( int c ); int ispunct( int c ); int isascii( int c ); int tolower( int c ); int toupper( int c ); typedef struct { long quot; long rem; }ldiv_t; typedef struct { int quot; int rem; }div_t; div_t div ( int numerator, int denominator ); ldiv_t ldiv ( long numerator, long denominator ); #endif // _CTYPE_H_ ================================================ FILE: src/sdk/include/dirent.h ================================================ #ifndef _DIRENT_H_ #define _DIRENT_H_ #include typedef struct DIR { int fd; struct dirent entry; } DIR; DIR* opendir( const char* name ); int closedir( DIR* dir ); struct dirent* readdir( DIR* dir ); int readdir_r( DIR* dir, struct dirent* entry, struct dirent** result ); void rewinddir( DIR* dir ); #endif /* _DIRENT_H_ */ ================================================ FILE: src/sdk/include/endian.h ================================================ #ifndef _ENDIAN_H_ #define _ENDIAN_H_ #define __LITTLE_ENDIAN 1234 #define __BIG_ENDIAN 4321 #define __BYTE_ORDER __LITTLE_ENDIAN #endif /* _ENDIAN_H_ */ ================================================ FILE: src/sdk/include/errno.h ================================================ #ifndef _ERRNO_H_ #define _ERRNO_H_ #define ENOMEM 1 #define EINVAL 2 #define EIO 3 #define ETIME 4 #define ENOSYS 5 #define ENOENT 6 #define EEXIST 7 #define EBUSY 8 #define EISDIR 9 #define ENOINO 10 #define ENOEXEC 11 #define EBADF 12 #define EHW 13 #define ERANGE 14 #define ENXIO 15 #define EDOM 16 #define ENODEV 17 #define EINTR 18 #define ENOTTY 19 #define EPERM 20 #define EROFS 21 #define ELOOP 22 #define ENOTDIR 23 #define ENOTEMPTY 24 #define EAGAIN 25 #define E2BIG 26 #define ETIMEDOUT 27 #define EOVERFLOW 28 #define ENOSPC 29 #define ECHILD 30 #define ENAMETOOLONG 31 #define ESPIPE 32 #define EACCES 33 extern int errno; #endif /* _ERRNO_H_ */ ================================================ FILE: src/sdk/include/fcntl.h ================================================ #ifndef _FCNTL_H_ #define _FCNTL_H_ #include #include #define O_RDONLY 0x01 #define O_WRONLY 0x02 #define O_RDWR 0x03 #define O_CREAT 0x04 #define O_TRUNC 0x08 #define O_APPEND 0x10 #define O_EXCL 0x20 #define O_NONBLOCK 0x40 #define F_DUPFD 0 #define F_GETFD 1 #define F_SETFD 2 #define F_GETFL 3 #define F_SETFL 4 #define FD_CLOEXEC 1 int open( const char* filename, int flags, ... ) __nonnull((1)); int creat( const char* pathname, mode_t mode ) __nonnull((1)); int fcntl( int fd, int cmd, ... ); #endif /* _FCNTL_H_ */ ================================================ FILE: src/sdk/include/float.h ================================================ /* * ISO C Standard: 5.2.4.2.2 Characteristics of floating types */ #ifndef _FLOAT_H___ #define _FLOAT_H___ /* Radix of exponent representation, b. */ #undef FLT_RADIX #define FLT_RADIX __FLT_RADIX__ /* Number of base-FLT_RADIX digits in the significand, p. */ #undef FLT_MANT_DIG #undef DBL_MANT_DIG #undef LDBL_MANT_DIG #define FLT_MANT_DIG __FLT_MANT_DIG__ #define DBL_MANT_DIG __DBL_MANT_DIG__ #define LDBL_MANT_DIG __LDBL_MANT_DIG__ /* Number of decimal digits, q, such that any floating-point number with q decimal digits can be rounded into a floating-point number with p radix b digits and back again without change to the q decimal digits, p * log10(b) if b is a power of 10 floor((p - 1) * log10(b)) otherwise */ #undef FLT_DIG #undef DBL_DIG #undef LDBL_DIG #define FLT_DIG __FLT_DIG__ #define DBL_DIG __DBL_DIG__ #define LDBL_DIG __LDBL_DIG__ /* Minimum int x such that FLT_RADIX**(x-1) is a normalized float, emin */ #undef FLT_MIN_EXP #undef DBL_MIN_EXP #undef LDBL_MIN_EXP #define FLT_MIN_EXP __FLT_MIN_EXP__ #define DBL_MIN_EXP __DBL_MIN_EXP__ #define LDBL_MIN_EXP __LDBL_MIN_EXP__ /* Minimum negative integer such that 10 raised to that power is in the range of normalized floating-point numbers, ceil(log10(b) * (emin - 1)) */ #undef FLT_MIN_10_EXP #undef DBL_MIN_10_EXP #undef LDBL_MIN_10_EXP #define FLT_MIN_10_EXP __FLT_MIN_10_EXP__ #define DBL_MIN_10_EXP __DBL_MIN_10_EXP__ #define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__ /* Maximum int x such that FLT_RADIX**(x-1) is a representable float, emax. */ #undef FLT_MAX_EXP #undef DBL_MAX_EXP #undef LDBL_MAX_EXP #define FLT_MAX_EXP __FLT_MAX_EXP__ #define DBL_MAX_EXP __DBL_MAX_EXP__ #define LDBL_MAX_EXP __LDBL_MAX_EXP__ /* Maximum integer such that 10 raised to that power is in the range of representable finite floating-point numbers, floor(log10((1 - b**-p) * b**emax)) */ #undef FLT_MAX_10_EXP #undef DBL_MAX_10_EXP #undef LDBL_MAX_10_EXP #define FLT_MAX_10_EXP __FLT_MAX_10_EXP__ #define DBL_MAX_10_EXP __DBL_MAX_10_EXP__ #define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__ /* Maximum representable finite floating-point number, (1 - b**-p) * b**emax */ #undef FLT_MAX #undef DBL_MAX #undef LDBL_MAX #define FLT_MAX __FLT_MAX__ #define DBL_MAX __DBL_MAX__ #define LDBL_MAX __LDBL_MAX__ /* The difference between 1 and the least value greater than 1 that is representable in the given floating point type, b**1-p. */ #undef FLT_EPSILON #undef DBL_EPSILON #undef LDBL_EPSILON #define FLT_EPSILON __FLT_EPSILON__ #define DBL_EPSILON __DBL_EPSILON__ #define LDBL_EPSILON __LDBL_EPSILON__ /* Minimum normalized positive floating-point number, b**(emin - 1). */ #undef FLT_MIN #undef DBL_MIN #undef LDBL_MIN #define FLT_MIN __FLT_MIN__ #define DBL_MIN __DBL_MIN__ #define LDBL_MIN __LDBL_MIN__ /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown. */ /* ??? This is supposed to change with calls to fesetround in . */ #undef FLT_ROUNDS #define FLT_ROUNDS 1 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* The floating-point expression evaluation method. -1 indeterminate 0 evaluate all operations and constants just to the range and precision of the type 1 evaluate operations and constants of type float and double to the range and precision of the double type, evaluate long double operations and constants to the range and precision of the long double type 2 evaluate all operations and constants to the range and precision of the long double type ??? This ought to change with the setting of the fp control word; the value provided by the compiler assumes the widest setting. */ #undef FLT_EVAL_METHOD #define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ /* Number of decimal digits, n, such that any floating-point number in the widest supported floating type with pmax radix b digits can be rounded to a floating-point number with n decimal digits and back again without change to the value, pmax * log10(b) if b is a power of 10 ceil(1 + pmax * log10(b)) otherwise */ #undef DECIMAL_DIG #define DECIMAL_DIG __DECIMAL_DIG__ #endif /* C99 */ #ifdef __STDC_WANT_DEC_FP__ /* Draft Technical Report 24732, extension for decimal floating-point arithmetic: Characteristic of decimal floating types . */ /* Number of base-FLT_RADIX digits in the significand, p. */ #undef DEC32_MANT_DIG #undef DEC64_MANT_DIG #undef DEC128_MANT_DIG #define DEC32_MANT_DIG __DEC32_MANT_DIG__ #define DEC64_MANT_DIG __DEC64_MANT_DIG__ #define DEC128_MANT_DIG __DEC128_MANT_DIG__ /* Minimum exponent. */ #undef DEC32_MIN_EXP #undef DEC64_MIN_EXP #undef DEC128_MIN_EXP #define DEC32_MIN_EXP __DEC32_MIN_EXP__ #define DEC64_MIN_EXP __DEC64_MIN_EXP__ #define DEC128_MIN_EXP __DEC128_MIN_EXP__ /* Maximum exponent. */ #undef DEC32_MAX_EXP #undef DEC64_MAX_EXP #undef DEC128_MAX_EXP #define DEC32_MAX_EXP __DEC32_MAX_EXP__ #define DEC64_MAX_EXP __DEC64_MAX_EXP__ #define DEC128_MAX_EXP __DEC128_MAX_EXP__ /* Maximum representable finite decimal floating-point number (there are 6, 15, and 33 9s after the decimal points respectively). */ #undef DEC32_MAX #undef DEC64_MAX #undef DEC128_MAX #define DEC32_MAX __DEC32_MAX__ #define DEC64_MAX __DEC64_MAX__ #define DEC128_MAX __DEC128_MAX__ /* The difference between 1 and the least value greater than 1 that is representable in the given floating point type. */ #undef DEC32_EPSILON #undef DEC64_EPSILON #undef DEC128_EPSILON #define DEC32_EPSILON __DEC32_EPSILON__ #define DEC64_EPSILON __DEC64_EPSILON__ #define DEC128_EPSILON __DEC128_EPSILON__ /* Minimum normalized positive floating-point number. */ #undef DEC32_MIN #undef DEC64_MIN #undef DEC128_MIN #define DEC32_MIN __DEC32_MIN__ #define DEC64_MIN __DEC64_MIN__ #define DEC128_MIN __DEC128_MIN__ /* Minimum denormalized positive floating-point number. */ #undef DEC32_DEN #undef DEC64_DEN #undef DEC128_DEN #define DEC32_DEN __DEC32_DEN__ #define DEC64_DEN __DEC64_DEN__ #define DEC128_DEN __DEC128_DEN__ /* The floating-point expression evaluation method. -1 indeterminate 0 evaluate all operations and constants just to the range and precision of the type 1 evaluate operations and constants of type _Decimal32 and _Decimal64 to the range and precision of the _Decimal64 type, evaluate _Decimal128 operations and constants to the range and precision of the _Decimal128 type; 2 evaluate all operations and constants to the range and precision of the _Decimal128 type. */ #undef DECFLT_EVAL_METHOD #define DECFLT_EVAL_METHOD __DECFLT_EVAL_METHOD__ #endif /* __STDC_WANT_DEC_FP__ */ #endif /* _FLOAT_H___ */ ================================================ FILE: src/sdk/include/getopt.h ================================================ #ifndef _GETOPT_H_ #define _GETOPT_H_ typedef struct option { const char *name; int has_arg; int* flag; int val; } option_t ; #define no_argument 0 #define required_argument 1 #define optional_argument 2 extern char *optarg; extern int optind, opterr, optopt; int getopt( int argc, char* const * argv, const char* opstring ); int getopt_long( int argc, char* const * argv, const char* shortopts, const struct option* longopts, int* longind ); int getopt_long_only( int argc, char* const * argv, const char* shortopts, const struct option* longopts, int* longind ); #endif // _GETOPT_H_ ================================================ FILE: src/sdk/include/inttypes.h ================================================ #ifndef _INTTYPES_H_ #define _INTTYPES_H_ #include intmax_t strtoimax( const char *nptr, char** endptr, int base ); uintmax_t strtoumax( const char *nptr, char** endptr, int base ); #endif /* _INTTYPES_H_ */ ================================================ FILE: src/sdk/include/limits.h ================================================ #ifndef _LIMITS_H_ #define _LIMITS_H_ #ifndef __INT_MAX__ #define __INT_MAX__ 2147483647 #endif #ifndef __LONG_MAX__ #if __WORDSIZE == 64 #define __LONG_MAX__ 9223372036854775807L #else #define __LONG_MAX__ 2147483647L #endif #endif #define CHAR_BIT 8 #define SCHAR_MIN (-128) #define SCHAR_MAX 127 #define UCHAR_MAX 255 #ifdef __CHAR_UNSIGNED__ #define CHAR_MIN 0 #define CHAR_MAX UCHAR_MAX #else #define CHAR_MIN SCHAR_MIN #define CHAR_MAX SCHAR_MAX #endif #define SHRT_MIN (-32768) #define SHRT_MAX 32767 #define USHRT_MAX 65535 #define INT_MIN (-1 - INT_MAX) #define INT_MAX (__INT_MAX__) #define UINT_MAX (INT_MAX * 2U + 1U) #define LONG_MIN (-1L - LONG_MAX) #define LONG_MAX ((__LONG_MAX__) + 0L) #define ULONG_MAX (LONG_MAX * 2UL + 1UL) #define LLONG_MAX 9223372036854775807LL #define LLONG_MIN (-LLONG_MAX - 1LL) #define ULLONG_MAX 18446744073709551615ULL #define PATH_MAX 256 #define MB_LEN_MAX 16 #endif // _LIMITS_H_ ================================================ FILE: src/sdk/include/linker.ld ================================================ OUTPUT_FORMAT(elf32-i386) OUTPUT_ARCH(i386) ENTRY (_start) SECTIONS{ . = 0x40000000; .text :{ *(.text) } .data ALIGN (0x1000) : { start_ctors = .; *(.ctor*) end_ctors = .; start_dtors = .; *(.dtor*) end_dtors = .; *(.data) } .rodata ALIGN (0x1000) : { *(.rodata) } .data ALIGN (0x1000) : { *(.data) } .bss : { sbss = .; *(COMMON) *(.bss) ebss = .; } } ================================================ FILE: src/sdk/include/locale.h ================================================ #ifndef _LOCALE_H_ #define _LOCALE_H_ enum { LC_CTYPE = 0, LC_NUMERIC = 1, LC_TIME = 2, LC_COLLATE = 3, LC_MONETARY = 4, LC_MESSAGES = 5, LC_ALL = 6, LC_PAPER = 7, LC_NAME = 8, LC_ADDRESS = 9, LC_TELEPHONE = 10, LC_MEASUREMENT = 11, LC_IDENTIFICATION = 12 }; struct lconv { char* decimal_point; char* thousands_sep; char* grouping; char* int_curr_symbol; char* currency_symbol; char* mon_decimal_point; char* mon_thousands_sep; char* mon_grouping; char* positive_sign; char* negative_sign; char int_frac_digits; char frac_digits; char p_cs_precedes; char p_sep_by_space; char n_cs_precedes; char n_sep_by_space; char p_sign_posn; char n_sign_posn; char int_p_cs_precedes; char int_p_sep_by_space; char int_n_cs_precedes; char int_n_sep_by_space; char int_p_sign_posn; char int_n_sign_posn; }; struct lconv* localeconv( void ); char* setlocale( int category, const char* locale ); #endif /* _LOCALE_H_ */ ================================================ FILE: src/sdk/include/math.h ================================================ #ifndef _MATH_H_ #define _MATH_H_ #define HUGE_VAL \ (__extension__ \ ((union { unsigned __l __attribute__((__mode__(__DI__))); double __d; }) \ { __l: 0x7ff0000000000000ULL }).__d) int finite( double x ); double sin( double x ); double cos( double x ); double log( double x ); double log10( double x ); double exp( double x ); double floor( double x ); double ceil( double x ); double frexp( double x, int* exp ); double fabs( double x ); double fmod( double x, double y ); double atan2( double y, double x ); double hypot( double x, double y ); double pow( double x, double y ); double ldexp( double x, int exp ); double scalbn( double x, int exp ); double modf( double x, double* iptr ); #endif // _MATH_H_ ================================================ FILE: src/sdk/include/netinet/in.h ================================================ #ifndef _NETINET_IN_H_ #define _NETINET_IN_H_ #include #include #define ntohs(n) \ ((((uint16_t)(n) & 0xFF) << 8) | ((uint16_t)(n) >> 8)) #define ntohl(n) \ (((uint32_t)(n) << 24) | (((uint32_t)(n) & 0xFF00) << 8) | (((uint32_t)(n) & 0x00FF0000) >> 8) | ((uint32_t)(n) >> 24)) #define htons ntohs #define htonl ntohl /* Standard well-defined IP protocols. */ enum { IPPROTO_IP = 0, /* Dummy protocol for TCP. */ #define IPPROTO_IP IPPROTO_IP IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options. */ #define IPPROTO_HOPOPTS IPPROTO_HOPOPTS IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */ #define IPPROTO_ICMP IPPROTO_ICMP IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */ #define IPPROTO_IGMP IPPROTO_IGMP IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */ #define IPPROTO_IPIP IPPROTO_IPIP IPPROTO_TCP = 6, /* Transmission Control Protocol. */ #define IPPROTO_TCP IPPROTO_TCP IPPROTO_EGP = 8, /* Exterior Gateway Protocol. */ #define IPPROTO_EGP IPPROTO_EGP IPPROTO_PUP = 12, /* PUP protocol. */ #define IPPROTO_PUP IPPROTO_PUP IPPROTO_UDP = 17, /* User Datagram Protocol. */ #define IPPROTO_UDP IPPROTO_UDP IPPROTO_IDP = 22, /* XNS IDP protocol. */ #define IPPROTO_IDP IPPROTO_IDP IPPROTO_TP = 29, /* SO Transport Protocol Class 4. */ #define IPPROTO_TP IPPROTO_TP IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol. */ #define IPPROTO_DCCP IPPROTO_DCCP IPPROTO_IPV6 = 41, /* IPv6 header. */ #define IPPROTO_IPV6 IPPROTO_IPV6 IPPROTO_ROUTING = 43, /* IPv6 routing header. */ #define IPPROTO_ROUTING IPPROTO_ROUTING IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header. */ #define IPPROTO_FRAGMENT IPPROTO_FRAGMENT IPPROTO_RSVP = 46, /* Reservation Protocol. */ #define IPPROTO_RSVP IPPROTO_RSVP IPPROTO_GRE = 47, /* General Routing Encapsulation. */ #define IPPROTO_GRE IPPROTO_GRE IPPROTO_ESP = 50, /* encapsulating security payload. */ #define IPPROTO_ESP IPPROTO_ESP IPPROTO_AH = 51, /* authentication header. */ #define IPPROTO_AH IPPROTO_AH IPPROTO_ICMPV6 = 58, /* ICMPv6. */ #define IPPROTO_ICMPV6 IPPROTO_ICMPV6 IPPROTO_NONE = 59, /* IPv6 no next header. */ #define IPPROTO_NONE IPPROTO_NONE IPPROTO_DSTOPTS = 60, /* IPv6 destination options. */ #define IPPROTO_DSTOPTS IPPROTO_DSTOPTS IPPROTO_MTP = 92, /* Multicast Transport Protocol. */ #define IPPROTO_MTP IPPROTO_MTP IPPROTO_ENCAP = 98, /* Encapsulation Header. */ #define IPPROTO_ENCAP IPPROTO_ENCAP IPPROTO_PIM = 103, /* Protocol Independent Multicast. */ #define IPPROTO_PIM IPPROTO_PIM IPPROTO_COMP = 108, /* Compression Header Protocol. */ #define IPPROTO_COMP IPPROTO_COMP IPPROTO_SCTP = 132, /* Stream Control Transmission Protocol. */ #define IPPROTO_SCTP IPPROTO_SCTP IPPROTO_UDPLITE = 136, /* UDP-Lite protocol. */ #define IPPROTO_UDPLITE IPPROTO_UDPLITE IPPROTO_RAW = 255, /* Raw IP packets. */ #define IPPROTO_RAW IPPROTO_RAW IPPROTO_MAX }; typedef uint16_t in_port_t; typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; }; struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; /* Port number. */ struct in_addr sin_addr; /* Internet address. */ /* Pad to size of `struct sockaddr'. */ unsigned char sin_zero[ sizeof( struct sockaddr ) - sizeof( sa_family_t ) - sizeof( in_port_t ) - sizeof( struct in_addr ) ]; }; #endif /* _NETINET_IN_H_ */ ================================================ FILE: src/sdk/include/os.h ================================================ #ifndef _OS_H_ #define _OS_H_ #include #include "../../kernel/core/api/kernel/syscall.h" #include "../../kernel/core/api/kernel/syscall_table.h" #endif ================================================ FILE: src/sdk/include/pwd.h ================================================ #ifndef _PWD_H_ #define _PWD_H_ #include struct passwd { char* pw_name; char* pw_passwd; uid_t pw_uid; gid_t pw_gid; char* pw_gecos; char* pw_dir; char* pw_shell; }; struct passwd* getpwnam( const char* name ); struct passwd* getpwent( void ); struct passwd* getpwuid( uid_t uid ); void setpwent( void ); void endpwent( void ); #endif /* _PWD_H_ */ ================================================ FILE: src/sdk/include/setjmp.h ================================================ #ifndef _SETJMP_H_ #define _SETJMP_H_ typedef unsigned long jmp_buf[ 6 ]; int setjmp( jmp_buf env ); void longjmp( jmp_buf env, int val ); #endif // _SETJMP_H_ ================================================ FILE: src/sdk/include/signal.h ================================================ #ifndef _SIGNAL_H_ #define _SIGNAL_H_ #include #include #define SIGHUP 1 /* Hangup (POSIX). */ #define SIGINT 2 /* Interrupt (ANSI). */ #define SIGQUIT 3 /* Quit (POSIX). */ #define SIGILL 4 /* Illegal instruction (ANSI). */ #define SIGTRAP 5 /* Trace trap (POSIX). */ #define SIGABRT 6 /* Abort (ANSI). */ #define SIGIOT 6 /* IOT trap (4.2 BSD). */ #define SIGBUS 7 /* BUS error (4.2 BSD). */ #define SIGFPE 8 /* Floating-point exception (ANSI). */ #define SIGKILL 9 /* Kill, unblockable (POSIX). */ #define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ #define SIGSEGV 11 /* Segmentation violation (ANSI). */ #define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ #define SIGPIPE 13 /* Broken pipe (POSIX). */ #define SIGALRM 14 /* Alarm clock (POSIX). */ #define SIGTERM 15 /* Termination (ANSI). */ #define SIGSTKFLT 16 /* Stack fault. */ #define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ #define SIGCHLD 17 /* Child status has changed (POSIX). */ #define SIGCONT 18 /* Continue (POSIX). */ #define SIGSTOP 19 /* Stop, unblockable (POSIX). */ #define SIGTSTP 20 /* Keyboard stop (POSIX). */ #define SIGTTIN 21 /* Background read from tty (POSIX). */ #define SIGTTOU 22 /* Background write to tty (POSIX). */ #define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ #define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ #define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ #define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ #define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ #define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ #define SIGPOLL SIGIO /* Pollable event occurred (System V). */ #define SIGIO 29 /* I/O now possible (4.2 BSD). */ #define SIGPWR 30 /* Power failure restart (System V). */ #define SIGSYS 31 /* Bad system call. */ #define _NSIG 65 /* Biggest signal number + 1 (including real-time signals). */ #define SIG_ERR ((sighandler_t)-1) /* Error return. */ #define SIG_DFL ((sighandler_t)0) /* Default action. */ #define SIG_IGN ((sighandler_t)1) /* Ignore signal. */ #define SIG_BLOCK 0 /* Block signals. */ #define SIG_UNBLOCK 1 /* Unblock signals. */ #define SIG_SETMASK 2 /* Set the set of blocked signals. */ #define SA_NOCLDSTOP 1 /* Don't send SIGCHLD when children stop. */ #define SA_NOCLDWAIT 2 /* Don't create zombie on child death. */ #define SA_SIGINFO 4 /* Invoke signal-catching function with three arguments instead of one. */ #define SA_ONSTACK 0x08000000 /* Use signal stack by using `sa_restorer'. */ #define SA_STACK SA_ONSTACK #define SA_RESTART 0x10000000 /* Restart syscall on signal return. */ #define SA_NODEFER 0x40000000 /* Don't automatically block the signal when its handler is being executed. */ #define SA_NOMASK SA_NODEFER #define SA_RESETHAND 0x80000000 /* Reset to SIG_DFL on entry to handler. */ #define SA_ONESHOT SA_RESETHAND typedef int sig_atomic_t; typedef uint64_t sigset_t; typedef int sigval_t; typedef void ( *__sighandler_t )( int ); typedef __sighandler_t sighandler_t; typedef struct siginfo { int si_signo; /* Signal number */ int si_errno; /* An errno value */ int si_code; /* Signal code */ int si_trapno; /* Trap number that caused hardware-generated signal (unused on most architectures) */ pid_t si_pid; /* Sending process ID */ uid_t si_uid; /* Real user ID of sending process */ int si_status; /* Exit value or signal */ clock_t si_utime; /* User time consumed */ clock_t si_stime; /* System time consumed */ sigval_t si_value; /* Signal value */ int si_int; /* POSIX.1b signal */ void *si_ptr; /* POSIX.1b signal */ int si_overrun; /* Timer overrun count; POSIX.1b timers */ int si_timerid; /* Timer ID; POSIX.1b timers */ void *si_addr; /* Memory location which caused fault */ int si_band; /* Band event */ int si_fd; /* File descriptor */ } siginfo_t; struct sigaction { void ( *sa_handler )( int ); void ( *sa_sigaction )( int, siginfo_t*, void* ); sigset_t sa_mask; int sa_flags; void ( *sa_restorer )( void ); }; int sigemptyset( sigset_t* set ); int sigfillset( sigset_t* set ); int sigaddset( sigset_t* set, int signum ); int sigdelset( sigset_t* set, int signum ); int sigismember( const sigset_t* set, int signum ); sighandler_t signal( int signum, sighandler_t handler ); int sigaction( int signum, const struct sigaction* act, struct sigaction* oldact ); int sigprocmask( int how, const sigset_t* set, sigset_t* oldset ); int kill( pid_t pid, int signal ); int killpg( int pgrp, int signal ); int raise( int signal ); #endif /* _SIGNAL_H_ */ ================================================ FILE: src/sdk/include/stdarg.h ================================================ #ifndef _STDARG_H_ #define _STDARG_H_ typedef __builtin_va_list va_list; #define va_start(a,b) __builtin_va_start(a,b) #define va_end(a) __builtin_va_end(a) #define va_arg(a,b) __builtin_va_arg(a,b) #define __va_copy(d,s) __builtin_va_copy((d),(s)) #endif // _STDARG_H_ ================================================ FILE: src/sdk/include/stddef.h ================================================ #ifndef _STDDEF_H #define _STDDEF_H #ifndef NULL #define NULL 0 #endif #ifndef _HAVE_PTRDIFF_T #define _HAVE_PTRDIFF_T typedef signed long int ptrdiff_t; #endif #ifndef _HAVE_SIZE_T #define _HAVE_SIZE_T //typedef unsigned int size_t; typedef long unsigned int size_t; #endif #if ( (! defined _HAVE_WCHAR_T) && (! defined __cplusplus ) ) #define _HAVE_WCHAR_T typedef int wchar_t; #endif #define offsetof(struct_type, member) \ (size_t) &(((struct_type *)0)->member) /*#define offsetof(type, memberdesig) \ ((const unsigned int)((ptrdiff_t)&(type.memberdesig) - (ptrdiff_t)&type)) */ #endif ================================================ FILE: src/sdk/include/stdint.h ================================================ #ifndef _STDINT_H_ #define _STDINT_H_ typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef signed long long int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef signed long intptr_t; typedef unsigned long uintptr_t; #if __WORDSIZE == 64 typedef signed long int intmax_t; typedef unsigned long int uintmax_t; #else typedef signed long long int intmax_t; typedef unsigned long long int uintmax_t; #endif /* __WORDSIZE == 64 */ /* The ISO C99 standard specifies that in C++ implementations these macros should only be defined if explicitly requested. */ #if !defined __cplusplus || defined __STDC_LIMIT_MACROS #if __WORDSIZE == 64 #define __INT64_C(c) c ## L #define __UINT64_C(c) c ## UL #else #define __INT64_C(c) c ## LL #define __UINT64_C(c) c ## ULL #endif /* Limits of integral types. */ /* Minimum of signed integral types. */ # define INT8_MIN (-128) # define INT16_MIN (-32767-1) # define INT32_MIN (-2147483647-1) # define INT64_MIN (-__INT64_C(9223372036854775807)-1) /* Maximum of signed integral types. */ # define INT8_MAX (127) # define INT16_MAX (32767) # define INT32_MAX (2147483647) # define INT64_MAX (__INT64_C(9223372036854775807)) /* Maximum of unsigned integral types. */ # define UINT8_MAX (255) # define UINT16_MAX (65535) # define UINT32_MAX (4294967295U) # define UINT64_MAX (__UINT64_C(18446744073709551615)) #endif #endif /* _STDINT_H_ */ ================================================ FILE: src/sdk/include/stdio.h ================================================ #ifndef _STDIO_H_ #define _STDIO_H_ #define __need_size_t #define __need_NULL #include #include #include #define _IONBF 0 #define _IOLBF 1 #define _IOFBF 2 #define __FILE_CAN_READ 0x01 #define __FILE_CAN_WRITE 0x02 #define __FILE_ERROR 0x04 #define __FILE_EOF 0x08 #define __FILE_BUFLINEWISE 0x10 #define __FILE_DONTFREEBUF 0x20 #define __FILE_NOBUF 0x40 #define __FILE_BUFINPUT 0x80 #define EOF -1 #define _IO_BUFSIZE 2048 #ifndef BUFSIZ #define BUFSIZ _IO_BUFSIZE #endif /* BUFSIZ */ #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #define P_tmpdir "/temp" typedef struct FILE { int fd; int flags; char* buffer; unsigned int buffer_pos; unsigned int buffer_size; unsigned int buffer_data_size; int has_ungotten; unsigned char unget_buffer; } FILE; extern FILE* stdin; extern FILE* stdout; extern FILE* stderr; FILE* fopen( const char* path, const char* mode ); FILE* fdopen( int fd, const char* mode ); FILE* freopen( const char* path, const char* mode, FILE* stream ); int fclose( FILE* stream ); int feof( FILE* stream ); int ferror( FILE* stream ); int fileno( FILE* stream ); int fflush( FILE* stream ); int fseek( FILE* stream, long offset, int whence ); int fseeko( FILE* stream, off_t offset, int whence ); long ftell( FILE* stream ); off_t ftello( FILE* stream ); size_t fread( void* ptr, size_t size, size_t nmemb, FILE* stream ); size_t fwrite( const void* ptr, size_t size, size_t nmemb, FILE* stream ); int fpurge( FILE* stream ); void rewind( FILE* stream ); int ungetc( int c, FILE* stream ); void clearerr( FILE* stream ); int printf( const char* format, ... ) __attribute__(( __format__( __printf__, 1, 2 ) )); int fprintf( FILE* stream, const char* format, ... ) __attribute__(( __format__( __printf__, 2, 3 ) )); int sprintf( char* str, const char* format, ... ) __attribute__(( __format__( __printf__, 2, 3 ) )); int snprintf( char* str, size_t size, const char* format, ... ) __attribute__(( __format__( __printf__, 3, 4 ) )); int vprintf( const char* format, va_list ap ) __attribute__(( __format__( __printf__, 1, 0 ) )); int vfprintf( FILE* stream, const char* format, va_list ap ) __attribute__(( __format__( __printf__, 2, 0 ) )); int vsprintf( char *str, const char *format, va_list ap ) __attribute__(( __format__( __printf__, 2, 0 ) )); int vsnprintf( char* str, size_t size, const char* format, va_list ap ) __attribute__(( __format__( __printf__, 3, 0 ) )); int asprintf(char **strp, const char *fmt, ...) __attribute__(( __format__( __printf__, 2, 3 ) )); int scanf( const char* format, ... ); int fscanf( FILE* stream, const char* format, ... ); int sscanf( const char* str, const char* format, ... ); int vscanf( const char* format, va_list ap ); int vsscanf( const char* str, const char* format, va_list ap ); int vfscanf( FILE* stream, const char* format, va_list ap ); int fgetc( FILE* stream ); int getc( FILE* stream ); char* fgets( char* s, int size, FILE* stream ); #define getchar(c) getc(stdin) int fputc( int c, FILE* stream ); int putc( int c, FILE* stream ); int fputs( const char* s, FILE* stream ); int puts( const char* s ); int putchar( int c ); #define setbuf(stream,buf) setvbuf(stream,buf,(buf!=NULL)?_IOFBF:_IONBF,BUFSIZ) #define setbuffer(stream,buf,size) setvbuf(stream,buf,(buf!=NULL)?_IOFBF:_IONBF,size) int setvbuf( FILE* stream, char* buf, int flags, size_t size ); int rename( const char* oldpath, const char* newpath ); int remove( const char* path ); void perror( const char* s ); #endif /* _STDIO_H_ */ ================================================ FILE: src/sdk/include/stdlib.h ================================================ #ifndef _STDLIB_H_ #define _STDLIB_H_ #define __need_size_t #define __need_NULL #include #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 #define ATEXIT_MAX 32 #define WEXITSTATUS(status) (((status) & 0xFF00) >> 8) #define WTERMSIG(status) ((status) & 0x7F) #define WIFEXITED(status) (WTERMSIG(status) == 0) int abs( int j ); long labs( long j ); long long llabs( long long j ); void exit( int status ); int atexit( void ( *function )( void ) ); char* getenv( const char* name ); void* calloc( size_t nmemb, size_t size ) __attribute__(( malloc )); void* malloc( size_t size ) __attribute__(( malloc )); void free( void* ptr ); void* realloc( void* ptr, size_t size ); void abort( void ) __attribute__(( __noreturn__ )); int atoi( const char* s ); long atol( const char* s ); long long atoll( const char* s ); double atof( const char* s ); long int strtol( const char* nptr, char** endptr, int base ); unsigned long int strtoul( const char* nptr, char** endptr, int base ); double strtod( const char* s, char** endptr ); long int strtol( const char* nptr, char** endptr, int base ); long long int strtoll( const char* nptr, char** endptr, int base ); unsigned long long int strtoull( const char* nptr, char** endptr, int base ); void qsort( void* base, size_t nmemb, size_t size, int ( *compar )( const void*, const void* ) ); void* bsearch( const void* key, const void* base, size_t nmemb, size_t size, int ( *compare )( const void*, const void* ) ); long int random( void ); void srandom( unsigned int seed ); int rand( void ); void srand( unsigned int seed ); char* mktemp( char* templat ); int mkstemp( char* templat ); int system(char *ccc); #endif /* _STDLIB_H_ */ ================================================ FILE: src/sdk/include/string.h ================================================ #ifndef _STRING_H_ #define _STRING_H_ #define __need_size_t #define __need_NULL #include void* memset( void* s, int c, size_t n ); void* memcpy( void* d, const void* s, size_t n ); int memcmp( const void* p1, const void* p2, size_t c ); void* memmove( void* dest, const void* src, size_t n ); void* memchr( const void* s, int c, size_t n ); size_t strlen( const char* s ); size_t strnlen( const char* s, size_t count ); char* strchr( const char* s, int c ); char* strrchr( const char* s, int c ); char* strstr( const char* s1, const char* s2 ); int strcmp( const char* s1, const char* s2 ); int strncmp( const char* s1, const char* s2, size_t c ); int strcasecmp( const char* s1, const char* s2 ); int strncasecmp( const char* s1, const char* s2, size_t c ); char* strcpy( char* d, const char* s ); char* strncpy( char* d, const char* s, size_t c ); char* strcat( char* d, const char* s ); char* strncat( char* d, const char* s, size_t c ); char* strpbrk( const char* s, const char* accept ); size_t strspn( const char* s, const char* accept ); size_t strcspn( const char* s, const char* reject ); char* strtok_r( char* s, const char* delim, char** ptrptr ); char* strtok( char* s, const char* delim ); char* strdup( const char* s ); char* strndup( const char* s, size_t n); char* strerror( int errnum ); char* strsignal( int signum ); #endif /* _STRING_H_ */ ================================================ FILE: src/sdk/include/strings.h ================================================ #ifndef _STRINGS_H_ #define _STRINGS_H_ #endif /* _STRINGS_H_ */ ================================================ FILE: src/sdk/include/sys/cdefs.h ================================================ #ifndef _SYS_CDEFS_H_ #define _SYS_CDEFS_H_ #define __nonnull(params) __attribute__((__nonnull__ params)) #endif // _SYS_CDEFS_H_ ================================================ FILE: src/sdk/include/sys/ioctl.h ================================================ #ifndef _SYS_IOCTL_H_ #define _SYS_IOCTL_H_ #include #include "../../kernel/core/api/dev/ioctl.h" int ioctl( int fd, int request, ... ); #endif /* _SYS_IOCTL_H_ */ ================================================ FILE: src/sdk/include/sys/mman.h ================================================ #ifndef _SYS_MMAN_H_ #define _SYS_MMAN_H_ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #include #include #define PROT_NONE 0 #define PROT_READ 1 #define PROT_WRITE 2 #define PROT_EXEC 4 #define MAP_FILE 0 #define MAP_SHARED 1 #define MAP_PRIVATE 2 #define MAP_TYPE 0xF #define MAP_FIXED 0x10 #define MAP_ANONYMOUS 0x20 #define MAP_ANON MAP_ANONYMOUS /* Non-standard flag */ #define MAP_NORESERVE 0x4000 /* Don't reserve swap space for this mapping. Page protection must be set explicitely to access page. Only supported for anonymous private mappings. */ #define MAP_AUTOGROW 0x8000 /* Grow underlying object to mapping size. File must be opened for writing. */ #define MAP_FAILED ((void *)-1) /* * Flags for msync. */ #define MS_ASYNC 1 #define MS_SYNC 2 #define MS_INVALIDATE 4 /* * Flags for posix_madvise. */ #define POSIX_MADV_NORMAL 0 #define POSIX_MADV_SEQUENTIAL 1 #define POSIX_MADV_RANDOM 2 #define POSIX_MADV_WILLNEED 3 #define POSIX_MADV_DONTNEED 4 extern void *mmap (void *__addr, size_t __len, int __prot, int __flags, int __fd, off_t __off); extern int munmap (void *__addr, size_t __len); extern int mprotect (void *__addr, size_t __len, int __prot); extern int msync (void *__addr, size_t __len, int __flags); extern int mlock (const void *__addr, size_t __len); extern int munlock (const void *__addr, size_t __len); extern int posix_madvise (void *__addr, size_t __len, int __advice); extern int shm_open (const char *__name, int __oflag, mode_t __mode); extern int shm_unlink (const char *__name); #ifdef __cplusplus }; #endif /* __cplusplus */ #endif /* _SYS_MMAN_H_ */ ================================================ FILE: src/sdk/include/sys/mount.h ================================================ #ifndef _SYS_MOUNT_H_ #define _SYS_MOUNT_H_ #define MOUNT_NONE 0 #define MOUNT_RO 1 #define MOUNT_NOATIME 2 int mount( const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data ); int umount( const char* dir ); #endif /* _SYS_MOUNT_H_ */ ================================================ FILE: src/sdk/include/sys/param.h ================================================ #ifndef _SYS_PARAM_H_ #define _SYS_PARAM_H_ #include #undef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #undef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #define MAXPATHLEN PATH_MAX #endif // _SYS_PARAM_H_ ================================================ FILE: src/sdk/include/sys/resource.h ================================================ #ifndef _SYS_RESOURCE_H_ #define _SYS_RESOURCE_H_ #include struct rusage { struct timeval ru_utime; /* user time used */ struct timeval ru_stime; /* system time used */ long ru_maxrss; /* maximum resident set size */ long ru_ixrss; /* integral shared memory size */ long ru_idrss; /* integral unshared data size */ long ru_isrss; /* integral unshared stack size */ long ru_minflt; /* page reclaims */ long ru_majflt; /* page faults */ long ru_nswap; /* swaps */ long ru_inblock; /* block input operations */ long ru_oublock; /* block output operations */ long ru_msgsnd; /* messages sent */ long ru_msgrcv; /* messages received */ long ru_nsignals; /* signals received */ long ru_nvcsw; /* voluntary context switches */ long ru_nivcsw; /* involuntary context switches */ }; #endif /* _SYS_RESOURCE_H_ */ ================================================ FILE: src/sdk/include/sys/select.h ================================================ #ifndef _SYS_SELECT_H_ #define _SYS_SELECT_H_ #include #include #define FD_ZERO(set) \ memset( (set)->fds, 0, 1024 / 32 ); #define FD_CLR(fd,set) \ (set)->fds[fd/32] &= ~(1<<(fd%32)); #define FD_SET(fd,set) \ (set)->fds[fd/32] |= (1<<(fd%32)); #define FD_ISSET(fd,set) \ ((set)->fds[fd/32] & (1<<(fd%32))) typedef struct fd_set { uint32_t fds[ 1024 / 32 ]; } fd_set; int select( int fds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout ); #endif // _SYS_SELECT_H_ ================================================ FILE: src/sdk/include/sys/socket.h ================================================ #ifndef _SYS_SOCKET_H_ #define _SYS_SOCKET_H_ /* Protocol families. */ #define PF_UNSPEC 0 /* Unspecified. */ #define PF_LOCAL 1 /* Local to host (pipes and file-domain). */ #define PF_UNIX PF_LOCAL /* POSIX name for PF_LOCAL. */ #define PF_FILE PF_LOCAL /* Another non-standard name for PF_LOCAL. */ #define PF_INET 2 /* IP protocol family. */ #define PF_AX25 3 /* Amateur Radio AX.25. */ #define PF_IPX 4 /* Novell Internet Protocol. */ #define PF_APPLETALK 5 /* Appletalk DDP. */ #define PF_NETROM 6 /* Amateur radio NetROM. */ #define PF_BRIDGE 7 /* Multiprotocol bridge. */ #define PF_ATMPVC 8 /* ATM PVCs. */ #define PF_X25 9 /* Reserved for X.25 project. */ #define PF_INET6 10 /* IP version 6. */ #define PF_ROSE 11 /* Amateur Radio X.25 PLP. */ #define PF_DECnet 12 /* Reserved for DECnet project. */ #define PF_NETBEUI 13 /* Reserved for 802.2LLC project. */ #define PF_SECURITY 14 /* Security callback pseudo AF. */ #define PF_KEY 15 /* PF_KEY key management API. */ #define PF_NETLINK 16 #define PF_ROUTE PF_NETLINK /* Alias to emulate 4.4BSD. */ #define PF_PACKET 17 /* Packet family. */ #define PF_ASH 18 /* Ash. */ #define PF_ECONET 19 /* Acorn Econet. */ #define PF_ATMSVC 20 /* ATM SVCs. */ #define PF_SNA 22 /* Linux SNA Project */ #define PF_IRDA 23 /* IRDA sockets. */ #define PF_PPPOX 24 /* PPPoX sockets. */ #define PF_WANPIPE 25 /* Wanpipe API sockets. */ #define PF_BLUETOOTH 31 /* Bluetooth sockets. */ #define PF_IUCV 32 /* IUCV sockets. */ #define PF_RXRPC 33 /* RxRPC sockets. */ #define PF_ISDN 34 /* mISDN sockets. */ #define PF_MAX 35 /* For now.. */ /* Address families. */ #define AF_UNSPEC PF_UNSPEC #define AF_LOCAL PF_LOCAL #define AF_UNIX PF_UNIX #define AF_FILE PF_FILE #define AF_INET PF_INET #define AF_AX25 PF_AX25 #define AF_IPX PF_IPX #define AF_APPLETALK PF_APPLETALK #define AF_NETROM PF_NETROM #define AF_BRIDGE PF_BRIDGE #define AF_ATMPVC PF_ATMPVC #define AF_X25 PF_X25 #define AF_INET6 PF_INET6 #define AF_ROSE PF_ROSE #define AF_DECnet PF_DECnet #define AF_NETBEUI PF_NETBEUI #define AF_SECURITY PF_SECURITY #define AF_KEY PF_KEY #define AF_NETLINK PF_NETLINK #define AF_ROUTE PF_ROUTE #define AF_PACKET PF_PACKET #define AF_ASH PF_ASH #define AF_ECONET PF_ECONET #define AF_ATMSVC PF_ATMSVC #define AF_SNA PF_SNA #define AF_IRDA PF_IRDA #define AF_PPPOX PF_PPPOX #define AF_WANPIPE PF_WANPIPE #define AF_BLUETOOTH PF_BLUETOOTH #define AF_IUCV PF_IUCV #define AF_RXRPC PF_RXRPC #define AF_ISDN PF_ISDN #define AF_MAX PF_MAX /* Types of sockets. */ enum socket_type { SOCK_STREAM = 1, /* Sequenced, reliable, connection-based byte streams. */ #define SOCK_STREAM SOCK_STREAM SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams of fixed maximum length. */ #define SOCK_DGRAM SOCK_DGRAM SOCK_RAW = 3, /* Raw protocol interface. */ #define SOCK_RAW SOCK_RAW }; typedef unsigned short int sa_family_t; typedef unsigned int socklen_t; struct sockaddr { sa_family_t sa_family; char sa_data[ 14 ]; }; int socket( int domain, int type, int protocol ); int connect( int fd, const struct sockaddr* address, socklen_t addrlen ); /* Not implemented functions int socketpair( int d, int type, int protocol, int sv[2] ); int bind( int sockfd, const struct sockaddr *addr, socklen_t addrlen ); int getsockname( int s, struct sockaddr *name, socklen_t *namelen ); int getpeername( int s, struct sockaddr *name, socklen_t *namelen ); ssize_t send( int s, const void *buf, size_t len, int flags ); ssize_t sendto( int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen ); ssize_t sendmsg( int s, const struct msghdr *msg, int flags ); ssize_t recv( int s, void *buf, size_t len, int flags ); ssize_t recvfrom( int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen ); ssize_t recvmsg( int s, struct msghdr *msg, int flags ); int getsockopt( int s, int level, int optname, void *optval, socklen_t *optlen ); int setsockopt( int s, int level, int optname, const void *optval, socklen_t optlen ); int listen( int sockfd, int backlog ); int accept( int sockfd, struct sockaddr *addr, socklen_t *addrlen ); int shutdown( int s, int how ); */ #endif /* _SYS_SOCKET_H_ */ ================================================ FILE: src/sdk/include/sys/stat.h ================================================ #ifndef _SYS_STAT_H_ #define _SYS_STAT_H_ #include #include #define S_IFMT 00170000 #define S_IFSOCK 0140000 #define S_IFLNK 0120000 #define S_IFREG 0100000 #define S_IFBLK 0060000 #define S_IFDIR 0040000 #define S_IFCHR 0020000 #define S_IFIFO 0010000 #define S_ISUID 0004000 #define S_ISGID 0002000 #define S_ISVTX 0001000 #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) #define S_IRWXU 00700 #define S_IRUSR 00400 #define S_IWUSR 00200 #define S_IXUSR 00100 #define S_IRWXG 00070 #define S_IRGRP 00040 #define S_IWGRP 00020 #define S_IXGRP 00010 #define S_IRWXO 00007 #define S_IROTH 00004 #define S_IWOTH 00002 #define S_IXOTH 00001 struct stat { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; blksize_t st_blksize; blkcnt_t st_blocks; time_t st_atime; time_t st_mtime; time_t st_ctime; }; int stat( const char* path, struct stat* stat ); int fstat( int fd, struct stat* stat ); int lstat( const char* path, struct stat* stat ); int mkdir( const char* pathname, mode_t mode ); mode_t umask( mode_t mask ); int chmod( const char* path, mode_t mode ); #endif // _SYS_STAT_H_ ================================================ FILE: src/sdk/include/sys/time.h ================================================ #ifndef _SYS_TIME_H_ #define _SYS_TIME_H_ #include int gettimeofday( struct timeval* tv, struct timezone* tz ); #endif // _SYS_TIME_H_ ================================================ FILE: src/sdk/include/sys/types.h ================================================ #ifndef _SYS_TYPES_H_ #define _SYS_TYPES_H_ #include #define __need_size_t #include #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void*)0) #endif /* __cplusplus */ #endif /* NULL */ #define INFINITE_TIMEOUT 18446744073709551615ULL typedef unsigned char u_char; typedef int ssize_t; typedef int pid_t; typedef int64_t ino_t; typedef int64_t off_t; typedef int dev_t; typedef int mode_t; typedef int nlink_t; typedef int uid_t; typedef int gid_t; typedef int blksize_t; typedef int64_t blkcnt_t; #endif /* _SYS_TYPES_H_ */ ================================================ FILE: src/sdk/include/sys/wait.h ================================================ #ifndef _SYS_WAIT_H_ #define _SYS_WAIT_H_ #include #include #define WNOHANG 1 #define WUNTRACED 2 pid_t wait( int* status ); pid_t waitpid( pid_t pid, int* status, int options ); pid_t wait3( int* status, int options, struct rusage* rusage ); pid_t wait4( pid_t pid, int* status, int options, struct rusage* rusage ); #endif /* _SYS_WAIT_H_ */ ================================================ FILE: src/sdk/include/termios.h ================================================ #ifndef _TERMIOS_H_ #define _TERMIOS_H_ /* * Number of control characters. */ #define NCCS 19 /* * Control characters. */ #define VINTR 0 #define VQUIT 1 #define VERASE 2 #define VKILL 3 #define VEOF 4 #define VTIME 5 #define VMIN 6 #define VSWTC 7 #define VSTART 8 #define VSTOP 9 #define VSUSP 10 #define VEOL 11 #define VREPRINT 12 #define VDISCARD 13 #define VWERASE 14 #define VLNEXT 15 #define VEOL2 16 #define IGNBRK 0000001 #define BRKINT 0000002 #define IGNPAR 0000004 #define PARMRK 0000010 #define INPCK 0000020 #define ISTRIP 0000040 #define INLCR 0000100 #define IGNCR 0000200 #define ICRNL 0000400 #define IUCLC 0001000 #define IXON 0002000 #define IXANY 0004000 #define IXOFF 0010000 #define IMAXBEL 0020000 #define B0 0000000 #define B50 0000001 #define B75 0000002 #define B110 0000003 #define B134 0000004 #define B150 0000005 #define B200 0000006 #define B300 0000007 #define B600 0000010 #define B1200 0000011 #define B1800 0000012 #define B2400 0000013 #define B4800 0000014 #define B9600 0000015 #define B19200 0000016 #define B38400 0000017 #define CSIZE 0000060 #define CS5 0000000 #define CS6 0000020 #define CS7 0000040 #define CS8 0000060 #define CSTOPB 0000100 #define CREAD 0000200 #define PARENB 0000400 #define PARODD 0001000 #define HUPCL 0002000 #define CLOCAL 0004000 #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 #define B460800 0010004 #define B500000 0010005 #define B576000 0010006 #define B921600 0010007 #define B1000000 0010010 #define B1152000 0010011 #define B1500000 0010012 #define B2000000 0010013 #define B2500000 0010014 #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 #define ISIG 0000001 #define ICANON 0000002 #define XCASE 0000004 #define ECHO 0000010 #define ECHOE 0000020 #define ECHOK 0000040 #define ECHONL 0000100 #define NOFLSH 0000200 #define TOSTOP 0000400 #define ECHOCTL 0001000 #define ECHOPRT 0002000 #define ECHOKE 0004000 #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 #define OPOST 0000001 #define OLCUC 0000002 #define ONLCR 0000004 #define OCRNL 0000010 #define ONOCR 0000020 #define ONLRET 0000040 #define OFILL 0000100 #define OFDEL 0000200 /* tcflow() and TCXONC use these */ #define TCOOFF 0 #define TCOON 1 #define TCIOFF 2 #define TCION 3 /* tcflush() and TCFLSH use these */ #define TCIFLUSH 0 #define TCOFLUSH 1 #define TCIOFLUSH 2 /* tcsetattr uses these */ #define TCSANOW 0 #define TCSADRAIN 1 #define TCSAFLUSH 2 /* 0x54 is just a magic number to make these relatively unique ('T') */ #define TCGETS 0x5401 #define TCSETS 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ #define TCSETSW 0x5403 #define TCSETSF 0x5404 #define TCGETA 0x5405 #define TCSETA 0x5406 #define TCSETAW 0x5407 #define TCSETAF 0x5408 #define TCSBRK 0x5409 #define TCXONC 0x540A #define TCFLSH 0x540B #define TIOCEXCL 0x540C #define TIOCNXCL 0x540D #define TIOCSCTTY 0x540E #define TIOCGPGRP 0x540F #define TIOCSPGRP 0x5410 #define TIOCOUTQ 0x5411 #define TIOCSTI 0x5412 #define TIOCGWINSZ 0x5413 #define TIOCSWINSZ 0x5414 #define TIOCMGET 0x5415 #define TIOCMBIS 0x5416 #define TIOCMBIC 0x5417 #define TIOCMSET 0x5418 #define TIOCGSOFTCAR 0x5419 #define TIOCSSOFTCAR 0x541A #define FIONREAD 0x541B #define TIOCINQ FIONREAD #define TIOCLINUX 0x541C #define TIOCCONS 0x541D #define TIOCGSERIAL 0x541E #define TIOCSSERIAL 0x541F #define TIOCPKT 0x5420 #define FIONBIO 0x5421 #define TIOCNOTTY 0x5422 #define TIOCSETD 0x5423 #define TIOCGETD 0x5424 #define cfgetispeed(tio) ((tio)->c_ispeed) #define cfgetospeed(tio) ((tio)->c_ospeed) #define cfsetispeed(tio, spd) ((tio)->c_ispeed = (spd)) #define cfsetospeed(tio, spd) ((tio)->c_ospeed = (spd)) typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned int tcflag_t; struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t c_line; cc_t c_cc[ NCCS ]; speed_t c_ispeed; speed_t c_ospeed; }; struct winsize { unsigned short ws_row; unsigned short ws_col; }; int tcflow( int fd, int action ); int tcflush( int fd, int queue_selector ); int tcgetattr( int fd, struct termios* tio ); int tcsetattr( int fd, int optional_actions, const struct termios* tio ); #endif // _TERMIOS_H_ ================================================ FILE: src/sdk/include/time.h ================================================ #ifndef _TIME_H_ #define _TIME_H_ #include #define time_t uint64_t #define suseconds_t int typedef unsigned int clock_t; typedef struct timeval { time_t tv_sec; /* Seconds */ suseconds_t tv_usec; /* Microseconds */ } timeval_t; typedef struct timezone { int tz_minuteswest; int tz_dsttime; } timezone_t; struct timespec { time_t tv_sec; /* Seconds */ long tv_nsec; /* Nanoseconds */ }; typedef struct tm { int tm_sec; /* Seconds. [0-60] (1 leap second) */ int tm_min; /* Minutes. [0-59] */ int tm_hour; /* Hours. [0-23] */ int tm_mday; /* Day. [1-31] */ int tm_mon; /* Month. [0-11] */ int tm_year; /* Year [1970; ...] */ int tm_wday; /* Day of week. [0-6], 0=Sunday */ int tm_yday; /* Days in year. [0-365] */ int tm_isdst; /* Daylight saving [-1/0/1] */ } tm_t; void tzset( void ); time_t time(time_t* tloc); int stime(time_t* tptr); size_t strftime(char *s, size_t max, const char *format, const struct tm *tm); /* Converts a broken-down time to UNIX timestamp */ time_t mktime(tm_t* tloc); char* asctime(const tm_t* tm); char* asctime_r(const tm_t* tm, char* buf); tm_t* gmtime(const time_t* timep); tm_t* gmtime_r(const time_t* timep, tm_t* result); tm_t* localtime(const time_t* timep); tm_t* localtime_r(const time_t* timep, tm_t* result); char* ctime( const time_t* timep ); char* ctime_r( const time_t* timep, char* buf ); int nanosleep( const struct timespec* req, struct timespec* rem ); #endif // _TIME_H_ ================================================ FILE: src/sdk/include/unistd.h ================================================ #ifndef _UNISTD_H_ #define _UNISTD_H_ #include #include #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 #define F_OK 0x00 #define R_OK 0x01 #define W_OK 0x02 #define X_OK 0x04 #define NAME_MAX 255 #define _D_EXACT_NAMLEN(d) (strlen((d)->d_name)) #define _D_ALLOC_NAMLEN(d) (NAME_MAX+1) enum { _PC_LINK_MAX, #define _PC_LINK_MAX _PC_LINK_MAX _PC_MAX_CANON, #define _PC_MAX_CANON _PC_MAX_CANON _PC_MAX_INPUT, #define _PC_MAX_INPUT _PC_MAX_INPUT _PC_NAME_MAX, #define _PC_NAME_MAX _PC_NAME_MAX _PC_PATH_MAX, #define _PC_PATH_MAX _PC_PATH_MAX _PC_PIPE_BUF, #define _PC_PIPE_BUF _PC_PIPE_BUF _PC_CHOWN_RESTRICTED, #define _PC_CHOWN_RESTRICTED _PC_CHOWN_RESTRICTED _PC_NO_TRUNC, #define _PC_NO_TRUNC _PC_NO_TRUNC _PC_VDISABLE, #define _PC_VDISABLE _PC_VDISABLE _PC_SYNC_IO, #define _PC_SYNC_IO _PC_SYNC_IO _PC_ASYNC_IO, #define _PC_ASYNC_IO _PC_ASYNC_IO _PC_PRIO_IO, #define _PC_PRIO_IO _PC_PRIO_IO _PC_SOCK_MAXBUF, #define _PC_SOCK_MAXBUF _PC_SOCK_MAXBUF _PC_FILESIZEBITS, #define _PC_FILESIZEBITS _PC_FILESIZEBITS _PC_REC_INCR_XFER_SIZE, #define _PC_REC_INCR_XFER_SIZE _PC_REC_INCR_XFER_SIZE _PC_REC_MAX_XFER_SIZE, #define _PC_REC_MAX_XFER_SIZE _PC_REC_MAX_XFER_SIZE _PC_REC_MIN_XFER_SIZE, #define _PC_REC_MIN_XFER_SIZE _PC_REC_MIN_XFER_SIZE _PC_REC_XFER_ALIGN, #define _PC_REC_XFER_ALIGN _PC_REC_XFER_ALIGN _PC_ALLOC_SIZE_MIN, #define _PC_ALLOC_SIZE_MIN _PC_ALLOC_SIZE_MIN _PC_SYMLINK_MAX, #define _PC_SYMLINK_MAX _PC_SYMLINK_MAX _PC_2_SYMLINKS #define _PC_2_SYMLINKS _PC_2_SYMLINKS }; struct dirent { ino_t d_ino; char d_name[ NAME_MAX + 1 ]; }; void _exit( int status ); pid_t fork( void ); int execv( const char* file, char* const argv[] ); int execve( const char* filename, char* const argv[], char* const envp[] ); int execvp( const char* filename, char* const argv[] ); int execlp( const char* file, const char* arg, ... ); void* sbrk( int increment ); int open( const char* filename, int flags, ... ); int close( int fd ); int dup( int old_fd ); int dup2( int old_fd, int new_fd ); ssize_t read( int fd, void* buf, size_t count ); ssize_t write( int fd, const void* buf, size_t count ); ssize_t pread( int fd, void* buf, size_t count, off_t offset ); ssize_t pwrite( int fd, const void* buf, size_t count, off_t offset ); off_t lseek( int fd, off_t offset, int whence ); int pipe( int pipefd[2] ); int isatty( int fd ); int chdir( const char* path ); int fchdir( int fd ); int getdents( int fd, struct dirent* entry, unsigned int count ); int ftruncate( int fd, off_t length ); int link( const char* oldpath, const char* newpath ); int access( const char* pathname, int mode ); int unlink( const char* pathname ); ssize_t readlink( const char* path, char* buf, size_t bufsiz ); int rmdir( const char* pathname ); int chown( const char* path, uid_t owner, gid_t group ); char* getcwd( char* buf, size_t size ); int symlink( const char* oldpath, const char* newpath ); char* ttyname( int fd ); int ttyname_r( int fd, char* buf, size_t buflen ); pid_t getpid( void ); pid_t getppid( void ); pid_t gettid( void ); int getpagesize( void ); int getdtablesize( void ); int gethostname( char* name, size_t len ); unsigned int sleep( unsigned int seconds ); unsigned int alarm( unsigned int seconds ); long fpathconf( int fd, int name ); uid_t getuid( void ); uid_t geteuid( void ); int setuid( uid_t uid ); int setreuid( uid_t ruid, uid_t euid ); gid_t getgid( void ); gid_t getegid( void ); int setgid( gid_t gid ); int setregid( gid_t rgid, gid_t egid ); pid_t tcgetpgrp( int fd ); int tcsetpgrp( int fd, pid_t pgrp ); pid_t getpgid( pid_t pid ); int setpgid( pid_t pid, pid_t pgid ); pid_t getpgrp( void ); int setpgrp( void ); #endif /* _UNISTD_H_ */ ================================================ FILE: src/sdk/include/utime.h ================================================ #ifndef _UTIME_H_ #define _UTIME_H_ #include struct utimbuf { time_t actime; /* access time */ time_t modtime; /* modification time */ }; int utime( const char* filename, const struct utimbuf* times ); int utimes( const char* filename, const timeval_t times[2] ); #endif // _UTIME_H_ ================================================ FILE: src/sdk/lib/.gitkeep ================================================ ================================================ FILE: src/sdk/qemu.sh ================================================ #!/bin/bash qemu -m 1024 -s -hda ./c.img -curses -serial /dev/tty -redir tcp:2323::23 ================================================ FILE: src/sdk/src/libc/Makefile ================================================ ASMOBJS=arch/i386/setjmp.S \ arch/i386/longjmp.S \ arch/i386/math/e_exp.S \ arch/i386/math/e_log.S \ arch/i386/math/s_sin.S \ arch/i386/math/s_cos.S \ arch/i386/math/s_floor.S \ arch/i386/math/s_ceil.S \ arch/i386/math/s_frexp.S \ arch/i386/math/s_fabs.S \ arch/i386/math/e_fmod.S \ arch/i386/math/e_atan2.S \ arch/i386/math/e_hypot.S \ arch/i386/math/e_pow.S \ arch/i386/math/s_finite.S \ arch/i386/math/s_scalbn.S \ arch/i386/math/e_log10.S OBJS= arch/i386/getpagesize.c \ src/os/syscall.c \ src/opendir.c \ src/readdir.c \ src/closedir.c \ src/rewinddir.c \ src/udivmoddi4.c \ src/sscanf.c \ src/stdlib/malloc.c \ src/stdlib/abort.c \ src/stdlib/getenv.c \ src/stdlib/strtol.c \ src/stdlib/strtoll.c \ src/stdlib/strtoul.c \ src/stdlib/strtoull.c \ src/stdlib/atoi.c \ src/stdlib/atol.c \ src/stdlib/atoll.c \ src/stdlib/atof.c \ src/stdlib/qsort.c \ src/stdlib/bsearch.c \ src/stdlib/abs.c \ src/stdlib/labs.c \ src/stdlib/llabs.c \ src/stdlib/strtod.c \ src/stdlib/mkstemp.c \ src/stdlib/random.c \ src/stdlib/srandom.c \ src/stdlib/rand.c \ src/stdlib/srand.c \ src/stdlib/mktemp.c \ src/string/memset.c \ src/string/memcpy.c \ src/string/memcmp.c \ src/string/memmove.c \ src/string/memchr.c \ src/string/strchr.c \ src/string/strrchr.c \ src/string/strlen.c \ src/string/strnlen.c \ src/string/strcmp.c \ src/string/strncmp.c \ src/string/strcasecmp.c \ src/string/strncasecmp.c \ src/string/strdup.c \ src/string/strndup.c \ src/string/strcpy.c \ src/string/strncpy.c \ src/string/strstr.c \ src/string/strerror.c \ src/string/strsignal.c \ src/string/strcat.c \ src/string/strncat.c \ src/string/strpbrk.c \ src/string/strspn.c \ src/string/strcspn.c \ src/string/strtok_r.c \ src/string/strtok.c \ src/unistd/sbrk.c \ src/unistd/fork.c \ src/unistd/execve.c \ src/unistd/execv.c \ src/unistd/execlp.c \ src/unistd/dup.c \ src/unistd/dup2.c \ src/unistd/write.c \ src/unistd/read.c \ src/unistd/pwrite.c \ src/unistd/pread.c \ src/unistd/exit.c \ src/unistd/getdents.c \ src/unistd/close.c \ src/unistd/execvp.c \ src/unistd/fchdir.c \ src/unistd/isatty.c \ src/unistd/lseek.c \ src/unistd/unlink.c \ src/unistd/readlink.c \ src/unistd/getcwd.c \ src/unistd/sleep.c \ src/unistd/access.c \ src/unistd/chdir.c \ src/unistd/ftruncate.c \ src/unistd/getpid.c \ src/unistd/getppid.c \ src/unistd/gettid.c \ src/unistd/link.c \ src/unistd/rmdir.c \ src/unistd/chown.c \ src/unistd/symlink.c \ src/unistd/ttyname.c \ src/unistd/pipe.c \ src/unistd/mmap.c \ src/unistd/alarm.c \ src/unistd/fpathconf.c \ src/unistd/getuid.c \ src/unistd/geteuid.c \ src/unistd/setuid.c \ src/unistd/setreuid.c \ src/unistd/getgid.c \ src/unistd/getegid.c \ src/unistd/setgid.c \ src/unistd/setregid.c \ src/unistd/gethostname.c \ src/unistd/getdtablesize.c \ src/unistd/getpgid.c \ src/unistd/setpgid.c \ src/unistd/getpgrp.c \ src/unistd/setpgrp.c \ src/fcntl/open.c \ src/fcntl/creat.c \ src/fcntl/fcntl.c \ src/stdio/support_bufio.c \ src/stdio/support_pf.c \ src/stdio/support_supcon.c \ src/stdio/stdio_internal.c \ src/stdio/streams.c \ src/stdio/ferror.c \ src/stdio/fgetc.c \ src/stdio/getc.c \ src/stdio/fgets.c \ src/stdio/fputc.c \ src/stdio/fputs.c \ src/stdio/fileno.c \ src/stdio/feof.c \ src/stdio/fflush.c \ src/stdio/ungetc.c \ src/stdio/clearerr.c \ src/stdio/fopen.c \ src/stdio/fdopen.c \ src/stdio/freopen.c \ src/stdio/fclose.c \ src/stdio/putc.c \ src/stdio/setvbuf.c \ src/stdio/fseek.c \ src/stdio/ftell.c \ src/stdio/fread.c \ src/stdio/fwrite.c \ src/stdio/rewind.c \ src/stdio/perror.c \ src/stdio/puts.c \ src/stdio/putchar.c \ src/stdio/rename.c \ src/stdio/remove.c \ src/stdio/fpurge.c \ src/time/tzset.c \ src/time/time_int.c \ src/time/strftime.c \ src/time/mktime.c \ src/time/ctime.c \ src/time/ctime_r.c \ src/time/localtime.c \ src/time/localtime_r.c \ src/time/asctime.c \ src/time/asctime_r.c \ src/time/gmtime.c \ src/time/gmtime_r.c \ src/time/gettimeofday.c \ src/time/ctime.c \ src/time/time.c \ src/time/nanosleep.c \ src/getopt/getopt.c \ src/getopt/getopt_long.c \ src/getopt/getopt_long_only.c \ src/sys/stat.c \ src/sys/fstat.c \ src/sys/stime.c \ src/sys/mkdir.c \ src/sys/ioctl.c \ src/sys/select.c \ src/sys/mount.c \ src/sys/umount.c \ src/sys/lstat.c \ src/sys/umask.c \ src/sys/chmod.c \ src/sys/utime.c \ src/sys/utimes.c \ src/sys/wait.c \ src/sys/wait3.c \ src/sys/wait4.c \ src/sys/waitpid.c \ src/sys/socket.c \ src/sys/connect.c \ src/ctype/isalpha.c \ src/ctype/isupper.c \ src/ctype/isblank.c \ src/ctype/islower.c \ src/ctype/isdigit.c \ src/ctype/isxdigit.c \ src/ctype/isalnum.c \ src/ctype/isspace.c \ src/ctype/isprint.c \ src/ctype/iscntrl.c \ src/ctype/tolower.c \ src/ctype/toupper.c \ src/ctype/toascii.c \ src/ctype/isgraph.c \ src/ctype/ispunct.c \ src/ctype/isascii.c \ src/signal/signal.c \ src/signal/sigaction.c \ src/signal/kill.c \ src/signal/killpg.c \ src/signal/raise.c \ src/signal/sigemptyset.c \ src/signal/sigfillset.c \ src/signal/sigaddset.c \ src/signal/sigdelset.c \ src/signal/sigismember.c \ src/signal/sigprocmask.c \ src/locale/localeconv.c \ src/locale/setlocale.c \ src/termios/tcflush.c \ src/termios/tcgetattr.c \ src/termios/tcsetattr.c \ src/termios/tcflow.c \ src/termios/tcgetpgrp.c \ src/termios/tcsetpgrp.c \ src/math/s_ldexp.c \ src/math/s_modf.c \ src/os/debug.c \ src/os/semaphore.c \ src/os/sysinfo.c \ src/os/region.c \ src/os/module.c \ src/os/os.c \ src/os/thread.c \ src/os/ipc.c \ src/pwd/getpwuid.c \ src/pwd/getpwent.c \ src/pwd/getpwnam.c \ src/pwd/endpwent.c \ src/pwd/setpwent.c \ src/network/inet_aton.c \ src/network/inet_ntoa.c # src/trio/trio.c \ # src/trio/trionan.c \ # src/trio/triostr.c \ START=src/start.c STARTO= $(START:.c=.o) OBJO = $(OBJS:.c=.o) OBJSO= $(ASMOBJS:.S=.o) OBJ=libc.a crt CC=gcc -w -m32 -Wa,--32 -g -nostdlib -nostdinc -trigraphs -I $(SDKDIR)/include -c SDKDIR=../.. all: $(OBJ) libc.a: $(OBJO) $(OBJSO) ar rcs $@ *.o cp libc.a $(SDKDIR)/lib/libc.a crt: $(STARTO) cp start.o $(SDKDIR)/lib/crt_c.o rm *.o %.o: %.c $(CC) $< %.o: %.S $(CC) $< clean: rm -f $(OBJ) *.o *.a ================================================ FILE: src/sdk/src/libc/arch/i386/getpagesize.c ================================================ /* getpagesize function * * Copyright (c) 2009 Zoltan Kovacs * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include int getpagesize( void ) { return 4096; } ================================================ FILE: src/sdk/src/libc/arch/i386/longjmp.S ================================================ /* longjmp function * * Copyright (c) 2009 Zoltan Kovacs * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ .section .text .global longjmp longjmp: movl 4(%esp), %edx movl 8(%esp), %eax /* Restore registers */ movl 4(%edx), %ebp movl 8(%edx), %esp movl 12(%edx), %ebx movl 16(%edx), %edi movl 20(%edx), %esi /* Restore return address */ movl 0(%edx), %ecx movl %ecx, 0(%esp) /* Check return code */ cmpl $0, %eax je 1f ret 1: movl $1, %eax ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/e_atan2.S ================================================ /* * Written by J.T. Conklin . * Public domain. */ .section .text .align 4 .global atan2 atan2: fldl 4(%esp) fldl 12(%esp) fpatan ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/e_exp.S ================================================ /* * Written by J.T. Conklin . * Public domain. */ /* e^x = 2^(x * log2(e)) */ .section .text .align 4 .global exp exp: fldl 4(%esp) /* I added the following ugly construct because exp(+-Inf) resulted in NaN. The ugliness results from the bright minds at Intel. For the i686 the code can be written better. -- drepper@cygnus.com. */ fxam /* Is NaN or +-Inf? */ fstsw %ax movb $0x45, %dh andb %ah, %dh cmpb $0x05, %dh je 1f /* Is +-Inf, jump. */ fldl2e fmulp /* x * log2(e) */ fld %st frndint /* int(x * log2(e)) */ fsubr %st,%st(1) /* fract(x * log2(e)) */ fxch f2xm1 /* 2^(fract(x * log2(e))) - 1 */ fld1 faddp /* 2^(fract(x * log2(e))) */ fscale /* e^x */ fstp %st(1) ret 1: testl $0x200, %eax /* Test sign. */ jz 2f /* If positive, jump. */ fstp %st fldz /* Set result to 0. */ 2: ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/e_fmod.S ================================================ /* * Written by J.T. Conklin . * Public domain. */ .section .text .align 4 .global fmod fmod: fldl 12(%esp) fldl 4(%esp) 1: fprem fstsw %ax sahf jp 1b fstp %st(1) ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/e_hypot.S ================================================ /* Compute the hypothenuse of X and Y. Copyright (C) 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1998. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ .section .text .align 4 .global hypot hypot: fldl 4(%esp) // x fxam fnstsw fldl 12(%esp) // y : x movb %ah, %ch fxam fnstsw movb %ah, %al orb %ch, %ah sahf jc 1f fmul %st(0) // y * y : x fxch // x : y * y fmul %st(0) // x * x : y * y faddp // x * x + y * y fsqrt 2: ret // We have to test whether any of the parameters is Inf. // In this case the result is infinity. 1: andb $0x45, %al cmpb $5, %al je 3f // jump if y is Inf andb $0x45, %ch cmpb $5, %ch jne 4f // jump if x is not Inf fxch 3: fstp %st(1) fabs jmp 2b 4: testb $1, %al jnz 5f // y is NaN fxch 5: fstp %st(1) jmp 2b ================================================ FILE: src/sdk/src/libc/arch/i386/math/e_log.S ================================================ /* * Written by J.T. Conklin . * Public domain. * * Changed to use fyl2xp1 for values near 1, . */ .section .rodata .align 4 one: .double 1.0 /* It is not important that this constant is precise. It is only a value which is known to be on the safe side for using the fyl2xp1 instruction. */ limit: .double 0.29 #ifdef PIC #define MO(op) op##@GOTOFF(%edx) #else #define MO(op) op #endif .section .text .global log log: fldln2 // log(2) fldl 4(%esp) // x : log(2) fxam fnstsw #ifdef PIC LOAD_PIC_REG (dx) #endif fld %st // x : x : log(2) sahf jc 3f // in case x is NaN or +-Inf 4: fsubl MO(one) // x-1 : x : log(2) fld %st // x-1 : x-1 : x : log(2) fabs // |x-1| : x-1 : x : log(2) fcompl MO(limit) // x-1 : x : log(2) fnstsw // x-1 : x : log(2) andb $0x45, %ah jz 2f fstp %st(1) // x-1 : log(2) fyl2xp1 // log(x) ret 2: fstp %st(0) // x : log(2) fyl2x // log(x) ret 3: jp 4b // in case x is +-Inf fstp %st(1) fstp %st(1) ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/e_log10.S ================================================ /* * Written by J.T. Conklin . * Public domain. * * Changed to use fyl2xp1 for values near 1, . */ .section .rodata .align 4 one: .double 1.0 /* It is not important that this constant is precise. It is only a value which is known to be on the safe side for using the fyl2xp1 instruction. */ limit: .double 0.29 #ifdef PIC #define MO(op) op##@GOTOFF(%edx) #else #define MO(op) op #endif .section .text .align 4 .global log10 log10: fldlg2 // log10(2) fldl 4(%esp) // x : log10(2) #ifdef PIC LOAD_PIC_REG (dx) #endif fxam fnstsw fld %st // x : x : log10(2) sahf jc 3f // in case x is NaN or Inf 4: fsubl MO(one) // x-1 : x : log10(2) fld %st // x-1 : x-1 : x : log10(2) fabs // |x-1| : x-1 : x : log10(2) fcompl MO(limit) // x-1 : x : log10(2) fnstsw // x-1 : x : log10(2) andb $0x45, %ah jz 2f fstp %st(1) // x-1 : log10(2) fyl2xp1 // log10(x) ret 2: fstp %st(0) // x : log10(2) fyl2x // log10(x) ret 3: jp 4b // in case x is Inf fstp %st(1) fstp %st(1) ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/e_pow.S ================================================ /* ix87 specific implementation of pow function. Copyright (C) 1996, 1997, 1998, 1999, 2001, 2004, 2005, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1996. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ .section .rodata .align 4 inf_zero: infinity: .byte 0, 0, 0, 0, 0, 0, 0xf0, 0x7f zero: .double 0.0 minf_mzero: minfinity: .byte 0, 0, 0, 0, 0, 0, 0xf0, 0xff mzero: .byte 0, 0, 0, 0, 0, 0, 0, 0x80 one: .double 1.0 limit: .double 0.29 p63: .byte 0, 0, 0, 0, 0, 0, 0xe0, 0x43 #ifdef PIC #define MO(op) op##@GOTOFF(%ecx) #define MOX(op,x,f) op##@GOTOFF(%ecx,x,f) #else #define MO(op) op #define MOX(op,x,f) op(,x,f) #endif .section .text .align 4 .global pow pow: fldl 12(%esp) // y fxam #ifdef PIC LOAD_PIC_REG (cx) #endif fnstsw movb %ah, %dl andb $0x45, %ah cmpb $0x40, %ah // is y == 0 ? je 11f cmpb $0x05, %ah // is y == inf ? je 12f cmpb $0x01, %ah // is y == NaN ? je 30f fldl 4(%esp) // x : y subl $8,%esp fxam fnstsw movb %ah, %dh andb $0x45, %ah cmpb $0x40, %ah je 20f // x is 0 cmpb $0x05, %ah je 15f // x is inf fxch // y : x /* fistpll raises invalid exception for |y| >= 1L<<63. */ fld %st // y : y : x fabs // |y| : y : x fcompl MO(p63) // y : x fnstsw sahf jnc 2f /* First see whether `y' is a natural number. In this case we can use a more precise algorithm. */ fld %st // y : y : x fistpll (%esp) // y : x fildll (%esp) // int(y) : y : x fucomp %st(1) // y : x fnstsw sahf jne 2f /* OK, we have an integer value for y. */ popl %eax popl %edx orl $0, %edx fstp %st(0) // x jns 4f // y >= 0, jump fdivrl MO(one) // 1/x (now referred to as x) negl %eax adcl $0, %edx negl %edx 4: fldl MO(one) // 1 : x fxch 6: shrdl $1, %edx, %eax jnc 5f fxch fmul %st(1) // x : ST*x fxch 5: fmul %st(0), %st // x*x : ST*x shrl $1, %edx movl %eax, %ecx orl %edx, %ecx jnz 6b fstp %st(0) // ST*x ret /* y is NAN */ 30: fldl 4(%esp) // x : y fldl MO(one) // 1.0 : x : y fucomp %st(1) // x : y fnstsw sahf je 31f fxch // y : x 31: fstp %st(1) ret .align 4 2: /* y is a real number. */ fxch // x : y fldl MO(one) // 1.0 : x : y fldl MO(limit) // 0.29 : 1.0 : x : y fld %st(2) // x : 0.29 : 1.0 : x : y fsub %st(2) // x-1 : 0.29 : 1.0 : x : y fabs // |x-1| : 0.29 : 1.0 : x : y fucompp // 1.0 : x : y fnstsw fxch // x : 1.0 : y sahf ja 7f fsub %st(1) // x-1 : 1.0 : y fyl2xp1 // log2(x) : y jmp 8f 7: fyl2x // log2(x) : y 8: fmul %st(1) // y*log2(x) : y fst %st(1) // y*log2(x) : y*log2(x) frndint // int(y*log2(x)) : y*log2(x) fsubr %st, %st(1) // int(y*log2(x)) : fract(y*log2(x)) fxch // fract(y*log2(x)) : int(y*log2(x)) f2xm1 // 2^fract(y*log2(x))-1 : int(y*log2(x)) faddl MO(one) // 2^fract(y*log2(x)) : int(y*log2(x)) fscale // 2^fract(y*log2(x))*2^int(y*log2(x)) : int(y*log2(x)) addl $8, %esp fstp %st(1) // 2^fract(y*log2(x))*2^int(y*log2(x)) ret // pow(x,0) = 1 .align 4 11: fstp %st(0) // pop y fldl MO(one) ret // y == inf .align 4 12: fstp %st(0) // pop y fldl MO(one) // 1 fldl 4(%esp) // x : 1 fabs // abs(x) : 1 fucompp // < 1, == 1, or > 1 fnstsw andb $0x45, %ah cmpb $0x45, %ah je 13f // jump if x is NaN cmpb $0x40, %ah je 14f // jump if |x| == 1 shlb $1, %ah xorb %ah, %dl andl $2, %edx fldl MOX(inf_zero, %edx, 4) ret .align 4 14: fldl MO(one) ret .align 4 13: fldl 4(%esp) // load x == NaN ret .align 4 // x is inf 15: fstp %st(0) // y testb $2, %dh jz 16f // jump if x == +inf // We must find out whether y is an odd integer. fld %st // y : y fistpll (%esp) // y fildll (%esp) // int(y) : y fucompp // fnstsw sahf jne 17f // OK, the value is an integer, but is the number of bits small // enough so that all are coming from the mantissa? popl %eax popl %edx andb $1, %al jz 18f // jump if not odd movl %edx, %eax orl %edx, %edx jns 155f negl %eax 155: cmpl $0x00200000, %eax ja 18f // does not fit in mantissa bits // It's an odd integer. shrl $31, %edx fldl MOX(minf_mzero, %edx, 8) ret .align 4 16: fcompl MO(zero) addl $8, %esp fnstsw shrl $5, %eax andl $8, %eax fldl MOX(inf_zero, %eax, 1) ret .align 4 17: shll $30, %edx // sign bit for y in right position addl $8, %esp 18: shrl $31, %edx fldl MOX(inf_zero, %edx, 8) ret .align 4 // x is 0 20: fstp %st(0) // y testb $2, %dl jz 21f // y > 0 // x is 0 and y is < 0. We must find out whether y is an odd integer. testb $2, %dh jz 25f fld %st // y : y fistpll (%esp) // y fildll (%esp) // int(y) : y fucompp // fnstsw sahf jne 26f // OK, the value is an integer, but is the number of bits small // enough so that all are coming from the mantissa? popl %eax popl %edx andb $1, %al jz 27f // jump if not odd cmpl $0xffe00000, %edx jbe 27f // does not fit in mantissa bits // It's an odd integer. // Raise divide-by-zero exception and get minus infinity value. fldl MO(one) fdivl MO(zero) fchs ret 25: fstp %st(0) 26: addl $8, %esp 27: // Raise divide-by-zero exception and get infinity value. fldl MO(one) fdivl MO(zero) ret .align 4 // x is 0 and y is > 0. We must find out whether y is an odd integer. 21: testb $2, %dh jz 22f fld %st // y : y fistpll (%esp) // y fildll (%esp) // int(y) : y fucompp // fnstsw sahf jne 23f // OK, the value is an integer, but is the number of bits small // enough so that all are coming from the mantissa? popl %eax popl %edx andb $1, %al jz 24f // jump if not odd cmpl $0xffe00000, %edx jae 24f // does not fit in mantissa bits // It's an odd integer. fldl MO(mzero) ret 22: fstp %st(0) 23: addl $8, %esp // Don't use 2 x pop 24: fldl MO(zero) ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/s_ceil.S ================================================ /* * Written by J.T. Conklin . * Public domain. */ .section .text .align 4 .global ceil ceil: fldl 4(%esp) subl $8,%esp fstcw 4(%esp) /* store fpu control word */ /* We use here %edx although only the low 1 bits are defined. But none of the operations should care and they are faster than the 16 bit operations. */ movl $0x0800,%edx /* round towards +oo */ orl 4(%esp),%edx andl $0xfbff,%edx movl %edx,(%esp) fldcw (%esp) /* load modified control word */ frndint /* round */ fldcw 4(%esp) /* restore original control word */ addl $8,%esp ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/s_cos.S ================================================ /* * Written by J.T. Conklin . * Public domain. */ .section .text .align 4 .global cos cos: fldl 4(%esp) fcos fnstsw %ax testl $0x400,%eax jnz 1f ret .align 4 1: fldpi fadd %st(0) fxch %st(1) 2: fprem1 fnstsw %ax testl $0x400,%eax jnz 2b fstp %st(1) fcos ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/s_fabs.S ================================================ .section .text .align 4 .global fabs fabs: fldl 4(%esp) fabs ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/s_finite.S ================================================ /* * Written by Joe Keane . */ .section .text .align 4 .global finite finite: movl 8(%esp),%eax movl $0xFFEFFFFF,%ecx subl %eax,%ecx xorl %ecx,%eax shrl $31, %eax ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/s_floor.S ================================================ /* * Written by J.T. Conklin . * Public domain. */ .section .text .align 4 .global floor floor: fldl 4(%esp) subl $8,%esp fstcw 4(%esp) /* store fpu control word */ /* We use here %edx although only the low 1 bits are defined. But none of the operations should care and they are faster than the 16 bit operations. */ movl $0x400,%edx /* round towards -oo */ orl 4(%esp),%edx andl $0xf7ff,%edx movl %edx,(%esp) fldcw (%esp) /* load modified control word */ frndint /* round */ fldcw 4(%esp) /* restore original control word */ addl $8,%esp ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/s_frexp.S ================================================ /* ix87 specific frexp implementation for double. Copyright (C) 1997, 2000, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1997. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ .section .rodata .align 4 two54: .byte 0, 0, 0, 0, 0, 0, 0x50, 0x43 #ifdef PIC #define MO(op) op##@GOTOFF(%edx) #else #define MO(op) op #endif #define PARMS 4 #define VAL0 PARMS #define VAL1 VAL0+4 #define EXPP VAL1+4 .section .text .align 4 .global frexp frexp: movl VAL0(%esp), %ecx movl VAL1(%esp), %eax movl %eax, %edx andl $0x7fffffff, %eax orl %eax, %ecx jz 1f xorl %ecx, %ecx cmpl $0x7ff00000, %eax jae 1f cmpl $0x00100000, %eax jae 2f fldl VAL0(%esp) #ifdef PIC LOAD_PIC_REG (dx) #endif fmull MO(two54) movl $-54, %ecx fstpl VAL0(%esp) fwait movl VAL1(%esp), %eax movl %eax, %edx andl $0x7fffffff, %eax 2: shrl $20, %eax andl $0x800fffff, %edx subl $1022, %eax orl $0x3fe00000, %edx addl %eax, %ecx movl %edx, VAL1(%esp) /* Store %ecx in the variable pointed to by the second argument, get the factor from the stack and return. */ 1: movl EXPP(%esp), %eax fldl VAL0(%esp) movl %ecx, (%eax) ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/s_scalbn.S ================================================ /* * Written by J.T. Conklin . * Public domain. */ .section .text .align 4 .global scalbn scalbn: fildl 12(%esp) fldl 4(%esp) fscale fstp %st(1) ret ================================================ FILE: src/sdk/src/libc/arch/i386/math/s_sin.S ================================================ /* * Written by J.T. Conklin . * Public domain. */ .section .text .align 4 .global sin sin: fldl 4(%esp) fsin fnstsw %ax testl $0x400,%eax jnz 1f ret .align 4 1: fldpi fadd %st(0) fxch %st(1) 2: fprem1 fnstsw %ax testl $0x400,%eax jnz 2b fstp %st(1) fsin ret ================================================ FILE: src/sdk/src/libc/arch/i386/setjmp.S ================================================ /* setjmp function * * Copyright (c) 2009 Zoltan Kovacs * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ .section .text .global setjmp setjmp: movl 4(%esp), %edx /* Save return address */ movl 0(%esp), %ecx movl %ecx, 0(%edx) /* Save registers: ebp, esp, ebx, edi and esi */ movl %ebp, 4(%edx) movl %esp, 8(%edx) movl %ebx, 12(%edx) movl %edi, 16(%edx) movl %esi, 20(%edx) /* Return 0 */ movl $0, %eax ret ================================================ FILE: src/sdk/src/libc/src/closedir.c ================================================ #include #include #include #include int closedir( DIR* dir ) { if ( dir == NULL ) { errno = EBADF; return -1; } close( dir->fd ); free( dir ); return 0; } ================================================ FILE: src/sdk/src/libc/src/ctype/isalnum.c ================================================ #include int isalnum( int c ) { return ( ( isalpha( c ) ) || ( isdigit( c ) ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isalpha.c ================================================ #include int isalpha( int c ) { return ( islower( c ) || isupper( c ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isascii.c ================================================ #include int isascii( int c ) { return ( ( unsigned int )c < 128u ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isblank.c ================================================ #include int isblank( int c ) { return ( c == ' ' || c == '\t' ); } ================================================ FILE: src/sdk/src/libc/src/ctype/iscntrl.c ================================================ #include int iscntrl( int c ) { return ( ( ( unsigned int )c < 32u ) || ( c == 127 ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isdigit.c ================================================ #include int isdigit( int c ) { return ( ( c >= '0' ) && ( c <= '9' ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isgraph.c ================================================ #include int isgraph( int c ) { if ( c == ' ' ) { return 0; } return isprint( c ); } ================================================ FILE: src/sdk/src/libc/src/ctype/islower.c ================================================ #include int islower( int c ) { return ( ( c >= 'a' ) && ( c <= 'z' ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isprint.c ================================================ #include int isprint( int c ) { c &= 0x7F; return ( ( c >= 0x20 ) && ( c < 0x7F ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/ispunct.c ================================================ #include int ispunct( int c ) { return ( isprint( c ) && !isalnum( c ) && !isspace( c ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isspace.c ================================================ #include int isspace( int c ) { return ( c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r' || c == ' ' ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isupper.c ================================================ #include int isupper( int c ) { return ( ( c >= 'A' ) && ( c <= 'Z' ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/isxdigit.c ================================================ #include int isxdigit( int c ) { return ( ( ( c >= '0' ) && ( c <= '9' ) ) || ( ( c >= 'a' ) && ( c <= 'f' ) ) || ( ( c >= 'A' ) && ( c <= 'F' ) ) ); } ================================================ FILE: src/sdk/src/libc/src/ctype/toascii.c ================================================ #include int toascii( int c ) { return ( c & ~0x80 ); } ================================================ FILE: src/sdk/src/libc/src/ctype/tolower.c ================================================ #include int tolower( int c ) { if ( isupper( c ) ) { return c | 0x20; } else { return c; } } ================================================ FILE: src/sdk/src/libc/src/ctype/toupper.c ================================================ #include int toupper( int c ) { if ( islower( c ) ) { return c & ~0x20; } else { return c; } } ldiv_t ldiv(long numerator, long denominator) { ldiv_t x; x.quot=numerator/denominator; x.rem=numerator-x.quot*denominator; return x; } div_t div(int numerator, int denominator) { div_t x; x.quot=numerator/denominator; x.rem=numerator-x.quot*denominator; return x; } ================================================ FILE: src/sdk/src/libc/src/fcntl/creat.c ================================================ #include int creat( const char *pathname, mode_t mode ) { return open( pathname, O_CREAT | O_WRONLY | O_TRUNC, mode ); } ================================================ FILE: src/sdk/src/libc/src/fcntl/fcntl.c ================================================ #include #include #include int fcntl( int fd, int cmd, ... ) { int error; error = syscall3( SYS_fcntl, fd, cmd, *( ( ( int* )&cmd ) + 1 ) ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/fcntl/open.c ================================================ #include #include #include int open( const char* filename, int flags, ... ) { int error; error = syscall2( SYS_open, ( int )filename, flags ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/getopt/getopt.c ================================================ #include #include #include #include /* NULL */ #include #include "getopt_int.h" # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (d->__nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif char *optarg; int optind = 1; int opterr = 1; int optopt = '?'; static struct _getopt_data getopt_data; static void exchange (char **argv, struct _getopt_data *d) { int bottom = d->__first_nonopt; int middle = d->__last_nonopt; int top = d->optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, d->__nonoption_flags_max_len), '\0', top + 1 - d->__nonoption_flags_max_len); d->__nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ d->__first_nonopt += (d->optind - d->__last_nonopt); d->__last_nonopt = d->optind; } /* Initialize the internal data when the first call is made. */ static const char * _getopt_initialize (int argc, char *const *argv, const char *optstring, struct _getopt_data *d) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ d->__first_nonopt = d->__last_nonopt = d->optind; d->__nextchar = NULL; d->__posixly_correct = !!getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { d->__ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { d->__ordering = REQUIRE_ORDER; ++optstring; } else if (d->__posixly_correct) d->__ordering = REQUIRE_ORDER; else d->__ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (!d->__posixly_correct && argc == __libc_argc && argv == __libc_argv) { if (d->__nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') d->__nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = d->__nonoption_flags_max_len = strlen (orig_str); if (d->__nonoption_flags_max_len < argc) d->__nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (d->__nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) d->__nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', d->__nonoption_flags_max_len - len); } } d->__nonoption_flags_len = d->__nonoption_flags_max_len; } else d->__nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal_r (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d) { int print_errors = d->opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; d->optarg = NULL; if (d->optind == 0 || !d->__initialized) { if (d->optind == 0) d->optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring, d); d->__initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \ || (d->optind < d->__nonoption_flags_len \ && __getopt_nonoption_flags[d->optind] == '1')) #else # define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') #endif if (d->__nextchar == NULL || *d->__nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (d->__last_nonopt > d->optind) d->__last_nonopt = d->optind; if (d->__first_nonopt > d->optind) d->__first_nonopt = d->optind; if (d->__ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) exchange ((char **) argv, d); else if (d->__last_nonopt != d->optind) d->__first_nonopt = d->optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (d->optind < argc && NONOPTION_P) d->optind++; d->__last_nonopt = d->optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (d->optind != argc && !strcmp (argv[d->optind], "--")) { d->optind++; if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) exchange ((char **) argv, d); else if (d->__first_nonopt == d->__last_nonopt) d->__first_nonopt = d->optind; d->__last_nonopt = argc; d->optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (d->optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (d->__first_nonopt != d->__last_nonopt) d->optind = d->__first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (d->__ordering == REQUIRE_ORDER) return -1; d->optarg = argv[d->optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr (optstring, argv[d->optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) { if ((unsigned int) (nameend - d->__nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, "%s: option '%s' is ambiguous\n", argv[0], argv[d->optind]) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, "%s: option '%s' is ambiguous\n", argv[0], argv[d->optind]); #endif } d->__nextchar += strlen (d->__nextchar); d->optind++; d->optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; d->optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) d->optarg = nameend + 1; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif if (argv[d->optind - 1][1] == '-') { /* --option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, "\ %s: option '--%s' doesn't allow an argument\n", argv[0], pfound->name); #else fprintf (stderr, "\ %s: option '--%s' doesn't allow an argument\n", argv[0], pfound->name); #endif } else { /* +option or -option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, "\ %s: option '%c%s' doesn't allow an argument\n", argv[0], argv[d->optind - 1][0], pfound->name); #else fprintf (stderr, "\ %s: option '%c%s' doesn't allow an argument\n", argv[0], argv[d->optind - 1][0], pfound->name); #endif } #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #endif } d->__nextchar += strlen (d->__nextchar); d->optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (d->optind < argc) d->optarg = argv[d->optind++]; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, "\ %s: option '%s' requires an argument\n", argv[0], argv[d->optind - 1]) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, "%s: option '%s' requires an argument\n", argv[0], argv[d->optind - 1]); #endif } d->__nextchar += strlen (d->__nextchar); d->optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } d->__nextchar += strlen (d->__nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[d->optind][1] == '-' || strchr (optstring, *d->__nextchar) == NULL) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif if (argv[d->optind][1] == '-') { /* --option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, "%s: unrecognized option '--%s'\n", argv[0], d->__nextchar); #else fprintf (stderr, "%s: unrecognized option '--%s'\n", argv[0], d->__nextchar); #endif } else { /* +option or -option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, "%s: unrecognized option '%c%s'\n", argv[0], argv[d->optind][0], d->__nextchar); #else fprintf (stderr, "%s: unrecognized option '%c%s'\n", argv[0], argv[d->optind][0], d->__nextchar); #endif } #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #endif } d->__nextchar = (char *) ""; d->optind++; d->optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *d->__nextchar++; char *temp = strchr (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*d->__nextchar == '\0') ++d->optind; if (temp == NULL || c == ':') { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, "%s: invalid option -- '%c'\n", argv[0], c); #else fprintf (stderr, "%s: invalid option -- '%c'\n", argv[0], c); #endif #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #endif } d->optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ d->optind++; } else if (d->optind == argc) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, "%s: option requires an argument -- '%c'\n", argv[0], c) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, "%s: option requires an argument -- '%c'\n", argv[0], c); #endif } d->optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `d->optind' once; increment it again when taking next ARGV-elt as argument. */ d->optarg = argv[d->optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) { if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, "%s: option '-W %s' is ambiguous\n", argv[0], argv[d->optind]) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, "%s: option '-W %s' is ambiguous\n", argv[0], argv[d->optind]); #endif } d->__nextchar += strlen (d->__nextchar); d->optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) d->optarg = nameend + 1; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, "\ %s: option '-W %s' doesn't allow an argument\n", argv[0], pfound->name) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, "\ %s: option '-W %s' doesn't allow an argument\n", argv[0], pfound->name); #endif } d->__nextchar += strlen (d->__nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (d->optind < argc) d->optarg = argv[d->optind++]; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, "\ %s: option '%s' requires an argument\n", argv[0], argv[d->optind - 1]) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, "%s: option '%s' requires an argument\n", argv[0], argv[d->optind - 1]); #endif } d->__nextchar += strlen (d->__nextchar); return optstring[0] == ':' ? ':' : '?'; } } d->__nextchar += strlen (d->__nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } d->__nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; d->optind++; } else d->optarg = NULL; d->__nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ d->optind++; } else if (d->optind == argc) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, "\ %s: option requires an argument -- '%c'\n", argv[0], c) >= 0) { _IO_flockfile (stderr); int old_flags2 = ((_IO_FILE *) stderr)->_flags2; ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; __fxprintf (NULL, "%s", buf); ((_IO_FILE *) stderr)->_flags2 = old_flags2; _IO_funlockfile (stderr); free (buf); } #else fprintf (stderr, "%s: option requires an argument -- '%c'\n", argv[0], c); #endif } d->optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ d->optarg = argv[d->optind++]; d->__nextchar = NULL; } } return c; } } int _getopt_internal ( int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only ) { int result; getopt_data.optind = optind; getopt_data.opterr = opterr; result = _getopt_internal_r (argc, argv, optstring, longopts, longind, long_only, &getopt_data); optind = getopt_data.optind; optarg = getopt_data.optarg; optopt = getopt_data.optopt; return result; } int getopt( int argc, char* const * argv, const char* optstring ) { return _getopt_internal( argc, argv, optstring, (const struct option *) 0, (int *) 0, 0 ); } ================================================ FILE: src/sdk/src/libc/src/getopt/getopt_int.h ================================================ #ifndef _GETOPT_INT_H_ #define _GETOPT_INT_H_ struct _getopt_data { int optind; int opterr; int optopt; char *optarg; int __initialized; char *__nextchar; enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } __ordering; int __posixly_correct; int __first_nonopt; int __last_nonopt; int __nonoption_flags_max_len; int __nonoption_flags_len; }; #define _GETOPT_DATA_INITIALIZER { 1, 1 } extern int _getopt_internal (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); extern int _getopt_internal_r (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only, struct _getopt_data *__data); extern int _getopt_long_r (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, struct _getopt_data *__data); extern int _getopt_long_only_r (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, struct _getopt_data *__data); #endif ================================================ FILE: src/sdk/src/libc/src/getopt/getopt_long.c ================================================ #include #include #include #include /* NULL */ #include #include "getopt_int.h" int getopt_long( int argc, char* const * argv, const char* shortopts, const struct option* longopts, int* longind ){ return _getopt_internal (argc, argv, shortopts, longopts, longind, 0); } ================================================ FILE: src/sdk/src/libc/src/getopt/getopt_long_only.c ================================================ #include #include #include #include /* NULL */ #include #include "getopt_int.h" int getopt_long_only( int argc, char* const * argv, const char* shortopts, const struct option* longopts, int* longind ){ return _getopt_internal (argc, argv, shortopts, longopts, longind, 1); } ================================================ FILE: src/sdk/src/libc/src/locale/localeconv.c ================================================ #include #include static const struct lconv _locale = { .decimal_point = ".", .thousands_sep = "", .grouping = "", .int_curr_symbol = "", .currency_symbol = "", .mon_decimal_point = ".", .mon_thousands_sep = "", .mon_grouping = "", .positive_sign = "+", .negative_sign = "-", .int_frac_digits = CHAR_MAX, .frac_digits = CHAR_MAX, .p_cs_precedes = CHAR_MAX, .p_sep_by_space = CHAR_MAX, .n_cs_precedes = CHAR_MAX, .n_sep_by_space = CHAR_MAX, .p_sign_posn = CHAR_MAX, .n_sign_posn = CHAR_MAX, .int_p_cs_precedes = CHAR_MAX, .int_p_sep_by_space = CHAR_MAX, .int_n_cs_precedes = CHAR_MAX, .int_n_sep_by_space = CHAR_MAX, .int_p_sign_posn = CHAR_MAX, .int_n_sign_posn = CHAR_MAX }; struct lconv* localeconv( void ) { return ( struct lconv* ) &_locale; } ================================================ FILE: src/sdk/src/libc/src/locale/setlocale.c ================================================ #include #include char* setlocale( int category, const char* locale ) { /* TODO */ return NULL; } ================================================ FILE: src/sdk/src/libc/src/math/s_ldexp.c ================================================ #include #include double ldexp( double value, int exp ) { if ( !finite(value) || value == 0.0 ) return value; value = scalbn(value,exp); if ( !finite(value) || value == 0.0 ) errno = ERANGE; return value; } ================================================ FILE: src/sdk/src/libc/src/math/s_modf.c ================================================ /* * modf(double x, double *iptr) * return fraction part of x, and return x's integral part in *iptr. * Method: * Bit twiddling. * * Exception: * No exception. */ #include #include #define EXTRACT_WORDS(ix0,ix1,d) \ do { \ ieee_double_shape_type ew_u; \ ew_u.value = (d); \ (ix0) = ew_u.parts.msw; \ (ix1) = ew_u.parts.lsw; \ } while (0) #define INSERT_WORDS(d,ix0,ix1) \ do { \ ieee_double_shape_type iw_u; \ iw_u.parts.msw = (ix0); \ iw_u.parts.lsw = (ix1); \ (d) = iw_u.value; \ } while (0) typedef union { double value; struct { uint32_t lsw; uint32_t msw; } parts; } ieee_double_shape_type; static const double one = 1.0; double modf(double x, double *iptr) { int32_t i0,i1,j0; uint32_t i; EXTRACT_WORDS(i0,i1,x); j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */ if(j0<20) { /* integer part in high x */ if(j0<0) { /* |x|<1 */ INSERT_WORDS(*iptr,i0&0x80000000,0); /* *iptr = +-0 */ return x; } else { i = (0x000fffff)>>j0; if(((i0&i)|i1)==0) { /* x is integral */ *iptr = x; INSERT_WORDS(x,i0&0x80000000,0); /* return +-0 */ return x; } else { INSERT_WORDS(*iptr,i0&(~i),0); return x - *iptr; } } } else if (j0>51) { /* no fraction part */ *iptr = x*one; /* We must handle NaNs separately. */ if (j0 == 0x400 && ((i0 & 0xfffff) | i1)) return x*one; INSERT_WORDS(x,i0&0x80000000,0); /* return +-0 */ return x; } else { /* fraction part in low x */ i = ((uint32_t)(0xffffffff))>>(j0-20); if((i1&i)==0) { /* x is integral */ *iptr = x; INSERT_WORDS(x,i0&0x80000000,0); /* return +-0 */ return x; } else { INSERT_WORDS(*iptr,i0,i1&(~i)); return x - *iptr; } } } ================================================ FILE: src/sdk/src/libc/src/network/inet_aton.c ================================================ #include #include #include int inet_aton( const char* cp, struct in_addr* inp ) { int i; unsigned int ip = 0; char* tmp= ( char* )cp; for ( i = 24; ; ) { long j; j = strtoul( tmp, &tmp, 0 ); if ( *tmp == 0 ) { ip |= j; break; } else if ( *tmp == '.' ) { if ( j > 255 ) { return 0; } ip |= ( j << i ); if ( i > 0 ) { i -= 8; } ++tmp; continue; } return 0; } inp->s_addr = htonl( ip ); return 1; } ================================================ FILE: src/sdk/src/libc/src/network/inet_ntoa.c ================================================ #include #include #include #include char* inet_ntoa( struct in_addr in ) { unsigned int ip; static char __inet_ntoa_result[18]; int i; uint8_t bytes[4]; uint8_t* addrbyte; ip = in.s_addr; addrbyte = (uint8_t *)&ip; for(i = 0; i < 4; i++) { bytes[i] = *addrbyte++; } snprintf (__inet_ntoa_result, 18, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); return __inet_ntoa_result; } ================================================ FILE: src/sdk/src/libc/src/opendir.c ================================================ #include #include #include DIR* opendir( const char* name ) { DIR* dir; dir = ( DIR* )malloc( sizeof( DIR ) ); if ( dir == NULL ) { return NULL; } dir->fd = open( name, O_RDONLY ); if ( dir->fd < 0 ) { free( dir ); return NULL; } return dir; } ================================================ FILE: src/sdk/src/libc/src/os/debug.c ================================================ #include ================================================ FILE: src/sdk/src/libc/src/os/ipc.c ================================================ #include ================================================ FILE: src/sdk/src/libc/src/os/module.c ================================================ #include ================================================ FILE: src/sdk/src/libc/src/os/os.c ================================================ #include ================================================ FILE: src/sdk/src/libc/src/os/region.c ================================================ #include ================================================ FILE: src/sdk/src/libc/src/os/semaphore.c ================================================ #include ================================================ FILE: src/sdk/src/libc/src/os/syscall.c ================================================ #include int syscall0( int number ){ int ret; asm volatile (" \ mov %1, %%eax \n \ int $0x80 \n \ mov %%eax, %0" : "=g" (ret) : "g" (number) ); return ret; } int syscall1( int number, uint32_t p1 ){ int ret; asm volatile (" \ mov %1, %%eax \n \ mov %2, %%ebx \n \ int $0x80 \n \ mov %%eax, %0" : "=g" (ret) : "g" (number), "g" (p1) ); return ret; } int syscall2( int number, uint32_t p1, uint32_t p2 ){ int ret; asm volatile (" \ mov %1, %%eax \n \ mov %2, %%ebx \n \ mov %3, %%ecx \n \ int $0x80 \n \ mov %%eax, %0" : "=g" (ret) : "g" (number), "g" (p1), "g" (p2) ); return ret; } int syscall3( int number, uint32_t p1, uint32_t p2, uint32_t p3 ){ int ret; asm volatile (" \ mov %1, %%eax \n \ mov %2, %%ebx \n \ mov %3, %%ecx \n \ mov %4, %%edx \n \ int $0x80 \n \ mov %%eax, %0" : "=g" (ret) : "g" (number),"g" (p1), "g" (p2), "g" (p3) ); return ret; } int syscall4( int number, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4 ){ int ret; asm volatile (" \ mov %1, %%eax \n \ mov %2, %%ebx \n \ mov %3, %%ecx \n \ mov %4, %%edx \n \ mov %5, %%edi \n \ int $0x80 \n \ mov %%eax, %0" : "=g" (ret) : "g" (number),"g" (p1), "g" (p2), "g" (p3), "g" (p4) ); return ret; } int syscall5( int number, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5 ){ int ret; asm volatile (" \ mov %1, %%eax \n \ mov %2, %%ebx \n \ mov %3, %%ecx \n \ mov %4, %%edx \n \ mov %5, %%edi \n \ mov %6, %%esi \n \ int $0x80 \n \ mov %%eax, %0" : "=g" (ret) : "g" (number),"g" (p1), "g" (p2), "g" (p3), "g" (p4), "g" (p5) ); return ret; } ================================================ FILE: src/sdk/src/libc/src/os/sysinfo.c ================================================ #include #include ================================================ FILE: src/sdk/src/libc/src/os/thread.c ================================================ #include ================================================ FILE: src/sdk/src/libc/src/pwd/endpwent.c ================================================ #include extern int _passwd_db_position; void endpwent( void ) { _passwd_db_position = 0; } ================================================ FILE: src/sdk/src/libc/src/pwd/getpwent.c ================================================ #include typedef struct passwd_myos passwd_myos; struct passwd_myos { char name[64]; char password[64]; int uid; int gid; char gecos[64]; char dir[512]; char shell[64]; }; passwd_myos myos_pass; passwd_myos* myos_user_getN(const char* name){ int ret=syscall2(68,(uint32_t)name,(uint32_t)&myos_pass); if (ret!=0) return &myos_pass; else return NULL; } passwd_myos* myos_user_getID(int id){ int ret=syscall2(69,id,(uint32_t)&myos_pass); if (ret!=0) return &myos_pass; else return NULL; } int _passwd_db_position = 0; struct passwd __tmp_passwd; void build_tmp_passwd(){ __tmp_passwd.pw_name=myos_pass.name; __tmp_passwd.pw_passwd=myos_pass.password; __tmp_passwd.pw_uid=myos_pass.uid; __tmp_passwd.pw_gid=myos_pass.gid; __tmp_passwd.pw_gecos=myos_pass.gecos; __tmp_passwd.pw_dir=myos_pass.dir; __tmp_passwd.pw_shell=myos_pass.shell; } struct passwd* getpwent( void ) { passwd_myos* pass=myos_user_getID(_passwd_db_position); if (pass==NULL) return NULL; build_tmp_passwd(); _passwd_db_position++; return &__tmp_passwd; } ================================================ FILE: src/sdk/src/libc/src/pwd/getpwnam.c ================================================ #include typedef struct passwd_myos passwd_myos; struct passwd_myos { char name[64]; char password[64]; int uid; int gid; char gecos[64]; char dir[512]; char shell[64]; }; extern struct passwd __tmp_passwd; passwd_myos* myos_user_getN(const char* name); void build_tmp_passwd(); struct passwd* getpwnam( const char* name ) { passwd_myos* pass=myos_user_getN(name); if (pass==NULL) return NULL; build_tmp_passwd(); return &__tmp_passwd; } ================================================ FILE: src/sdk/src/libc/src/pwd/getpwuid.c ================================================ #include typedef struct passwd_myos passwd_myos; struct passwd_myos { char name[64]; char password[64]; int uid; int gid; char gecos[64]; char dir[512]; char shell[64]; }; extern struct passwd __tmp_passwd; passwd_myos* myos_user_getID(int id); struct passwd* getpwuid( uid_t uid ) { passwd_myos* pass=myos_user_getID(uid); if (pass==NULL) return NULL; build_tmp_passwd(); return &__tmp_passwd; } ================================================ FILE: src/sdk/src/libc/src/pwd/setpwent.c ================================================ #include extern int _passwd_db_position; void setpwent( void ) { _passwd_db_position = 0; } ================================================ FILE: src/sdk/src/libc/src/readdir.c ================================================ #include #include #include struct dirent* readdir( DIR* dir ) { int error; if ( dir == NULL ) { return NULL; } error = getdents( dir->fd, &dir->entry, sizeof( struct dirent ) ); if ( error == 0 ) { return NULL; } return &dir->entry; } int readdir_r( DIR* dir, struct dirent* entry, struct dirent** result ) { int error; if ( ( dir == NULL ) || ( entry == NULL ) ) { errno = -EINVAL; return -1; } error = getdents( dir->fd, entry, sizeof( struct dirent ) ); if ( error == 0 ) { *result = NULL; } else { *result = entry; } return 0; } ================================================ FILE: src/sdk/src/libc/src/rewinddir.c ================================================ #include #include #include void rewinddir( DIR* dirp ) { int error; error = syscall1( SYS_rewinddir, dirp->fd ); if ( error < 0 ) { errno = -error; } } ================================================ FILE: src/sdk/src/libc/src/signal/kill.c ================================================ #include #include #include int kill( pid_t pid, int signal ) { int error; error = syscall2( SYS_kill, pid, signal ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/signal/killpg.c ================================================ #include int killpg( int pgrp, int signal ) { return -1; } ================================================ FILE: src/sdk/src/libc/src/signal/raise.c ================================================ #include int raise( int signal ) { printf( "raise(): Not yet implemented!\n" ); return -1; } ================================================ FILE: src/sdk/src/libc/src/signal/sigaction.c ================================================ #include #include #include int sigaction( int signum, const struct sigaction* act, struct sigaction* oldact ) { int error; error = syscall3( SYS_sigaction, signum, ( int )act, ( int )oldact ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/signal/sigaddset.c ================================================ #include #include int sigaddset( sigset_t* set, int signum ) { if ( ( set == NULL ) || ( signum < 1 ) || ( signum >= _NSIG ) ) { errno = -EINVAL; return -1; } *set |= ( 1ULL << ( signum - 1 ) ); return 0; } ================================================ FILE: src/sdk/src/libc/src/signal/sigdelset.c ================================================ #include #include int sigdelset( sigset_t* set, int signum ) { if ( ( set == NULL ) || ( signum < 1 ) || ( signum >= _NSIG ) ) { errno = -EINVAL; return -1; } *set &= ~( 1ULL << ( signum - 1 ) ); return 0; } ================================================ FILE: src/sdk/src/libc/src/signal/sigemptyset.c ================================================ #include #include int sigemptyset( sigset_t* set ) { if ( set == NULL ) { errno = -EINVAL; return -1; } *set = 0; return 0; } ================================================ FILE: src/sdk/src/libc/src/signal/sigfillset.c ================================================ #include #include #include int sigfillset( sigset_t* set ) { if ( set == NULL ) { errno = -EINVAL; return -1; } memset( ( void* )set, 0xFF, sizeof( sigset_t ) ); return 0; } ================================================ FILE: src/sdk/src/libc/src/signal/sigismember.c ================================================ #include #include int sigismember( const sigset_t* set, int signum ) { if ( ( set == NULL ) || ( signum < 1 ) || ( signum >= _NSIG ) ) { errno = -EINVAL; return -1; } if ( ( ( *set ) & ( 1ULL << ( signum - 1 ) ) ) != 0 ) { return 1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/signal/signal.c ================================================ #include #include sighandler_t signal( int signum, sighandler_t handler ) { int error; struct sigaction act; struct sigaction oldact; if ( ( handler == SIG_ERR ) || ( signum < 0 ) || ( signum >= _NSIG ) ) { errno = -EINVAL; return SIG_ERR; } act.sa_handler = handler; error = sigemptyset( &act.sa_mask ); if ( error < 0 ) { return SIG_ERR; } error = sigaddset( &act.sa_mask, signum ); if ( error < 0 ) { return SIG_ERR; } act.sa_flags = SA_RESTART; if ( sigaction( signum, &act, &oldact ) < 0 ) { return SIG_ERR; } return oldact.sa_handler; } ================================================ FILE: src/sdk/src/libc/src/signal/sigprocmask.c ================================================ #include #include #include int sigprocmask( int how, const sigset_t* set, sigset_t* oldset ) { int error; error = syscall3( SYS_sigprocmask, how, ( int )set, ( int )oldset ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sscanf.c ================================================ /** * MyOS * Copyright (C) 2010 - 2011 Samy Pess * * 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 3 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 . **/ #include #include #include #include /** * simple_strtoul - convert a string to an unsigned long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) { unsigned long result = 0,value; if (!base) { base = 10; if (*cp == '0') { base = 8; cp++; if ((*cp == 'x') && isxdigit(cp[1])) { cp++; base = 16; } } } while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { result = result*base + value; cp++; } if (endp) *endp = (char *)cp; return result; } /** * simple_strtol - convert a string to a signed long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ long simple_strtol(const char *cp,char **endp,unsigned int base) { if(*cp=='-') return -simple_strtoul(cp+1,endp,base); return simple_strtoul(cp,endp,base); } /** * simple_strtoull - convert a string to an unsigned long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) { unsigned long long result = 0,value; if (!base) { base = 10; if (*cp == '0') { base = 8; cp++; if ((*cp == 'x') && isxdigit(cp[1])) { cp++; base = 16; } } } while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) ? toupper(*cp) : *cp)-'A'+10) < base) { result = result*base + value; cp++; } if (endp) *endp = (char *)cp; return result; } /** * simple_strtoll - convert a string to a signed long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ long long simple_strtoll(const char *cp,char **endp,unsigned int base) { if(*cp=='-') return -simple_strtoull(cp+1,endp,base); return simple_strtoull(cp,endp,base); } static int skip_atoi(const char **s) { int i=0; while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; return i; } /** * vsscanf - Unformat a buffer into a list of arguments * @buf: input buffer * @fmt: format of buffer * @args: arguments */ int vsscanf(const char * buf, const char * fmt, va_list args) { const char *str = buf; char *next; char digit; int num = 0; int qualifier; int base; int field_width; int is_sign = 0; while(*fmt && *str) { /* skip any white space in format */ /* white space in format matchs any amount of * white space, including none, in the input. */ if (isspace(*fmt)) { while (isspace(*fmt)) ++fmt; while (isspace(*str)) ++str; } /* anything that is not a conversion must match exactly */ if (*fmt != '%' && *fmt) { if (*fmt++ != *str++) break; continue; } if (!*fmt) break; ++fmt; /* skip this conversion. * advance both strings to next white space */ if (*fmt == '*') { while (!isspace(*fmt) && *fmt) fmt++; while (!isspace(*str) && *str) str++; continue; } /* get field width */ field_width = -1; if (isdigit(*fmt)) field_width = skip_atoi(&fmt); /* get conversion qualifier */ qualifier = -1; if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z' || *fmt == 'z') { qualifier = *fmt; fmt++; } base = 10; is_sign = 0; if (!*fmt || !*str) break; switch(*fmt++) { case 'c': { char *s = (char *) va_arg(args,char*); if (field_width == -1) field_width = 1; do { *s++ = *str++; } while (--field_width > 0 && *str); num++; } continue; case 's': { char *s = (char *) va_arg(args, char *); if(field_width == -1) field_width = sizeof(int); /* first, skip leading white space in buffer */ while (isspace(*str)) str++; /* now copy until next white space */ while (*str && !isspace(*str) && field_width--) { *s++ = *str++; } *s = '\0'; num++; } continue; case 'n': /* return number of characters read so far */ { int *i = (int *)va_arg(args,int*); *i = str - buf; } continue; case 'o': base = 8; break; case 'x': case 'X': base = 16; break; case 'i': base = 0; case 'd': is_sign = 1; case 'u': break; case '%': /* looking for '%' in str */ if (*str++ != '%') return num; continue; default: /* invalid format; stop here */ return num; } /* have some sort of integer conversion. * first, skip white space in buffer. */ while (isspace(*str)) str++; digit = *str; if (is_sign && digit == '-') digit = *(str + 1); if (!digit || (base == 16 && !isxdigit(digit)) || (base == 10 && !isdigit(digit)) || (base == 8 && (!isdigit(digit) || digit > '7')) || (base == 0 && !isdigit(digit))) break; switch(qualifier) { case 'h': if (is_sign) { short *s = (short *) va_arg(args,short *); *s = (short) simple_strtol(str,&next,base); } else { unsigned short *s = (unsigned short *) va_arg(args, unsigned short *); *s = (unsigned short) simple_strtoul(str, &next, base); } break; case 'l': if (is_sign) { long *l = (long *) va_arg(args,long *); *l = simple_strtol(str,&next,base); } else { unsigned long *l = (unsigned long*) va_arg(args,unsigned long*); *l = simple_strtoul(str,&next,base); } break; case 'L': if (is_sign) { long long *l = (long long*) va_arg(args,long long *); *l = simple_strtoll(str,&next,base); } else { unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*); *l = simple_strtoull(str,&next,base); } break; case 'Z': case 'z': { size_t *s = (size_t*) va_arg(args,size_t*); *s = (size_t) simple_strtoul(str,&next,base); } break; default: if (is_sign) { int *i = (int *) va_arg(args, int*); *i = (int) simple_strtol(str,&next,base); } else { unsigned int *i = (unsigned int*) va_arg(args, unsigned int*); *i = (unsigned int) simple_strtoul(str,&next,base); } break; } num++; if (!next) break; str = next; } return num; } /** * sscanf - Unformat a buffer into a list of arguments * @buf: input buffer * @fmt: formatting of buffer * @...: resulting arguments */ int sscanf(const char * buf, const char * fmt, ...) { va_list args; int i; va_start(args,fmt); i = vsscanf(buf,fmt,args); va_end(args); return i; } int fscanf(FILE*stream,const char * fmt, ...){ char*buf; buf=fgets(buf,512,stream); va_list args; int i; va_start(args,fmt); i = vsscanf(buf,fmt,args); va_end(args); return i; } int scanf(const char * fmt, ...){ char*buf; buf=fgets(buf,512,stdin); va_list args; int i; va_start(args,fmt); i = vsscanf(buf,fmt,args); va_end(args); return i; } ================================================ FILE: src/sdk/src/libc/src/start.c ================================================ #include #include #include #include #define MAX_ENV_COUNT 256 int main(int argc, char *argv []); int errno; char** environ={ "PATH","/bin/", NULL,NULL }; int __environ_allocated; void _start(int argc, char** argv) { stdout=fdopen(0,"rw"); stdin=fdopen(1,"rw"); stderr=fdopen(2,"rw"); int error; environ = 0; __environ_allocated = 0; /* Call the main function of the application */ error = main( argc, argv); /* Exit the process */ exit( error ); } ================================================ FILE: src/sdk/src/libc/src/stdio/clearerr.c ================================================ #include void clearerr( FILE* stream ) { stream->flags &= ~( __FILE_EOF | __FILE_ERROR ); } ================================================ FILE: src/sdk/src/libc/src/stdio/fclose.c ================================================ #include #include #include int fclose( FILE* stream ) { int result; result = fflush( stream ); result |= close( stream->fd ); if ( ( ( stream->flags & __FILE_DONTFREEBUF ) == 0 ) && ( stream->buffer != NULL ) ) { free( stream->buffer ); } free( stream ); return result; } ================================================ FILE: src/sdk/src/libc/src/stdio/fdopen.c ================================================ #include #include int __parse_mode( const char* mode ); FILE* __init_file( int fd, int close_on_error, int mode ); FILE* fdopen( int fd, const char* mode ) { int flags; if ( fd < 0 ) { errno = -EINVAL; return NULL; } flags = __parse_mode( mode ); return __init_file( fd, 0, flags ); } ================================================ FILE: src/sdk/src/libc/src/stdio/feof.c ================================================ #include int feof( FILE* stream ) { if ( stream->has_ungotten ) { return 0; } return ( stream->flags & __FILE_EOF ); } ================================================ FILE: src/sdk/src/libc/src/stdio/ferror.c ================================================ #include int ferror( FILE* stream ) { return ( stream->flags & __FILE_ERROR ); } ================================================ FILE: src/sdk/src/libc/src/stdio/fflush.c ================================================ #include #include int fflush( FILE* stream ) { if ( stream->flags & __FILE_BUFINPUT ) { int tmp; tmp = ( int )stream->buffer_pos - ( int )stream->buffer_data_size; if ( tmp != 0 ) { lseek( stream->fd, tmp, SEEK_CUR ); } stream->buffer_pos = 0; stream->buffer_data_size = 0; } else { if ( stream->buffer_pos > 0 ) { if ( write( stream->fd, stream->buffer, stream->buffer_pos ) != stream->buffer_pos ) { write(0,"\nerror file \n",strlen("\nerror file \n")); stream->flags |= __FILE_ERROR; return -1; } memset(stream->buffer,0,_IO_BUFSIZE); stream->buffer_pos = 0; } } return 0; } ================================================ FILE: src/sdk/src/libc/src/stdio/fgetc.c ================================================ #include #include #include "stdio_internal.h" int fgetc( FILE* stream ) { unsigned char c; /* Check if we can read from the stream */ if ( ( ( stream->flags & __FILE_CAN_READ ) == 0 ) || ( __set_stream_flags( stream, __FILE_BUFINPUT ) ) ) { stream->flags |= __FILE_ERROR; printf("EOF ! \n"); return EOF; } /* Check the unget buffer */ if ( stream->has_ungotten ) { stream->has_ungotten = 0; printf("un get ! \n"); return stream->unget_buffer; } /* Check the end of the file */ if ( feof( stream ) ) { printf("EOF ! \n"); return EOF; } /* Fill the buffer if it's empty */ if ( stream->buffer_pos >= stream->buffer_data_size ) { ssize_t length; length = read( stream->fd, stream->buffer, stream->buffer_size ); if ( length == 0 ) { stream->flags |= __FILE_EOF; printf("EOF ! \n"); return EOF; } else if ( length < 0 ) { stream->flags |= __FILE_ERROR; printf("EOF ! \n"); return EOF; } stream->buffer_pos = 0; stream->buffer_data_size = length; } /* Get one character from the buffer */ c = stream->buffer[ stream->buffer_pos ]; stream->buffer_pos++; return c; } ================================================ FILE: src/sdk/src/libc/src/stdio/fgets.c ================================================ #include char* fgets( char* s, int size, FILE* stream ) { char* orig = s; int l; for ( l = size; l > 1; ) { register int c = fgetc( stream ); //printf("c: %c \n"); if ( c == EOF ) { break; } *s = c; ++s; --l; if ( c == '\n' ) { break; } } if ( ( l == size ) || ( ferror( stream ) ) ) { return 0; } *s = 0; return orig; } ================================================ FILE: src/sdk/src/libc/src/stdio/fileno.c ================================================ #include int fileno( FILE* stream ) { return stream->fd; } ================================================ FILE: src/sdk/src/libc/src/stdio/fopen.c ================================================ #include #include #include #include int __parse_mode( const char* mode ) { int mode_flags = 0; for ( ;; ) { switch ( *mode ) { case 0 : return mode_flags; case 'b': break; case 'r': mode_flags = O_RDONLY; break; case 'w': mode_flags = O_WRONLY | O_CREAT | O_TRUNC; break; case 'a': mode_flags = O_WRONLY | O_CREAT | O_APPEND; break; case '+': mode_flags = ( mode_flags & ( ~O_WRONLY ) ) | O_RDWR; break; default : break; } ++mode; } } FILE* __init_file( int fd, int close_on_error, int mode ) { FILE* stream; stream = ( FILE* )malloc( sizeof( FILE ) ); if ( stream == NULL ) { if ( close_on_error ) { close( fd ); } return NULL; } stream->buffer = ( char* )malloc( _IO_BUFSIZE ); if ( stream->buffer == NULL ) { free( stream ); if ( close_on_error ) { close( fd ); } return NULL; } stream->fd = fd; stream->flags = 0; stream->buffer_pos = 0; stream->buffer_size = _IO_BUFSIZE; stream->buffer_data_size = 0; switch ( mode & O_RDWR ) { case O_RDWR : stream->flags |= ( __FILE_CAN_WRITE | __FILE_CAN_READ ); break; case O_RDONLY : stream->flags |= __FILE_CAN_READ; break; case O_WRONLY : stream->flags |= __FILE_CAN_WRITE; break; default : break; } stream->has_ungotten = 0; return stream; } FILE* fopen( const char* path, const char* mode ) { int fd; int flags; flags = __parse_mode( mode ); fd = open( path, flags, 0666 ); if ( fd < 0 ) { return NULL; } return __init_file( fd, 1, flags ); } ================================================ FILE: src/sdk/src/libc/src/stdio/fpurge.c ================================================ #include int fpurge( FILE* stream ) { if ( stream->flags & __FILE_NOBUF ) { return 0; } stream->has_ungotten = 0; if ( stream->flags & __FILE_BUFINPUT ) { stream->buffer_pos = stream->buffer_data_size; } else { stream->buffer_pos = 0; } return 0; } ================================================ FILE: src/sdk/src/libc/src/stdio/fputc.c ================================================ #include #include #include "stdio_internal.h" int fputc( int c, FILE* stream ) { /* Check if we can write to the stream */ if ( ( ( stream->flags & __FILE_CAN_WRITE ) == 0 ) || ( __set_stream_flags( stream, 0 ) ) ) { stream->flags |= __FILE_ERROR; return EOF; } /* Make sure we have free space in the buffer */ if ( stream->buffer_pos >= stream->buffer_size - 1 ) { if ( fflush( stream ) ) { stream->flags |= __FILE_ERROR; return EOF; } } if ( stream->flags & __FILE_NOBUF ) { if ( write( stream->fd, &c, 1 ) != 1 ) { stream->flags |= __FILE_ERROR; return EOF; } return 0; } stream->buffer[ stream->buffer_pos++ ] = c; if ( ( ( stream->flags & __FILE_BUFLINEWISE ) && ( c == '\n' ) ) || ( stream->flags & __FILE_NOBUF ) ) { if ( fflush( stream ) ) { stream->flags |= __FILE_ERROR; return EOF; } } return 0; } ================================================ FILE: src/sdk/src/libc/src/stdio/fputs.c ================================================ #include #include int fputs( const char* s, FILE* stream ) { while ( *s ) { fputc( *s++, stream ); } fflush( stream ); return 0; } ================================================ FILE: src/sdk/src/libc/src/stdio/fread.c ================================================ #include #include #include size_t fread( void* ptr, size_t size, size_t nmemb, FILE* stream ) { int res; unsigned long i, j; j = size * nmemb; i = 0; if ( ( stream->flags & __FILE_CAN_READ ) == 0 ) { stream->flags |= __FILE_ERROR; return 0; } if ( ( j == 0 ) || ( ( j / nmemb ) != size ) ) { return 0; } if ( stream->has_ungotten ) { stream->has_ungotten = 0; *( char* )ptr = stream->unget_buffer; ++i; if ( j == 1 ) { return 1; } } for ( ; i < j; ++i ) { res = fgetc( stream ); if ( res == EOF ) { return i / size; } else { ( ( unsigned char* )ptr )[ i ] = ( unsigned char )res; } } return nmemb; } ================================================ FILE: src/sdk/src/libc/src/stdio/freopen.c ================================================ #include #include #include #include int __parse_mode( const char* mode ); FILE* freopen( const char* path, const char* mode, FILE* stream ) { int flags; if ( stream == NULL ) { errno = -EINVAL; return NULL; } flags = __parse_mode( mode ); fflush( stream ); close( stream->fd ); stream->fd = open( path, flags, 0666 ); if ( stream->fd != -1 ) { stream->flags = 0; switch ( flags & 3 ) { case O_RDWR : stream->flags |= ( __FILE_CAN_READ | __FILE_CAN_WRITE ); break; case O_RDONLY : stream->flags |= __FILE_CAN_READ; break; case O_WRONLY : stream->flags |= __FILE_CAN_WRITE; break; } } return stream; } ================================================ FILE: src/sdk/src/libc/src/stdio/fseek.c ================================================ #include #include int fseeko( FILE* stream, off_t offset, int whence ) { fflush( stream ); stream->buffer_pos = 0; stream->buffer_data_size = 0; stream->flags &= ~( __FILE_EOF | __FILE_ERROR ); stream->has_ungotten = 0; return ( lseek( stream->fd, offset, whence ) != -1 ? 0 : -1 ); } int fseek( FILE* stream, long offset, int whence ) { return fseeko( stream, ( off_t )offset, whence ); } ================================================ FILE: src/sdk/src/libc/src/stdio/ftell.c ================================================ #include #include #include #include off_t ftello( FILE* stream ) { off_t l; if ( stream->flags & ( __FILE_EOF | __FILE_ERROR ) ) { return -1; } l = lseek( stream->fd, 0, SEEK_CUR ); if ( l == ( off_t )-1 ) { return -1; } if ( stream->flags & __FILE_BUFINPUT ) { return l - ( stream->buffer_data_size - stream->buffer_pos ) - stream->has_ungotten; } else { return l + stream->buffer_pos; } } long ftell( FILE* stream ) { off_t l; l = ftello( stream ); if ( l > LONG_MAX ) { errno = EOVERFLOW; return -1; } return ( long )l; } ================================================ FILE: src/sdk/src/libc/src/stdio/fwrite.c ================================================ #include #include #include #include size_t fwrite( const void* ptr, size_t size, size_t nmemb, FILE* stream ) { ssize_t res; unsigned long len=size * nmemb; long i; if ( ( stream->flags & __FILE_CAN_WRITE ) == 0 ) { stream->flags |= __FILE_ERROR; return 0; } if ( ( nmemb == 0 ) || ( ( len / nmemb ) != size ) ) { return 0; } if ( ( len > stream->buffer_size ) || ( stream->flags & __FILE_NOBUF ) ) { if ( fflush( stream ) ) { return 0; } res = write( stream->fd, ptr, len ); } else { register const unsigned char* c = ptr; for ( i = len; i > 0; --i, ++c ) { if ( fputc( *c, stream ) ) { res = len - i; goto abort; } } res = len; } if ( res < 0 ) { stream->flags |= __FILE_ERROR; return 0; } abort: return size ? res / size : 0; } ================================================ FILE: src/sdk/src/libc/src/stdio/getc.c ================================================ #include int getc( FILE* stream ) { return fgetc( stream ); } int gets(char* buf){ fgets(buf,512,stdin); return 1; } ================================================ FILE: src/sdk/src/libc/src/stdio/perror.c ================================================ #include #include #include void perror( const char* s ) { if ( s != NULL ) { fprintf( stderr, "%s", s ); } fprintf( stderr, ": %s\n", strerror( errno ) ); } ================================================ FILE: src/sdk/src/libc/src/stdio/putc.c ================================================ #include #include #include int putc( int c, FILE* stream ) { return fputc( c, stream ); } int support_vfprintf(FILE* stream, const char* format, va_list ap); int vfprintf(FILE* stream, const char* format, va_list arg) { return support_vfprintf( stream, format, arg ); } int printf(const char* format, ...) { int rc; va_list ap; va_start(ap, format); rc = vfprintf( stdout, format, ap ); va_end(ap); return rc; } int fprintf(FILE*stream,const char* format, ...) { int rc; va_list ap; va_start(ap, format); rc = vfprintf(stream, format, ap ); va_end(ap); return rc; } ================================================ FILE: src/sdk/src/libc/src/stdio/putchar.c ================================================ #include int putchar( int c ) { return fputc( c, stdout ); } ================================================ FILE: src/sdk/src/libc/src/stdio/puts.c ================================================ #include int puts( const char* s ) { printf("%s\n", s ); //fflush( stdout ); return 0; } ================================================ FILE: src/sdk/src/libc/src/stdio/remove.c ================================================ #include #include #include #include int remove( const char* path ) { struct stat st; if ( stat( path, &st) != 0 ) { return -1; } if ( S_ISDIR( st.st_mode ) ) { return rmdir( path ); } else { return unlink( path ); } } ================================================ FILE: src/sdk/src/libc/src/stdio/rename.c ================================================ #include #include int rename( const char* oldpath, const char* newpath ) { printf( "TODO: rename not yet implemented! (from: %s to: %s)\n", oldpath, newpath ); errno = -ENOSYS; return -1; } ================================================ FILE: src/sdk/src/libc/src/stdio/rewind.c ================================================ #include void rewind( FILE* stream ) { clearerr( stream ); fseek( stream, 0L, SEEK_SET ); } ================================================ FILE: src/sdk/src/libc/src/stdio/setvbuf.c ================================================ #include #include #include #include static int set_flags( FILE* stream, int flags ) { switch ( flags ) { case _IONBF : stream->flags = ( stream->flags & ~( __FILE_BUFLINEWISE ) ) | __FILE_NOBUF; return 0; case _IOLBF : stream->flags = ( stream->flags & ~( __FILE_NOBUF ) ) | __FILE_BUFLINEWISE; return 0; case _IOFBF : stream->flags = stream->flags & ~( __FILE_NOBUF | __FILE_BUFLINEWISE ); return 0; default : return -1; } } int setvbuf( FILE* stream, char* buf, int flags, size_t size ) { if ( buf != NULL ) { if ( ( stream->flags & __FILE_DONTFREEBUF ) == 0 ) { free( stream->buffer ); } stream->buffer = buf; stream->flags |= __FILE_DONTFREEBUF; } else { char *tmp; if ( size == 0 ) { return set_flags( stream, flags ); } tmp = ( char* )malloc( size ); if ( tmp == NULL ) { return -1; } if ( ( stream->flags & __FILE_DONTFREEBUF ) == 0 ) { free( stream->buffer ); } stream->buffer = tmp; stream->flags &= ~__FILE_DONTFREEBUF; } stream->buffer_size = size; stream->buffer_pos = 0; stream->buffer_data_size = 0; return set_flags( stream, flags ); } ================================================ FILE: src/sdk/src/libc/src/stdio/stdio_internal.c ================================================ #include #include "stdio_internal.h" int __set_stream_flags( FILE* stream, int new_flags ) { if ( ( stream->flags & __FILE_BUFINPUT ) != new_flags) { int error; error = fflush( stream ); stream->flags = ( stream->flags & ~__FILE_BUFINPUT ) | new_flags; return error; } return 0; } ================================================ FILE: src/sdk/src/libc/src/stdio/stdio_internal.h ================================================ #ifndef _STDIO_INTERNAL_H_ #define _STDIO_INTERNAL_H_ int __set_stream_flags( FILE* stream, int new_flags ); #endif /* _STDIO_INTERNAL_H_ */ ================================================ FILE: src/sdk/src/libc/src/stdio/streams.c ================================================ #include static char __stdin_buffer[ _IO_BUFSIZE ]; static char __stdout_buffer[ _IO_BUFSIZE ]; static char __stderr_buffer[ _IO_BUFSIZE ]; static FILE _stdin = { .fd = 0, .flags = __FILE_CAN_READ | __FILE_DONTFREEBUF | __FILE_BUFLINEWISE | __FILE_BUFINPUT, .buffer = __stdin_buffer, .buffer_pos = 0, .buffer_size = _IO_BUFSIZE, .buffer_data_size = 0, .has_ungotten = 0, .unget_buffer = -1 }; static FILE _stdout = { .fd = 1, .flags = __FILE_CAN_WRITE | __FILE_BUFLINEWISE | __FILE_DONTFREEBUF, .buffer = __stdout_buffer, .buffer_pos = 0, .buffer_size = _IO_BUFSIZE, .buffer_data_size = 0, .has_ungotten = 0, .unget_buffer = -1 }; static FILE _stderr = { .fd = 2, .flags = __FILE_CAN_WRITE | __FILE_DONTFREEBUF | __FILE_NOBUF, .buffer = __stderr_buffer, .buffer_pos = 0, .buffer_size = _IO_BUFSIZE, .buffer_data_size = 0, .has_ungotten = 0, .unget_buffer = -1 }; FILE* stdin = &_stdin; FILE* stdout = &_stdout; FILE* stderr = &_stderr; ================================================ FILE: src/sdk/src/libc/src/stdio/support_bufio.c ================================================ #include /* * This file not a part of the standard C99 library but * I'm keeping the helper functions for printf and * sprintf here. * * So this file consists of formatting and printing (to * screen and to a buffer) of strings and numbers. * */ // ---------------- LENGTH OF NUMBERS AND STRINGS --- int bufcon_leni(int num) { int p; int sign; if ( num < 0 ) { p = -num; sign = 1; } else { p = num; sign = 0; } if ( p < 10 ) return sign + 1; if ( p < 100 ) return sign + 2; if ( p < 1000 ) return sign + 3; if ( p < 10000 ) return sign + 4; if ( p < 100000 ) return sign + 5; if ( p < 1000000 ) return sign + 6; if ( p < 10000000 ) return sign + 7; if ( p < 100000000 ) return sign + 8; if ( p < 1000000000 ) return sign + 9; return 10; } int bufcon_lenui(unsigned int p) { if ( p < 10 ) return 1; if ( p < 100 ) return 2; if ( p < 1000 ) return 3; if ( p < 10000 ) return 4; if ( p < 100000 ) return 5; if ( p < 1000000 ) return 6; if ( p < 10000000 ) return 7; if ( p < 100000000 ) return 8; if ( p < 1000000000 ) return 9; return 10; } int bufcon_lenp(unsigned int p) { if ( p < 0x10 ) return 1; if ( p < 0x100 ) return 2; if ( p < 0x1000 ) return 3; if ( p < 0x10000 ) return 4; if ( p < 0x100000 ) return 5; if ( p < 0x1000000 ) return 6; if ( p < 0x10000000 ) return 7; return 8; } int bufcon_lenx( unsigned int p ) { return (bufcon_lenp( p ) + 2); } int bufcon_lens( char *s ) { int i = 0; while ( s[i] != 0 ) i++; return i; } // ---------------- BUFFER MANIPULATION ------------- char* bufcon_putc( char *buffer, unsigned char c ) { unsigned char str[2]; str[0] = c; str[1] = 0; strcat( buffer,(const char*)str ); return buffer; } char* bufcon_puts( char *buffer, char *str ) { strcat( buffer, str ); return buffer; } char* bufcon_puti( char *buffer, int num ) { unsigned int divisor; unsigned int current; unsigned int remainder; unsigned int found; if ( num < 0 ) { bufcon_putc( buffer, '-' ); current = -num; } else current = num; divisor = 1000000000; found = 0; while (divisor > 0) { remainder = current % divisor; current = current / divisor; if ( current != 0 ) found = 1; if ( found != 0 ) bufcon_putc( buffer, current + '0' ); divisor = divisor / 10; current = remainder; } if ( found == 0 ) bufcon_putc( buffer, current + '0' ); return buffer; } char* bufcon_putui( char *buffer, unsigned int num ) { unsigned int divisor; unsigned int current; unsigned int remainder; unsigned int found; current = num; divisor = 1000000000; found = 0; while (divisor > 0) { remainder = current % divisor; current = current / divisor; if ( current != 0 ) found = 1; if ( found != 0 ) bufcon_putc( buffer, current + '0' ); divisor = divisor / 10; current = remainder; } if ( found == 0 ) bufcon_putc( buffer, current + '0' ); return buffer; } char* bufcon_putp( char *buffer, unsigned int p ) { int offset; unsigned char c; int found = 0; for ( offset = 28; offset >= 0; offset -= 4 ) { c = (p>>offset) & 0xF; if ( c != 0 ) found = 1; if ( found == 1 ) { if ( c < 10 ) bufcon_putc( buffer, c + '0' ); else bufcon_putc( buffer, c - 10 + 'a' ); } } if (found == 0 ) bufcon_putc( buffer, '0' ); return buffer; } char* bufcon_putx( char *buffer, unsigned int p ) { int offset; unsigned char c; int found = 0; bufcon_puts( buffer, "0x" ); for ( offset = 28; offset >= 0; offset -= 4 ) { c = (p>>offset) & 0xF; if ( c != 0 ) found = 1; if ( found == 1 ) { if ( c < 10 ) bufcon_putc( buffer, c + '0' ); else bufcon_putc( buffer, c - 10 + 'a' ); } } if (found == 0 ) bufcon_putc( buffer, '0' ); return buffer; } char* bufcon_putX( char *buffer, unsigned int p ) { int offset; unsigned char c; int found = 0; bufcon_puts( buffer, "0x" ); for ( offset = 28; offset >= 0; offset -= 4 ) { c = (p>>offset) & 0xF; if ( c != 0 ) found = 1; if ( found == 1 ) { if ( c < 10 ) bufcon_putc( buffer, c + '0' ); else bufcon_putc( buffer, c - 10 + 'A' ); } } if (found == 0 ) bufcon_putc( buffer, '0' ); return buffer; } ================================================ FILE: src/sdk/src/libc/src/stdio/support_pf.c ================================================ #include #include #include int bufcon_leni(int num); int bufcon_lenui(unsigned int p); int bufcon_lenp(unsigned int p); int bufcon_lenx( unsigned int p ); int bufcon_lens( char *s ); char* bufcon_putc( char *buffer, unsigned char c ); char* bufcon_puts( char *buffer, char *str ); char* bufcon_puti( char *buffer, int num ); char* bufcon_putui( char *buffer, unsigned int num ); char* bufcon_putp( char *buffer, unsigned int p ); char* bufcon_putx( char *buffer, unsigned int p ); char* bufcon_putX( char *buffer, unsigned int p ); void supcon_putX( unsigned int num ); void supcon_putx( unsigned int num ); void supcon_putp( unsigned int num, char offset ); void supcon_putui( unsigned int num ); void supcon_puti( int num ); void supcon_putc( unsigned char c ); void supcon_puts( unsigned char *c ); int supcon_lenx( unsigned int p ); int supcon_lenp(unsigned int p); int supcon_lenui(unsigned int p); int supcon_leni(int num); int printf_buffer(int i) { int j; if ( i <= 0 ) return 0; for ( j = 0; j < i; j++) supcon_putc(' '); return 0; } #define STATE_OFF 0 #define STATE_PAD 1 int support_vfprintf(FILE* stream, const char* format, va_list ap) { int d, i; int index; char c, *s; int modifier; int state; int off_length; int pad_length; modifier = 0; state = STATE_OFF; off_length = 0; pad_length = 0; while (*format) { switch(*format++) { case 's': if (modifier == 0) { supcon_putc(*(format-1)); break; } s = va_arg(ap, char*); printf_buffer( off_length - strlen(s) ); supcon_puts((unsigned char*)s); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'd': case 'i': if (modifier == 0) { supcon_putc(*(format-1)); break; } i = va_arg(ap, int); printf_buffer( off_length - supcon_leni(i) - pad_length ); for ( index = 0; index < pad_length - supcon_leni(i); index++) supcon_putc( '0' ); supcon_puti(i); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'u': if (modifier == 0) { supcon_putc(*(format-1)); break; } i = va_arg(ap, int); printf_buffer( off_length - supcon_lenui(i) - pad_length ); for ( index = 0; index < pad_length - supcon_lenui(i); index++) supcon_putc( '0' ); supcon_putui(i); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'p': if (modifier == 0) { supcon_putc(*(format-1)); break; } d = va_arg(ap, int); printf_buffer( off_length - supcon_lenp(d) - pad_length ); for ( index = 0; index < pad_length - supcon_lenp(d); index++ ) supcon_putc( '0' ); supcon_putp(d,'A'); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'x': if (modifier == 0) { supcon_putc(*(format-1)); break; } d = va_arg(ap, int); printf_buffer( off_length - supcon_lenx(d) - 2 ); supcon_puts((unsigned char*)"0x"); for ( index = 0; index < pad_length-supcon_lenx(d)-2; index++ ) supcon_putc( '0' ); supcon_putx(d); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'l': if (modifier == 0) { supcon_putc(*(format-1)); break; } break; case 'X': if (modifier == 0) { supcon_putc(*(format-1)); break; } d = va_arg(ap, int); printf_buffer( off_length - supcon_lenx(d) - 2 ); supcon_puts((unsigned char*)"0x"); for ( index = 0; index < pad_length-supcon_lenx(d)-2; index++ ) supcon_putc( '0' ); supcon_putX(d); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'c': if (modifier == 0) { supcon_putc(*(format-1)); break; } c = (char) va_arg(ap, int); printf_buffer( off_length - 1 ); supcon_putc(c); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case '%': modifier = 1; off_length = 0; pad_length = 0; state = STATE_OFF; break; case '.': if (modifier == 0) { supcon_putc(*(format-1)); break; } if ( state == STATE_PAD ) { modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; } state = STATE_PAD; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if ( modifier != 1 ) { supcon_putc( *(format-1) ); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; } if ( state == STATE_OFF ) off_length = off_length * 10 + ((*(format-1)) - '0'); if ( state == STATE_PAD ) pad_length = pad_length * 10 + ((*(format-1)) - '0'); break; default: printf_buffer( off_length - 1 ); supcon_putc( *(format-1) ); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; } } return 0; } // --------------------------------- int sprintf_buffer(char *s, int i) { int j; if ( i <= 0 ) return 0; for ( j = 0; j < i; j++) strcat(s," "); return 0; } int vsnprintf(char* str, size_t size, const char *format, va_list arg_ptr) { return support_vsprintf(str,format,arg_ptr); } int snprintf(char *str,size_t size,const char *format,...) { int n; va_list arg_ptr; va_start(arg_ptr, format); n=vsnprintf(str,size,format,arg_ptr); va_end (arg_ptr); return n; } int support_vsprintf(char* buffer, const char* format, va_list ap) { int d, i; int index; char c, *s; int modifier; int state; int off_length; int pad_length; modifier = 0; state = STATE_OFF; off_length = 0; pad_length = 0; buffer[0] = 0; while (*format) { switch(*format++) { case 's': if (modifier == 0) { bufcon_putc( buffer, *(format-1)); break; } s = va_arg(ap, char*); sprintf_buffer( buffer, off_length - strlen(s) ); bufcon_puts( buffer, s); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'd': case 'i': if (modifier == 0) { bufcon_putc( buffer, *(format-1)); break; } i = va_arg(ap, int); sprintf_buffer( buffer, off_length - supcon_leni(i) - pad_length ); for ( index = 0; index < pad_length - supcon_leni(i); index++) bufcon_putc( buffer, '0' ); bufcon_puti(buffer, i); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'u': if (modifier == 0) { bufcon_putc( buffer, *(format-1)); break; } i = va_arg(ap, int); sprintf_buffer( buffer, off_length - supcon_lenui(i) - pad_length ); for ( index = 0; index < pad_length - supcon_lenui(i); index++) bufcon_putc( buffer, '0' ); bufcon_putui( buffer, i); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'p': if (modifier == 0) { bufcon_putc( buffer, *(format-1)); break; } d = va_arg(ap, int); sprintf_buffer( buffer, off_length - supcon_lenp(d) - pad_length ); for ( index = 0; index < pad_length - supcon_lenp(d); index++ ) bufcon_putc( buffer, '0' ); bufcon_putp( buffer, d); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'l': if (modifier == 0) { supcon_putc(*(format-1)); break; } break; case 'x': if (modifier == 0) { bufcon_putc( buffer, *(format-1)); break; } d = va_arg(ap, int); sprintf_buffer( buffer, off_length - supcon_lenx(d) - 2 ); /*bufcon_puts(buffer,"0x"); for ( index = 0; index < pad_length-supcon_lenx(d)-2; index++ ) bufcon_putc( buffer, '0' );*/ bufcon_putx( buffer, d); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'X': if (modifier == 0) { bufcon_putc( buffer, *(format-1)); break; } d = va_arg(ap, int); sprintf_buffer( buffer, off_length - supcon_lenx(d) - 2 ); /*bufcon_puts(buffer,"0x"); for ( index = 0; index < pad_length-supcon_lenx(d)-2; index++ ) bufcon_putc( buffer, '0' );*/ bufcon_putX(buffer,d); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case 'c': if (modifier == 0) { bufcon_putc( buffer, *(format-1)); break; } c = (char) va_arg(ap, int); sprintf_buffer( buffer, off_length - 1 ); bufcon_putc(buffer, c); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; case '%': modifier = 1; off_length = 0; pad_length = 0; state = STATE_OFF; break; case '.': if (modifier == 0) { bufcon_putc( buffer, *(format-1)); break; } if ( state == STATE_PAD ) { modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; } state = STATE_PAD; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if ( modifier != 1 ) { bufcon_putc( buffer, *(format-1) ); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; } if ( state == STATE_OFF ) off_length = off_length * 10 + ((*(format-1)) - '0'); if ( state == STATE_PAD ) pad_length = pad_length * 10 + ((*(format-1)) - '0'); break; default: sprintf_buffer( buffer, off_length - 1 ); bufcon_putc( buffer, *(format-1) ); modifier = 0; off_length = 0; pad_length = 0; state = STATE_OFF; break; } } return 0; } ================================================ FILE: src/sdk/src/libc/src/stdio/support_supcon.c ================================================ #include #include // ---------------- LENGTH OF NUMBERS AND STRINGS --- int supcon_leni(int num) { int p; int sign; if ( num < 0 ) { p = -num; sign = 1; } else { p = num; sign = 0; } if ( p < 10 ) return sign + 1; if ( p < 100 ) return sign + 2; if ( p < 1000 ) return sign + 3; if ( p < 10000 ) return sign + 4; if ( p < 100000 ) return sign + 5; if ( p < 1000000 ) return sign + 6; if ( p < 10000000 ) return sign + 7; if ( p < 100000000 ) return sign + 8; if ( p < 1000000000 ) return sign + 9; return 10; } int supcon_lenui(unsigned int p) { if ( p < 10 ) return 1; if ( p < 100 ) return 2; if ( p < 1000 ) return 3; if ( p < 10000 ) return 4; if ( p < 100000 ) return 5; if ( p < 1000000 ) return 6; if ( p < 10000000 ) return 7; if ( p < 100000000 ) return 8; if ( p < 1000000000 ) return 9; return 10; } int supcon_lenp(unsigned int p) { if ( p < 0x10 ) return 1; if ( p < 0x100 ) return 2; if ( p < 0x1000 ) return 3; if ( p < 0x10000 ) return 4; if ( p < 0x100000 ) return 5; if ( p < 0x1000000 ) return 6; if ( p < 0x10000000 ) return 7; return 8; } int supcon_lenx( unsigned int p ) { return (supcon_lenp( p )); } // ---------------------- USEFUL STUFF --------------------------------- void supcon_puts( unsigned char *c ) { fputs((const char *)c,stdout); } void supcon_putc( unsigned char c ) { char buffer[2]; buffer[0] = c; buffer[1] = 0; fputs((const char *)buffer,stdout); } void supcon_puti( int num ) { int sign; int temp; char buffer[ 128 ]; // You're generous. int position = 126; // Short circuit unnecessary work. if ( num == 0 ) { fputs("0",stdout); return; } // Prepare to do work. if ( num < 0 ) { sign = 1; temp = -num; } else { sign = 0; temp = num; } buffer[127] = 0; // Now reduce it. while ( temp > 0 ) { buffer[ position-- ] = '0' + (temp % 10); temp = temp / 10; } if ( sign == 1 ) buffer[ position-- ] = '-'; // Now print it. fputs(buffer + position + 1 ,stdout); } void supcon_putui( unsigned int num ) { char buffer[ 128 ]; // You're generous. int position = 126; unsigned int temp = num; // Short circuit unnecessary work. if ( num == 0 ) { fputs("0",stdout); return; } buffer[127] = 0; // Now reduce it. while ( temp > 0 ) { buffer[ position-- ] = '0' + (temp % 10); temp = temp / 10; } // Now print it. fputs(buffer + position + 1 ,stdout); } void supcon_putp( unsigned int num, char offset ) { char buffer[ 128 ]; // You're generous. int position = 126; unsigned int temp = num; int value; // Short circuit unnecessary work. if ( num == 0 ) { fputs("0",stdout); return; } buffer[127] = 0; // Now reduce it. while ( temp > 0 ) { value = temp % 16; if ( value < 10 ) buffer[ position-- ] = '0' + value; else buffer[ position-- ] = offset - 10 + value; temp = temp / 16; } // Now print it. fputs(buffer + position + 1 ,stdout); } void supcon_putx( unsigned int num ) { supcon_putp( num, 'a' ); } void supcon_putX( unsigned int num ) { supcon_putp( num, 'A' ); } ================================================ FILE: src/sdk/src/libc/src/stdio/ungetc.c ================================================ #include int ungetc( int c, FILE* stream ) { if ( ( stream->has_ungotten ) || ( c < 0 ) || ( c > 255 ) ) { return EOF; } stream->has_ungotten = 1; stream->unget_buffer = ( unsigned char )c; stream->flags &= ~( __FILE_EOF | __FILE_ERROR ); return c; } ================================================ FILE: src/sdk/src/libc/src/stdlib/abort.c ================================================ #include #include #include void abort( void ) { fprintf( stderr, "Application aborted!\n" ); exit( -1 ); } ================================================ FILE: src/sdk/src/libc/src/stdlib/abs.c ================================================ #include int abs( int j ) { if ( j < 0 ) { return -j; } else { return j; } } ================================================ FILE: src/sdk/src/libc/src/stdlib/atof.c ================================================ #include double atof( const char* s ) { return strtod( s, ( char** )NULL ); } ================================================ FILE: src/sdk/src/libc/src/stdlib/atoi.c ================================================ #include #include int atoi( const char* s ) { int v = 0; int sign = 0; while ( ( *s == ' ' ) || ( ( unsigned int )( *s - 9 ) < 5u ) ) { ++s; } switch ( *s ) { case '-' : sign = -1; case '+' : ++s; } while ( ( unsigned int )( *s - '0' ) < 10u ) { v = v * 10 + *s - '0'; ++s; } return sign ? -v : v; } ================================================ FILE: src/sdk/src/libc/src/stdlib/atol.c ================================================ #include #include long atol( const char* s ) { long v = 0; int sign = 0; while ( ( *s == ' ' ) || ( ( unsigned int )( *s - 9 ) < 5u ) ) { ++s; } switch ( *s ) { case '-' : sign = -1; case '+' : ++s; } while ( ( unsigned int )( *s - '0' ) < 10u ) { v = v * 10 + *s - '0'; ++s; } return sign ? -v : v; } ================================================ FILE: src/sdk/src/libc/src/stdlib/atoll.c ================================================ #include #include long long int atoll( const char* s ) { long long int v = 0; int sign = 1; while ( *s == ' ' || ( unsigned int )( *s - 9 ) < 5u ) { ++s; } switch ( *s ) { case '-': sign = -1; case '+': ++s; } while ( ( unsigned int )( *s - '0' ) < 10u ) { v= v * 10 + *s - '0'; ++s; } return sign == -1 ? -v : v; } ================================================ FILE: src/sdk/src/libc/src/stdlib/bsearch.c ================================================ #include void* bsearch( const void* key, const void* base, size_t nmemb, size_t size, int ( *compare )( const void*, const void* ) ) { size_t m; while ( nmemb ) { int tmp; void* p; m = nmemb / 2; p = ( void* )( ( ( const char* )base ) + ( m * size ) ); if ( ( tmp = ( *compare )( key, p ) ) < 0 ) { nmemb = m; } else if ( tmp > 0 ) { base = p + size; nmemb -= m + 1; } else { return p; } } return NULL; } ================================================ FILE: src/sdk/src/libc/src/stdlib/getenv.c ================================================ #include #include extern char** environ; char* getenv( const char* name ) { return NULL; int i; size_t length; size_t name_length; name_length = strlen( name ); for ( i = 0; environ[ i ] != NULL; i++ ) { length = strlen( environ[ i ] ); if ( length < ( name_length + 1 ) ) { continue; } if ( ( strncmp( environ[ i ], name, name_length ) == 0 ) && ( environ[ i ][ name_length ] == '=' ) ) { return &environ[ i ][ name_length + 1 ]; } } return NULL; } ================================================ FILE: src/sdk/src/libc/src/stdlib/labs.c ================================================ #include long labs( long j ) { if ( j < 0 ) { return -j; } else { return j; } } ================================================ FILE: src/sdk/src/libc/src/stdlib/llabs.c ================================================ #include long long llabs( long long j ) { if ( j < 0 ) { return -j; } else { return j; } } ================================================ FILE: src/sdk/src/libc/src/stdlib/malloc.c ================================================ #include #include #define MALLOC_MINSIZE 16 #define PAGESIZE 4096 struct malloc_header { unsigned long size:31; /* taille totale de l'enregistrement */ unsigned long used:1; } __attribute__ ((packed)); extern char *b_heap; extern char *e_heap; char *b_heap = 0; /* pointe sur le debut du heap */ char *e_heap = 0; /* pointe sur le sommet du heap */ void* sbrk( int increment ); void* malloc(unsigned long size) { unsigned long realsize; /* taille totale de l'enregistrement */ unsigned long i; struct malloc_header *bl, *newbl; realsize = sizeof(struct malloc_header) + size; if ((i = realsize % MALLOC_MINSIZE)) { realsize = realsize - i + MALLOC_MINSIZE; } /* * On recherche un bloc libre de 'size' octets en parcourant tous les * blocs du heap a partir du debut */ if (b_heap == 0) { /* Initialisation du heap */ if ((b_heap = sbrk(realsize)) == (char*) -1) return (char*) -1; e_heap = b_heap + realsize;; bl = (struct malloc_header *) b_heap; bl->size = realsize; bl->used = 0; } else { bl = (struct malloc_header *) b_heap; while (bl->used || bl->size < realsize) { bl = (struct malloc_header *) ((char *) bl + bl->size); if (bl == (struct malloc_header *) e_heap) { if ((int)(e_heap = sbrk(realsize)) < 0) { return (char*) -1; } else { bl = (struct malloc_header *) e_heap; bl->size = realsize; bl->used = 0; e_heap += realsize; } } else if (bl > (struct malloc_header *) e_heap) { return (char *) -1; /* BUG ! */ } } } /* * On a trouve un bloc libre dont la taille est >= 'size' * On fait de sorte que chaque bloc ait une taille minimale */ if (bl->size - realsize < MALLOC_MINSIZE) { bl->used = 1; } else { newbl = (struct malloc_header *) ((char *) bl + realsize); newbl->size = bl->size - realsize; newbl->used = 0; bl->size = realsize; bl->used = 1; } /* retourne un pointeur sur la zone de donnees */ return (char *) bl + sizeof(struct malloc_header); } void free(void *v_addr) { struct malloc_header *bl, *nextbl; /* Calcul du debut du bloc */ bl = (struct malloc_header *) (v_addr - sizeof(struct malloc_header)); /* * On merge le bloc nouvellement libere avec le bloc suivant ci celui-ci * est aussi libre */ while ((nextbl = (struct malloc_header *) ((char *) bl + bl->size)) && nextbl < (struct malloc_header *) e_heap && nextbl->used == 0) bl->size += nextbl->size; /* On libere le bloc alloue */ bl->used = 0; } void* realloc(void* ptr,size_t nsize) { if (ptr==0){ return malloc(nsize); } else if (nsize==0) return ptr; struct malloc_header *bl=ptr-sizeof(struct malloc_header); unsigned long size=bl->size; void *newptr=malloc(size+nsize); memcpy(newptr,ptr,size); free(ptr); return newptr; } void* calloc(size_t n1,size_t n2){ return malloc(n1*n2); } ================================================ FILE: src/sdk/src/libc/src/stdlib/mkstemp.c ================================================ #include #include #include #include #include #ifndef O_NOFOLLOW #define O_NOFOLLOW 0 #endif int mkstemp( char* template ) { int i; char* tmp; int result; unsigned int rnd; tmp = template + strlen( template ) - 6; if ( tmp < template ) { errno = EINVAL; return -1; } for ( i = 0; i < 6; i++ ) { if ( tmp[ i ] != 'X' ) { errno = EINVAL; return -1; } } for ( ;; ) { for ( i = 0; i < 6; i++ ) { int hexdigit; rnd = random(); hexdigit = ( rnd >> ( i * 5 ) ) & 0x1F; tmp[ i ] = hexdigit > 9 ? ( hexdigit + 'a' - 10 ) : ( hexdigit + '0' ); } result = open( template, O_CREAT | O_RDWR | O_EXCL | O_NOFOLLOW, 0600 ); if ( ( result >= 0 ) || ( errno != EEXIST ) ) { break; } } return result; } ================================================ FILE: src/sdk/src/libc/src/stdlib/mktemp.c ================================================ #include #include #include #include char* mktemp( char* template ) { int fd; fd = mkstemp( template ); if ( fd < 0 ) { return NULL; } close( fd ); unlink( template ); return template; } ================================================ FILE: src/sdk/src/libc/src/stdlib/qsort.c ================================================ #include #include static void exch(char* base,size_t size,size_t a,size_t b) { char* x=base+a*size; char* y=base+b*size; while (size) { char z=*x; *x=*y; *y=z; --size; ++x; ++y; } } /* Quicksort with 3-way partitioning, ala Sedgewick */ /* Blame him for the scary variable names */ /* http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf */ static void quicksort(char* base,size_t size,ssize_t l,ssize_t r, int (*compar)(const void*,const void*)) { ssize_t i=l-1, j=r, p=l-1, q=r, k; char* v=base+r*size; if (r<=l) return; for (;;) { while (++i != r && compar(base+i*size,v)<0) ; while (compar(v,base+(--j)*size)<0) if (j == l) break; if (i >= j) break; exch(base,size,i,j); if (compar(base+i*size,v)==0) exch(base,size,++p,i); if (compar(v,base+j*size)==0) exch(base,size,j,--q); } exch(base,size,i,r); j = i-1; ++i; for (k=l; kq; k--, i++) exch(base,size,i,k); quicksort(base,size,l,j,compar); quicksort(base,size,i,r,compar); } void qsort(void* base,size_t nmemb,size_t size,int (*compar)(const void*,const void*)) { /* check for integer overflows */ if (nmemb >= (((size_t)-1)>>1) || size >= (((size_t)-1)>>1)) return; #if 0 if (sizeof(size_t) < sizeof(unsigned long long)) { if ((unsigned long long)size * nmemb > (size_t)-1) return; } else { if (size*nmemb/nmemb != size) return; } #endif if (nmemb>1) quicksort(base,size,0,nmemb-1,compar); } ================================================ FILE: src/sdk/src/libc/src/stdlib/rand.c ================================================ #include unsigned int _seed2 = 0xDEADBEEF; int rand( void ) { unsigned int next = _seed2; unsigned int result; next *= 1103515245; next += 12345; result = ( unsigned int ) ( next / 65536 ) % 2048; next *= 1103515245; next += 12345; result <<= 10; result ^= ( unsigned int ) ( next / 65536 ) % 1024; next *= 1103515245; next += 12345; result <<= 10; result ^= ( unsigned int ) ( next / 65536 ) % 1024; _seed2 = next; return result; } ================================================ FILE: src/sdk/src/libc/src/stdlib/random.c ================================================ unsigned int _seed = 0xDEADBEEF; long int random( void ) { unsigned int next = _seed; unsigned long int result; next *= 1103515245; next += 12345; result = ( unsigned int ) ( next / 65536 ) % 2048; next *= 1103515245; next += 12345; result <<= 10; result ^= ( unsigned int ) ( next / 65536 ) % 1024; next *= 1103515245; next += 12345; result <<= 10; result ^= ( unsigned int ) ( next / 65536 ) % 1024; _seed = next; return result; } ================================================ FILE: src/sdk/src/libc/src/stdlib/srand.c ================================================ #include extern unsigned int _seed2; void srand(unsigned int seed){ _seed2 = seed; } ================================================ FILE: src/sdk/src/libc/src/stdlib/srandom.c ================================================ #include extern unsigned int _seed; void srandom(unsigned int seed){ _seed = seed; } ================================================ FILE: src/sdk/src/libc/src/stdlib/strtod.c ================================================ #include #include #include double strtod( const char* s, char** endptr ) { register const char* p = s; register long double value = 0.L; int sign = +1; long double factor; unsigned int expo; while ( isspace(*p) ) { p++; } switch ( *p ) { case '-': sign = -1; case '+': p++; default : break; } while ( (unsigned int)(*p - '0') < 10u ) value = value*10 + (*p++ - '0'); if ( *p == '.' ) { factor = 1.; p++; while ( (unsigned int)(*p - '0') < 10u ) { factor *= 0.1; value += (*p++ - '0') * factor; } } if ( (*p | 32) == 'e' ) { expo = 0; factor = 10.L; switch (*++p) { case '-': factor = 0.1; case '+': p++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default : value = 0.L; p = s; goto done; } while ( (unsigned int)(*p - '0') < 10u ) expo = 10 * expo + (*p++ - '0'); while ( 1 ) { if ( expo & 1 ) value *= factor; if ( (expo >>= 1) == 0 ) break; factor *= factor; } } done: if ( endptr != NULL ) *endptr = (char*)p; return value * sign; } ================================================ FILE: src/sdk/src/libc/src/stdlib/strtol.c ================================================ #include #include #include #include #if __WORDSIZE == 64 #define ABS_LONG_MIN 9223372036854775808UL #else #define ABS_LONG_MIN 2147483648UL #endif long int strtol( const char* nptr, char** endptr, int base ) { int neg = 0; unsigned long int v; const char* orig = nptr; while ( isspace( *nptr ) ) { nptr++; } if ( ( *nptr == '-' ) && ( isalnum( nptr[ 1 ] ) ) ) { neg = -1; ++nptr; } v = strtoul( nptr, endptr, base ); if ( ( endptr ) && ( *endptr == nptr) ) { *endptr = ( char* )orig; } if ( v >= ABS_LONG_MIN ) { if ( ( v == ABS_LONG_MIN ) && ( neg ) ) { return v; } return ( neg ? LONG_MIN : LONG_MAX ); } return ( neg ? -v : v ); } ================================================ FILE: src/sdk/src/libc/src/stdlib/strtoll.c ================================================ #include #include #include #include #include long long int strtoll( const char* nptr, char** endptr, int base ) { int neg = 0; unsigned long long int v; const char* orig = nptr; while ( isspace( *nptr ) ) { nptr++; } if ( *nptr == '-' && isalnum( nptr[ 1 ] ) ) { neg = -1; nptr++; } v = strtoull( nptr, endptr, base ); if ( endptr && *endptr == nptr ) { *endptr = ( char* )orig; } if ( v > LLONG_MAX ) { if ( v == 0x8000000000000000ull && neg ) { errno = 0; return v; } errno=ERANGE; return ( neg ? LLONG_MIN : LLONG_MAX ); } return ( neg ? -v : v ); } intmax_t strtoimax( const char* nptr, char** endptr, int base ) __attribute__(( alias( "strtoll" ) )); ================================================ FILE: src/sdk/src/libc/src/stdlib/strtoul.c ================================================ #include #include #include #include unsigned long int strtoul( const char* ptr, char** endptr, int base ) { int neg = 0, overflow = 0; unsigned long int v=0; const char* orig; const char* nptr = ptr; while ( isspace( *nptr ) ) { ++nptr; } if ( *nptr == '-') { neg = 1; nptr++; } else if ( *nptr == '+' ) { ++nptr; } orig = nptr; if ( ( base == 16 ) && ( nptr[ 0 ] == '0' ) ) { goto skip0x; } if ( base ) { register unsigned int b = base - 2; if ( b > 34 ) { return 0; } } else { if ( *nptr == '0' ) { base = 8; skip0x: if ( ( nptr[ 1 ] == 'x' || nptr[ 1 ] == 'X' ) && isxdigit( nptr[ 2 ] ) ) { nptr += 2; base = 16; } } else { base = 10; } } while ( *nptr ) { register unsigned char c = *nptr; c = ( c >= 'a' ? c - 'a' + 10 : c >= 'A' ? c - 'A' + 10 : c <= '9' ? c - '0' : 0xFF ); if ( c >= base ) break; /* out of base */ { register unsigned long x=(v&0xff)*base+c; register unsigned long w=(v>>8)*base+(x>>8); if ( w > ( ULONG_MAX >> 8 ) ) { overflow = 1; } v = ( w << 8 ) + ( x & 0xFF ); } ++nptr; } if ( nptr == orig ) { /* no conversion done */ nptr = ptr; v = 0; } if ( endptr != NULL ) { *endptr = ( char* )nptr; } if ( overflow ) { return ULONG_MAX; } return ( neg ? -v : v ); } ================================================ FILE: src/sdk/src/libc/src/stdlib/strtoull.c ================================================ #include #include #include #include #include unsigned long long int strtoull( const char* ptr, char** endptr, int base ) { int neg = 0, overflow = 0; long long int v = 0; const char* orig; const char* nptr = ptr; while ( isspace( *nptr ) ) { ++nptr; } if ( *nptr == '-' ) { neg=1; nptr++; } else if ( *nptr == '+' ) { ++nptr; } orig = nptr; if ( ( base == 16 ) && ( nptr[ 0 ] == '0' ) ) { goto skip0x; } if ( base ) { register unsigned int b = base - 2; if ( b > 34 ) { errno = EINVAL; return 0; } } else { if ( *nptr == '0' ) { base = 8; skip0x: if ( ( ( *( nptr + 1 ) == 'x' ) || ( *( nptr + 1 ) == 'X' ) ) && isxdigit( nptr[ 2 ] ) ) { nptr += 2; base = 16; } } else { base = 10; } } while ( *nptr ) { register unsigned char c = *nptr; c = ( c >= 'a' ? c - 'a' + 10 : c >= 'A' ? c - 'A' + 10 : c <= '9' ? c - '0' : 0xFF ); if ( c >= base ) { break; /* out of base */ } { register unsigned long x = ( v & 0xFF ) * base + c; register unsigned long long w = ( v >> 8 ) * base + ( x >> 8 ); if ( w > ( ULLONG_MAX >> 8 ) ) { overflow = 1; } v = ( w << 8 ) + ( x & 0xFF ); } ++nptr; } if ( nptr == orig ) { /* no conversion done */ nptr = ptr; errno = EINVAL; v = 0; } if ( endptr != NULL ) { *endptr = (char *)nptr; } if ( overflow ) { errno = ERANGE; return ULLONG_MAX; } return ( neg ? -v : v ); } uintmax_t strtoumax( const char* nptr, char** endptr, int base ) __attribute__(( alias( "strtoull" ) )); ================================================ FILE: src/sdk/src/libc/src/string/memchr.c ================================================ #include void* memchr( const void* s, int c, size_t n ) { const unsigned char* src = ( const unsigned char* )s; unsigned char ch = c; for ( ; n != 0; n-- ) { if ( *src == ch ) { return ( void* )src; } src++; } return NULL; } ================================================ FILE: src/sdk/src/libc/src/string/memcmp.c ================================================ #include int memcmp( const void* p1, const void* p2, size_t c ) { const unsigned char* su1, *su2; signed char res = 0; for ( su1 = p1, su2 = p2; 0 < c; ++su1, ++su2, c-- ) { if ( ( res = *su1 - *su2 ) != 0 ) { break; } } return res; } ================================================ FILE: src/sdk/src/libc/src/string/memcpy.c ================================================ #include void* memcpy( void* d, const void* s, size_t n ) { char* dest; char* src; dest = ( char* )d; src = ( char* )s; while ( n-- ) { *dest++ = *src++; } return d; } ================================================ FILE: src/sdk/src/libc/src/string/memmove.c ================================================ #include void* memmove( void* dest, const void* src, size_t n ) { char* _dest; char* _src; if ( dest < src ) { _dest = ( char* )dest; _src = ( char* )src; while ( n-- ) { *_dest++ = *_src++; } } else { _dest = ( char* )dest + n; _src = ( char* )src + n; while ( n-- ) { *--_dest = *--_src; } } return dest; } ================================================ FILE: src/sdk/src/libc/src/string/memset.c ================================================ #include void* memset( void* s, int c, size_t n ) { char* _src; _src = ( char* )s; while ( n-- ) { *_src++ = c; } return s; } ================================================ FILE: src/sdk/src/libc/src/string/strcasecmp.c ================================================ #include #include int strcasecmp( const char* s1, const char* s2 ) { int result; while ( 1 ) { result = tolower( *s1 ) - tolower( *s2++ ); if ( ( result != 0 ) || ( *s1++ == 0 ) ) { break; } } return result; } ================================================ FILE: src/sdk/src/libc/src/string/strcat.c ================================================ #include char* strcat( char* d, const char* s ) { char* tmp = d; while ( *d ) d++; while ( ( *d++ = *s++ ) != 0 ) ; return tmp; } ================================================ FILE: src/sdk/src/libc/src/string/strchr.c ================================================ #include char* strchr( const char* s, int c ) { for ( ; *s != ( char )c; s++ ) { if ( *s == 0 ) { return NULL; } } return ( char* )s; } ================================================ FILE: src/sdk/src/libc/src/string/strcmp.c ================================================ #include int strcmp( const char* s1, const char* s2 ) { int result; while ( 1 ) { result = *s1 - *s2++; if ( ( result != 0 ) || ( *s1++ == 0 ) ) { break; } } return result; } ================================================ FILE: src/sdk/src/libc/src/string/strcpy.c ================================================ #include #include char* strcpy( char* d, const char* s ) { char* tmp = d; while ( ( *d++ = *s++ ) != 0 ) ; return tmp; } int support_vsprintf(char* buffer, const char* format, va_list ap); int vsprintf(char* s, const char* format, va_list arg) { return support_vsprintf( s, format, arg ); } int sprintf(char *buffer, const char* format, ...) { int rc; va_list ap; va_start(ap, format); rc = vsprintf( buffer, format, ap ); va_end(ap); return 0; } ================================================ FILE: src/sdk/src/libc/src/string/strcspn.c ================================================ #include #include size_t strcspn( const char* s, const char* reject ) { size_t l = 0; int a = 1; int i; int al = strlen( reject ); while ( ( a ) && ( *s ) ) { for ( i = 0; ( a ) && ( i < al ); i++ ) { if ( *s == reject[ i ] ) { a = 0; } } if ( a ) { l++; } s++; } return l; } ================================================ FILE: src/sdk/src/libc/src/string/strdup.c ================================================ #include #include char* strdup( const char* s ) { char* s2; size_t length; length = strlen( s ); s2 = ( char* )malloc( length + 1 ); if ( s2 == NULL ) { return NULL; } memcpy( s2, s, length + 1 ); return s2; } ================================================ FILE: src/sdk/src/libc/src/string/strerror.c ================================================ #include static char* error_strings[] = { "Cannot allocate memory", /* ENOMEM */ "Invalid argument", /* EINVAL */ "Input/output error", /* EIO */ "Timer expired", /* ETIME */ "Function not implemented", /* ENOSYS */ "No such file or directory", /* ENOENT */ "File exists", /* EEXIST */ "Device or resource busy", /* EBUSY */ "Is a directory", /* EISDIR */ "Inode not found", /* ENOINO */ "Executable format error", /* ENOEXEC */ "Bad file descriptor", /* EBADF */ "Hardware error", /* EHW */ "Numerical result out of range", /* ERANGE */ "No such device or address", /* ENXIO */ "Numerical argument out of domain", /* EDOM */ "No such device", /* ENODEV */ "Interrupted system call", /* EINTR */ "Inappropriate ioctl for device", /* ENOTTY */ "Operation not permitted", /* EPERM */ "Read-only file system", /* EROFS */ "Too many levels of symbolic links", /* ELOOP */ "Not a directory", /* ENOTDIR */ "Directory not empty", /* ENOTEMPTY */ "Resource temporarily unavailable", /* EAGAIN */ "Argument list too long", /* E2BIG */ "Connection timed out", /* ETIMEDOUT */ "Value too large for defined data type", /* EOVERFLOW */ "No space left on device", /* ENOSPC */ "No child processes", /* ECHILD */ "File name too long", /* ENAMETOOLONG */ "Illegal seek", /* ESPIPE */ "Permission denied" /* EACCES */ }; char* strerror( int errnum ) { if ( errnum < 0 ) { errnum = -errnum; } errnum--; if ( ( errnum < 0 ) || ( errnum >= ( sizeof( error_strings ) / sizeof( error_strings[ 0 ] ) ) ) ) { return NULL; } return error_strings[ errnum ]; } ================================================ FILE: src/sdk/src/libc/src/string/strlen.c ================================================ #include size_t strlen( const char* s ) { size_t r = 0; for( ; *s++ != 0; r++ ) { } return r; } ================================================ FILE: src/sdk/src/libc/src/string/strncasecmp.c ================================================ #include #include int strncasecmp( const char* s1, const char* s2, size_t c ) { int result = 0; while ( c ) { result = toupper( *s1 ) - toupper( *s2++ ); if ( ( result != 0 ) || ( *s1++ == 0 ) ) { break; } c--; } return result; } ================================================ FILE: src/sdk/src/libc/src/string/strncat.c ================================================ #include char* strncat( char* d, const char* s, size_t c ) { char* tmp = d; if ( c > 0 ) { while ( *d ) d++; while ( ( *d++ = *s++ ) ) { if ( --c == 0 ) { *d = 0; break; } } } return tmp; } ================================================ FILE: src/sdk/src/libc/src/string/strncmp.c ================================================ #include int strncmp( const char* s1, const char* s2, size_t c ) { int result = 0; while ( c ) { result = *s1 - *s2++; if ( ( result != 0 ) || ( *s1++ == 0 ) ) { break; } c--; } return result; } ================================================ FILE: src/sdk/src/libc/src/string/strncpy.c ================================================ #include char* strncpy( char* d, const char* s, size_t c ) { size_t i; char* tmp = d; for ( i = 0; i < c; i++ ) { *d++ = *s; if ( *s++ == 0 ) { break; } } for ( ; i < c; i++ ) { *d++ = 0; } return tmp; } ================================================ FILE: src/sdk/src/libc/src/string/strndup.c ================================================ #include #include #include char* strndup( const char* s, size_t n ) { char* s2; size_t len; len = strlen( s ); len = MIN( len, n ); s2 = ( char* )malloc( len + 1 ); if ( s2 == NULL ) { return NULL; } memcpy( s2, s, len ); s2[ len ] = '\0'; return s2; } ================================================ FILE: src/sdk/src/libc/src/string/strnlen.c ================================================ #include size_t strnlen( const char* s, size_t count ) { const char* sc; for ( sc = s; count-- && ( *sc != 0 ); ++sc ) { } return ( sc - s ); } ================================================ FILE: src/sdk/src/libc/src/string/strpbrk.c ================================================ #include char* strpbrk( const char* s, const char* accept ) { register int i, l = strlen( accept ); for ( ; *s != 0; s++ ) for ( i = 0; i < l; i++ ) if (*s == accept[i]) return (char*)s; return 0; } ================================================ FILE: src/sdk/src/libc/src/string/strrchr.c ================================================ #include char* strrchr( const char* s, int c ) { const char* end = s + strlen( s ); do { if ( *end == ( char )c ) { return ( char * )end; } } while ( --end >= s ); return NULL; } ================================================ FILE: src/sdk/src/libc/src/string/strsignal.c ================================================ #include static char* signal_names[] = { "Hangup", "Interrupt", "Quit", "Illegal instruction", "Trace/breakpoint trap", "Aborted", "Aborted", "Bus error", "Floating point exception", "Killed", "User defined signal 1", "Segmentation fault", "User defined signal 2", "Broken pipe", "Alarm clock", "Terminated", "Stack fault", "Child exited", "Continued", "Stopped (signal)", "Stopped", "Stopped (tty input)", "Stopped (tty output)", "Urgent I/O condition", "CPU time limit exceeded", "File size limit exceeded", "Virtual timer expired", "Profiling timer expired", "Window changed", "I/O possible", "Power failure", "Bad system call" }; char* strsignal( int signum ) { if ( signum <= 0 ) { return NULL; } signum--; if ( signum >= ( sizeof( signal_names ) / sizeof( signal_names[ 0 ] ) ) ) { return NULL; } return signal_names[ signum ]; } ================================================ FILE: src/sdk/src/libc/src/string/strspn.c ================================================ #include size_t strspn( const char* s, const char* accept ) { size_t l = 0; int a = 1; int i; int al = strlen( accept ); while( ( a ) && ( *s ) ) { for ( a = i = 0; ( !a ) && ( i < al ); i++ ) { if ( *s == accept[ i ] ) { a = 1; } } if ( a ) { l++; } s++; } return l; } ================================================ FILE: src/sdk/src/libc/src/string/strstr.c ================================================ #include char* strstr( const char* s1, const char* s2 ) { int l1, l2; l2 = strlen( s2 ); if ( !l2 ) { return ( char * )s1; } l1 = strlen( s1 ); while ( l1 >= l2 ) { l1--; if ( !memcmp( s1, s2, l2 ) ) { return ( char * )s1; } s1++; } return NULL; } ================================================ FILE: src/sdk/src/libc/src/string/strtok.c ================================================ #include static char* strtok_pos; char* strtok( char* s, const char* delim ) { return strtok_r( s, delim, &strtok_pos ); } ================================================ FILE: src/sdk/src/libc/src/string/strtok_r.c ================================================ #include char* strtok_r( char* s, const char* delim, char** ptrptr ) { char* tmp = NULL; if ( s == NULL ) { s = *ptrptr; } s += strspn( s, delim ); if ( *s ) { tmp = s; s += strcspn( s, delim ); if ( *s ) { *s++ = 0; } } *ptrptr = s; return tmp; } ================================================ FILE: src/sdk/src/libc/src/sys/chmod.c ================================================ #include int chmod( const char* path, mode_t mode ) { /* TODO */ return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/connect.c ================================================ #include #include #include int connect( int fd, const struct sockaddr* address, socklen_t addrlen ) { int error; error = syscall3( SYS_connect, fd, ( int )address, addrlen ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/fstat.c ================================================ #include #include #include int fstat( int fd, struct stat* stat ) { int error; error = syscall2( SYS_fstat, fd, ( int )stat ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/ioctl.c ================================================ #include #include #include int ioctl( int fd, int request, ... ) { int error; error = syscall3( SYS_ioctl, fd, request, *( ( ( ( int* )&request ) ) + 1 ) ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/sys/lstat.c ================================================ #include #include #include int lstat( const char* path, struct stat* stat ) { int error; error = syscall2( SYS_lstat, ( int )path, ( int )stat ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/mkdir.c ================================================ #include #include #include int mkdir( const char* pathname, mode_t mode ) { int error; error = syscall2( SYS_mkdir, ( int )pathname, ( int )mode ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/mount.c ================================================ #include #include #include int mount( const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data ) { int error; error = syscall4( SYS_mount, ( int )source, ( int )target, ( int )filesystemtype, ( int )mountflags ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/select.c ================================================ #include #include #include int select( int fds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout ) { int error; error = syscall5( SYS_select, fds, ( int )readfds, ( int )writefds, ( int )exceptfds, ( int )timeout ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/sys/socket.c ================================================ #include #include #include int socket( int domain, int type, int protocol ) { int error; error = syscall3( SYS_socket, domain, type, protocol ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/sys/stat.c ================================================ #include #include #include int stat( const char* path, struct stat* stat ) { int error; error = syscall2( SYS_stat, ( int )path, ( int )stat ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/stime.c ================================================ #include #include #include int stime( time_t *t ) { int error; error = syscall1( SYS_stime, ( int )t ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/umask.c ================================================ #include mode_t umask( mode_t mask ) { /* TODO */ return 0666; } ================================================ FILE: src/sdk/src/libc/src/sys/umount.c ================================================ #include #include #include int umount( const char* dir ) { int error; error = syscall1( SYS_unmount, ( int )dir ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/utime.c ================================================ #include #include #include int utime( const char* filename, const struct utimbuf* times ) { int error; struct utimbuf current; if ( times == NULL ) { current.actime = time( NULL ); current.modtime = current.actime; times = ( const struct utimbuf* )¤t; } error = syscall2( SYS_utime, ( int )filename, ( int )times ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/sys/utimes.c ================================================ #include #include #include int utimes( const char* filename, const timeval_t times[2] ) { struct utimbuf tmp; /* NOTE: no microsecond precision */ tmp.actime = times[ 0 ].tv_sec; tmp.modtime = times[ 1 ].tv_sec; /* This is a wrapper around utime() */ return utime( filename, &tmp ); } ================================================ FILE: src/sdk/src/libc/src/sys/wait.c ================================================ #include pid_t wait( int* status ) { return wait4( -1, status, 0, NULL ); } ================================================ FILE: src/sdk/src/libc/src/sys/wait3.c ================================================ #include pid_t wait3( int* status, int options, struct rusage* rusage ) { return wait4( -1, status, options, rusage ); } ================================================ FILE: src/sdk/src/libc/src/sys/wait4.c ================================================ #include #include #include pid_t wait4( pid_t pid, int* status, int options, struct rusage* rusage ) { int error; error = syscall4( SYS_wait4, pid, ( int )status, options, ( int )rusage ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/sys/waitpid.c ================================================ #include #include pid_t waitpid( pid_t pid, int* status, int options ) { return wait4( pid, status, options, NULL ); } ================================================ FILE: src/sdk/src/libc/src/termios/tcflow.c ================================================ #include int tcflow( int fd, int action ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/termios/tcflush.c ================================================ #include int tcflush( int fd, int queue_selector ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/termios/tcgetattr.c ================================================ #include #include #include #include int tcgetattr( int fd, struct termios* tio ) { int error; if ( tio == NULL ) { errno = EINVAL; return -1; } error = ioctl( fd, TCGETA, tio ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/termios/tcgetpgrp.c ================================================ #include pid_t tcgetpgrp( int fd ) { /* NOTE: This is a temp. hack to get bash working :) */ return getpid(); } ================================================ FILE: src/sdk/src/libc/src/termios/tcsetattr.c ================================================ #include #include #include #include int tcsetattr( int fd, int optional_actions, const struct termios* tio ) { int error; if ( tio == NULL ) { errno = EINVAL; return -1; } switch ( optional_actions ) { case TCSANOW : error = ioctl( fd, TCSETA, tio ); break; case TCSADRAIN : error = ioctl( fd, TCSETAW, tio ); break; case TCSAFLUSH : error = ioctl( fd, TCSETAF, tio ); break; default : error = -EINVAL; break; } if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/termios/tcsetpgrp.c ================================================ #include int tcsetpgrp( int fd, pid_t pgrp ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/time/asctime.c ================================================ #include static char asctime_buffer[ 32 ]; char* asctime( const tm_t* tm ) { return asctime_r( tm, asctime_buffer ); } ================================================ FILE: src/sdk/src/libc/src/time/asctime_r.c ================================================ #include char* asctime_r( const tm_t* tm, char* buf ) { strftime( buf, 26, "%a %b %d %H:%M:%S %Y\n", tm ); return buf; } ================================================ FILE: src/sdk/src/libc/src/time/ctime.c ================================================ #include char* ctime( const time_t* timep ) { return asctime( localtime( timep ) ); } ================================================ FILE: src/sdk/src/libc/src/time/ctime_r.c ================================================ #include char* ctime_r( const time_t* timep, char *buf) { buf = asctime( localtime( timep ) ); return buf; } ================================================ FILE: src/sdk/src/libc/src/time/gettimeofday.c ================================================ #include #include int gettimeofday( struct timeval* tv, struct timezone* tz ) { int ret; uint64_t time; ret = syscall1( SYS_get_system_time, ( int )&time ); if ( ret >= 0 ) { if ( tv != NULL ) { tv->tv_sec = time / 1000000; tv->tv_usec = time % 1000000; } } return ret; } ================================================ FILE: src/sdk/src/libc/src/time/gmtime.c ================================================ #include static tm_t ret; tm_t* gmtime( const time_t* timep ) { return gmtime_r( timep, &ret ); } ================================================ FILE: src/sdk/src/libc/src/time/gmtime_r.c ================================================ #include #include "time_int.h" tm_t* gmtime_r( const time_t* timep, tm_t* result ) { if ( _gmtime( *timep, result ) < 0 ) { return NULL; } return result; } ================================================ FILE: src/sdk/src/libc/src/time/localtime.c ================================================ #include static tm_t ret; tm_t* localtime( const time_t* timep ) { gmtime_r( timep, &ret ); /* TODO: timezones, tzset(3), tzname, etc */ return &ret; } ================================================ FILE: src/sdk/src/libc/src/time/localtime_r.c ================================================ #include tm_t* localtime_r( const time_t* timep, tm_t* result ) { gmtime_r( timep, result ); return result; } ================================================ FILE: src/sdk/src/libc/src/time/mktime.c ================================================ #include #include "time_int.h" time_t mktime( tm_t* tm ) { if ( tm->tm_year > 2100 ) { return -1; } return daysdiff( tm->tm_year, tm->tm_mon, tm->tm_mday ) * SECONDS_PER_DAY + tm->tm_hour * SECONDS_PER_HOUR + tm->tm_min * SECONDS_PER_MINUTE + tm->tm_sec; } ================================================ FILE: src/sdk/src/libc/src/time/nanosleep.c ================================================ #include #include #include #include int nanosleep( const struct timespec* req, struct timespec* rem ) { int error; uint64_t microsecs; uint64_t remaining; microsecs = ( uint64_t )req->tv_sec * 1000000 + ( uint64_t )req->tv_nsec / 1000; if ( microsecs == 0 ) { microsecs = 1; } error = syscall2( SYS_sleep_thread, ( int )µsecs, ( int )&remaining ); if ( error < 0 ) { errno = -error; if ( rem != NULL ) { rem->tv_sec = remaining / 1000000; rem->tv_nsec = ( remaining % 1000000 ) * 1000; } return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/time/strftime.c ================================================ #include #include #include #define APPEND( str ) \ ret += strlen(str); \ if(ret > max){ \ return 0; \ } \ strcat(s, (const char*) str); #define STRFT_ALTFORM 0x01 const char* month_names[ 12 ] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; const char* smonth_names[ 12 ] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; const char* day_names[ 7 ] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; const char* sday_names[ 7 ] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; size_t strftime(char* s, size_t max, const char* format, const tm_t* tm){ size_t ret = 0; int state; int flags; char tmp[max]; s[0] = '\0'; /* Initialize s */ max--; /* Reserve space for '\0' at the end */ state = flags = 0; for( ; *format != '\0'; format++){ switch(state){ case 0: if(*format != '%'){ if(ret < max){ s[ret++] = *format; s[ret] = '\0'; } else { s[ret] = '\0'; return 0; } break; } state++; format++; case 1: if(*format == '%'){ if(ret < max){ s[ret++] = '%'; s[ret] = '\0'; } else { s[ret] = '\0'; return 0; } state = flags = 0; break; } /* TODO: locale-independent, we need locales first :) if(*format == 'E'){ } */ if(*format == 'O'){ flags |= STRFT_ALTFORM; /* TODO: use this */ } /* TODO: glibc modifiers: _-0^# */ state++; case 2: switch(*format){ case 'a': APPEND(sday_names[tm->tm_wday]); break; case 'A': APPEND(day_names[tm->tm_wday]); break; case 'h': case 'b': APPEND(smonth_names[tm->tm_mon]); break; case 'B': APPEND(month_names[tm->tm_mon]); break; case 'c': /* The preferred date and time representation for the current locale. */ strftime(tmp, max-ret, "%a %b %e %H:%M:%S %Z %Y", tm); APPEND(tmp); break; case 'C': snprintf(tmp, max, "%d", tm->tm_year / 100); APPEND(tmp); break; case 'd': snprintf(tmp, max, "%02d", tm->tm_mday); APPEND(tmp); break; case 'D': strftime(tmp, max-ret, "%m/%d/%y", tm); APPEND(tmp); break; case 'e': snprintf(tmp, max, "%2d", tm->tm_mday); APPEND(tmp); break; case 'F': strftime(tmp, max-ret, "%Y-%m-%d", tm); APPEND(tmp); break; case 'G': /* The ISO 8601 year with century as a decimal number. The 4-digit year corresponding to the ISO week number (see %V). This has the same format and value as %y, except that if the ISO week number belongs to the previous or next year, that year is used instead. (TZ)*/ break; case 'g': /* Like %G, but without century, that is, with a 2-digit year (00-99). (TZ) */ break; case 'H': snprintf(tmp, max, "%02d", tm->tm_hour); APPEND(tmp); break; case 'I': snprintf(tmp, max, "%02d", tm->tm_hour % 12); APPEND(tmp); break; case 'j': /* Day of the year, 001-366 */ snprintf(tmp, max, "%03d", tm->tm_yday + 1); APPEND(tmp); break; case 'k': snprintf(tmp, max, "%2d", tm->tm_hour); APPEND(tmp); break; case 'l': snprintf(tmp, max, "%2d", tm->tm_hour % 12); APPEND(tmp); break; case 'm': snprintf(tmp, max, "%02d", tm->tm_mon + 1); APPEND(tmp); break; case 'M': snprintf(tmp, max, "%02d", tm->tm_min); APPEND(tmp); break; case 'n': APPEND("\n"); break; case 'p': if(tm->tm_hour >= 12){ APPEND("PM"); }else{ APPEND("AM"); } break; case 'P': if(tm->tm_hour >= 12){ APPEND("pm"); }else{ APPEND("am"); } break; case 'r': strftime(tmp, max-ret, "%I:%M:%S %p", tm); APPEND(tmp); break; case 'R': strftime(tmp, max-ret, "%H:%M", tm); APPEND(tmp); break; case 's': snprintf(tmp, max, "%llu", mktime((tm_t*) tm)); APPEND(tmp); break; case 'S': snprintf(tmp, max, "%02d", tm->tm_sec); APPEND(tmp); break; case 't': APPEND("\t"); break; case 'T': strftime(tmp, max-ret, "%H:%M:%S", tm); APPEND(tmp); break; case 'u': /* Day of the week, 1-7, Monday=1 */ snprintf(tmp, max, "%d", 1 + (tm->tm_wday + 6 ) % 7); APPEND(tmp); break; case 'U': /* The week number of the current year as a decimal number, range 00 to 53, starting with the first Sunday as the first day of week 01.*/ break; case 'V': /* The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week. See also %U and %W. */ break; case 'w': /* Day of the week, 0-6, Sunday=0 */ snprintf(tmp, max, "%d", tm->tm_wday); APPEND(tmp); break; case 'W': /* The week number of the current year as a decimal number, range 00 to 53, starting with the first Monday as the first day of week 01. */ break; case 'x': /* The preferred date representation for the current locale without the time. */ strftime(tmp, max-ret, "%a %b %e %Z %Y", tm); APPEND(tmp); break; case 'X': /* The preferred time representation for the current locale without the date. */ strftime(tmp, max-ret, "%H:%M:%S", tm); APPEND(tmp); break; case 'y': /* The year as a decimal number without a century (range 00 to 99). */ snprintf(tmp, max, "%02d", tm->tm_year % 100); APPEND(tmp); break; case 'Y': /* The year as a decimal number including the century. */ snprintf(tmp, max, "%d", tm->tm_year); APPEND(tmp); break; case 'z': /* The time-zone as hour offset from GMT. Required to emit RFC 822-conformant dates (using "%a, %d %b %Y %H:%M:%S %z"). (GNU) */ break; case 'Z': /* The time zone or name or abbreviation. */ break; default: break; } state = flags = 0; } } s[ret] = '\0'; return ret; } ================================================ FILE: src/sdk/src/libc/src/time/time.c ================================================ #include #include time_t time( time_t* t ) { int ret; uint64_t time; ret = syscall1( SYS_get_system_time, ( int )&time ); if ( ret < 0 ) { time = 0; } else { time /= 1000000; } if ( t != NULL ) { *t = time; } return time; } ================================================ FILE: src/sdk/src/libc/src/time/time_int.c ================================================ #include #include "time_int.h" const unsigned short int monthdays[ 13 ] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; const unsigned short int monthdays2[ 13 ] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; const unsigned short int sumofdays[ 60 ] = { 0, 366, 731, 1096, 1461, 1827, 2192, 2557, 2922, 3288, 3653, 4018, 4383, 4749, 5114, 5479, 5844, 6210, 6575, 6940, 7305, 7671, 8036, 8401, 8766, 9132, 9497, 9862, 10227, 10593, 10958, 11323, 11688, 12054, 12419, 12784, 13149, 13515, 13880, 14245, 14610, 14976, 15341, 15706, 16071, 16437, 16802, 17167, 17532, 17898, 18263, 18628, 18993, 19359, 19724, 20089, 20454, 20820, 21185, 21550 }; int _gmtime( time_t timeval, tm_t* ret ) { int i; ret->tm_sec = timeval % SECONDS_PER_MINUTE; timeval /= SECONDS_PER_MINUTE; ret->tm_min = timeval % MINUTES_PER_HOUR; timeval /= MINUTES_PER_HOUR; ret->tm_hour = timeval % HOURS_PER_DAY; timeval /= HOURS_PER_DAY; /* 1970(Epoch) is a leap year, and every 4th year too. 2000 is also a leap year, because its divisible by 400. timeval now holds the difference of whole days. 1 Jan 1970 was a Thursday. */ ret->tm_wday = (4 + timeval) % 7; /* TODO: return NULL when year does not fit. */ ret->tm_year = EPOCH; for ( i = 0; i < 60; i++ ) { if ( sumofdays[ i ] > timeval ) { ret->tm_year = EPOCH + i - 1; timeval -= sumofdays[ i - 1 ]; break; } } ret->tm_yday = ( int )timeval; if ( ret->tm_year % 4 == 0 ) { for ( ret->tm_mon = 0; ret->tm_mon < 12; ret->tm_mon++ ) { if ( monthdays2[ ret->tm_mon ] > timeval ) { timeval -= monthdays2[ --ret->tm_mon ]; break; } } } else { for ( ret->tm_mon = 0; ret->tm_mon < 12; ret->tm_mon++ ) { if ( monthdays[ ret->tm_mon ] > timeval ) { timeval -= monthdays[ --ret->tm_mon ]; break; } } } ret->tm_mday = ( int )timeval + 1; ret->tm_isdst = -1; return 0; } int daysdiff( int year, int month, int day ) { int i, days = 0; for ( i = EPOCH; i < year; i++ ) { if ( i % 4 == 0 ) { /* If it is a leap year */ days += 366; } else { days += 365; } } if ( year % 4 == 0 ) { days += monthdays2[ month ]; } else { days += monthdays[ month ]; } days += day - 1; return days; } int dayofweek( int year, int month, int day ) { /* The UNIX Epoch(1 Jan 1970) was a Thursday */ return ( 4 + daysdiff( year, month, day ) ) % 7; } ================================================ FILE: src/sdk/src/libc/src/time/time_int.h ================================================ #ifndef _TIME_INT_H_ #define _TIME_INT_H_ #include /* Time structures */ #define EPOCH 1970 /* Counting only time elapsed since 1 Jan 1970 */ #define SECONDS_PER_DAY 86400 #define SECONDS_PER_HOUR 3600 #define SECONDS_PER_MINUTE 60 #define MINUTES_PER_HOUR 60 #define HOURS_PER_DAY 24 /* The number of days that come before each month */ extern const unsigned short int monthdays[ 13 ]; /* Common year */ extern const unsigned short int monthdays2[ 13 ]; /* Leap year */ /* The number of days passed in N years after 1970 or any leap year */ extern const unsigned short int sumofdays[ 60 ]; /* Converts a UNIX timestamp to a broken-down time */ int _gmtime(time_t time, tm_t* ret); /* Returns the day of the week, 0=Sunday */ int dayofweek(int year, int month, int day); /* Returns the number of days since the epoch */ int daysdiff(int year, int month, int day); #endif // _TIME_INT_H_ ================================================ FILE: src/sdk/src/libc/src/time/tzset.c ================================================ void tzset( void ) { } ================================================ FILE: src/sdk/src/libc/src/trio/trio.c ================================================ /* * TODO: * - Scan is probably too permissive about its modifiers. * - C escapes in %#[] ? * - Multibyte characters (done for format parsing, except scan groups) * - Complex numbers? (C99 _Complex) * - Boolean values? (C99 _Bool) * - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used * to print the mantissa, e.g. NaN(0xc000000000000000) * - Should we support the GNU %a alloc modifier? GNU has an ugly hack * for %a, because C99 used %a for other purposes. If specified as * %as or %a[ it is interpreted as the alloc modifier, otherwise as * the C99 hex-float. This means that you cannot scan %as as a hex-float * immediately followed by an 's'. * - Scanning of collating symbols. */ /************************************************************************* * Trio include files */ #include "triodef.h" #include "trio.h" #include "triop.h" #if defined(TRIO_EMBED_NAN) # define TRIO_PUBLIC_NAN static # if TRIO_FEATURE_FLOAT # define TRIO_FUNC_NAN # define TRIO_FUNC_NINF # define TRIO_FUNC_PINF # define TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT # define TRIO_FUNC_ISINF # endif #endif #include "trionan.h" #if defined(TRIO_EMBED_STRING) # define TRIO_PUBLIC_STRING static # define TRIO_FUNC_LENGTH # define TRIO_FUNC_LENGTH_MAX # define TRIO_FUNC_TO_LONG # if TRIO_FEATURE_LOCALE # define TRIO_FUNC_COPY_MAX # endif # if TRIO_FEATURE_DYNAMICSTRING # define TRIO_FUNC_XSTRING_DUPLICATE # endif # if TRIO_EXTENSION && TRIO_FEATURE_SCANF # define TRIO_FUNC_EQUAL_LOCALE # endif # if TRIO_FEATURE_ERRNO # define TRIO_FUNC_ERROR # endif # if TRIO_FEATURE_FLOAT && TRIO_FEATURE_SCANF # define TRIO_FUNC_TO_DOUBLE # endif # if TRIO_FEATURE_DYNAMICSTRING # define TRIO_FUNC_STRING_EXTRACT # endif # if TRIO_FEATURE_DYNAMICSTRING # define TRIO_FUNC_STRING_TERMINATE # endif # if TRIO_FEATURE_USER_DEFINED # define TRIO_FUNC_DUPLICATE # endif # if TRIO_FEATURE_DYNAMICSTRING # define TRIO_FUNC_STRING_DESTROY # endif # if TRIO_FEATURE_USER_DEFINED # define TRIO_FUNC_DESTROY # endif # if TRIO_FEATURE_USER_DEFINED || (TRIO_FEATURE_FLOAT && TRIO_FEATURE_SCANF) # define TRIO_FUNC_EQUAL # endif # if TRIO_FEATURE_USER_DEFINED || TRIO_FEATURE_SCANF # define TRIO_FUNC_EQUAL_CASE # endif # if (TRIO_EXTENSION && TRIO_FEATURE_SCANF) # define TRIO_FUNC_EQUAL_MAX # endif # if TRIO_FEATURE_SCANF # define TRIO_FUNC_TO_UPPER # endif # if TRIO_FEATURE_DYNAMICSTRING # define TRIO_FUNC_XSTRING_APPEND_CHAR # endif #endif #include "triostr.h" /************************************************************************** * * Definitions * *************************************************************************/ #include #if TRIO_FEATURE_FLOAT # include # include #endif #if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_FEATURE_WIDECHAR # if !defined(TRIO_PLATFORM_WINCE) //# define TRIO_COMPILER_SUPPORTS_MULTIBYTE # if !defined(MB_LEN_MAX) # define MB_LEN_MAX 6 # endif # endif #endif #if (TRIO_COMPILER_VISUALC - 0 >= 1100) || defined(TRIO_COMPILER_BORLAND) # define TRIO_COMPILER_SUPPORTS_VISUALC_INT #endif #if TRIO_FEATURE_FLOAT # if defined(PREDEF_STANDARD_C99) \ || defined(PREDEF_STANDARD_UNIX03) # if !defined(HAVE_FLOORL) # define HAVE_FLOORL # endif # if !defined(HAVE_CEILL) # define HAVE_CEILL # endif # if !defined(HAVE_POWL) # define HAVE_POWL # endif # if !defined(HAVE_FMODL) # define HAVE_FMODL # endif # if !defined(HAVE_LOG10L) # define HAVE_LOG10L # endif # endif # if defined(TRIO_COMPILER_VISUALC) # if defined(floorl) # define HAVE_FLOORL # endif # if defined(ceill) # define HAVE_CEILL # endif # if defined(powl) # define HAVE_POWL # endif # if defined(fmodl) # define HAVE_FMODL # endif # if defined(log10l) # define HAVE_LOG10L # endif # endif #endif /************************************************************************* * Generic definitions */ #if !(defined(DEBUG) || defined(NDEBUG)) # define NDEBUG #endif #include #include #if defined(PREDEF_STANDARD_C99) && !defined(isascii) # define isascii(x) ((x) & 0x7F) #endif #if defined(TRIO_COMPILER_ANCIENT) # include #else # include #endif #include #if defined(TRIO_PLATFORM_WINCE) extern int errno; #else # include #endif #ifndef NULL # define NULL 0 #endif #define NIL ((char)0) #ifndef FALSE # define FALSE (1 == 0) # define TRUE (! FALSE) #endif #define BOOLEAN_T int /* mincore() can be used for debugging purposes */ #define VALID(x) (NULL != (x)) #if TRIO_FEATURE_ERRORCODE /* * Encode the error code and the position. This is decoded * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION. */ # define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8))) #else # define TRIO_ERROR_RETURN(x,y) (-1) #endif typedef unsigned long trio_flags_t; /************************************************************************* * Platform specific definitions */ #if defined(TRIO_PLATFORM_UNIX) # include # include # include # if !defined(TRIO_FEATURE_LOCALE) # define USE_LOCALE # endif #endif /* TRIO_PLATFORM_UNIX */ #if defined(TRIO_PLATFORM_VMS) # include #endif #if defined(TRIO_PLATFORM_WIN32) # if defined(TRIO_PLATFORM_WINCE) int read(int handle, char *buffer, unsigned int length); int write(int handle, const char *buffer, unsigned int length); # else # include # define read _read # define write _write # endif #endif /* TRIO_PLATFORM_WIN32 */ #if TRIO_FEATURE_WIDECHAR # if defined(PREDEF_STANDARD_C94) # include # include typedef wchar_t trio_wchar_t; typedef wint_t trio_wint_t; # else typedef char trio_wchar_t; typedef int trio_wint_t; # define WCONST(x) L ## x # define WEOF EOF # define iswalnum(x) isalnum(x) # define iswalpha(x) isalpha(x) # define iswcntrl(x) iscntrl(x) # define iswdigit(x) isdigit(x) # define iswgraph(x) isgraph(x) # define iswlower(x) islower(x) # define iswprint(x) isprint(x) # define iswpunct(x) ispunct(x) # define iswspace(x) isspace(x) # define iswupper(x) isupper(x) # define iswxdigit(x) isxdigit(x) # endif #endif /************************************************************************* * Compiler dependent definitions */ /* Support for long long */ #ifndef __cplusplus # if !defined(USE_LONGLONG) # if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__) # define USE_LONGLONG # else # if defined(TRIO_COMPILER_SUNPRO) # define USE_LONGLONG # else # if defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1400) # define USE_LONGLONG # else # if defined(_LONG_LONG) || defined(_LONGLONG) # define USE_LONGLONG # endif # endif # endif # endif # endif #endif /* The extra long numbers */ #if defined(USE_LONGLONG) typedef signed long long int trio_longlong_t; typedef unsigned long long int trio_ulonglong_t; #else # if defined(TRIO_COMPILER_SUPPORTS_VISUALC_INT) typedef signed __int64 trio_longlong_t; typedef unsigned __int64 trio_ulonglong_t; # else typedef TRIO_SIGNED long int trio_longlong_t; typedef unsigned long int trio_ulonglong_t; # endif #endif /* Maximal and fixed integer types */ #if defined(PREDEF_STANDARD_C99) # include typedef intmax_t trio_intmax_t; typedef uintmax_t trio_uintmax_t; typedef int8_t trio_int8_t; typedef int16_t trio_int16_t; typedef int32_t trio_int32_t; typedef int64_t trio_int64_t; #else # if defined(PREDEF_STANDARD_UNIX98) # include typedef intmax_t trio_intmax_t; typedef uintmax_t trio_uintmax_t; typedef int8_t trio_int8_t; typedef int16_t trio_int16_t; typedef int32_t trio_int32_t; typedef int64_t trio_int64_t; # else # if defined(TRIO_COMPILER_SUPPORTS_VISUALC_INT) typedef trio_longlong_t trio_intmax_t; typedef trio_ulonglong_t trio_uintmax_t; typedef __int8 trio_int8_t; typedef __int16 trio_int16_t; typedef __int32 trio_int32_t; typedef __int64 trio_int64_t; # else typedef trio_longlong_t trio_intmax_t; typedef trio_ulonglong_t trio_uintmax_t; # if defined(TRIO_INT8_T) typedef TRIO_INT8_T trio_int8_t; # else typedef TRIO_SIGNED char trio_int8_t; # endif # if defined(TRIO_INT16_T) typedef TRIO_INT16_T trio_int16_t; # else typedef TRIO_SIGNED short trio_int16_t; # endif # if defined(TRIO_INT32_T) typedef TRIO_INT32_T trio_int32_t; # else typedef TRIO_SIGNED int trio_int32_t; # endif # if defined(TRIO_INT64_T) typedef TRIO_INT64_T trio_int64_t; # else typedef trio_longlong_t trio_int64_t; # endif # endif # endif #endif #if defined(HAVE_FLOORL) # define trio_floor(x) floorl((x)) #else # define trio_floor(x) floor((double)(x)) #endif #if defined(HAVE_CEILL) # define trio_ceil(x) ceill((x)) #else # define trio_ceil(x) ceil((double)(x)) #endif #if defined(HAVE_FMODL) # define trio_fmod(x,y) fmodl((x),(y)) #else # define trio_fmod(x,y) fmod((double)(x),(double)(y)) #endif #if defined(HAVE_POWL) # define trio_pow(x,y) powl((x),(y)) #else # define trio_pow(x,y) pow((double)(x),(double)(y)) #endif #if defined(HAVE_LOG10L) # define trio_log10(x) log10l((x)) #else # define trio_log10(x) log10((double)(x)) #endif #if TRIO_FEATURE_FLOAT # define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x)) #endif /************************************************************************* * Internal Definitions */ #if TRIO_FEATURE_FLOAT # if !defined(DECIMAL_DIG) # define DECIMAL_DIG DBL_DIG # endif /* Long double sizes */ # ifdef LDBL_DIG # define MAX_MANTISSA_DIGITS LDBL_DIG # define MAX_EXPONENT_DIGITS 4 # define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP # else # define MAX_MANTISSA_DIGITS DECIMAL_DIG # define MAX_EXPONENT_DIGITS 3 # define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP # endif # if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG) # undef LDBL_DIG # undef LDBL_MANT_DIG # undef LDBL_EPSILON # define LDBL_DIG DBL_DIG # define LDBL_MANT_DIG DBL_MANT_DIG # define LDBL_EPSILON DBL_EPSILON # endif #endif /* TRIO_FEATURE_FLOAT */ /* The maximal number of digits is for base 2 */ #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT) /* The width of a pointer. The number of bits in a hex digit is 4 */ #define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4) #if TRIO_FEATURE_FLOAT /* Infinite and Not-A-Number for floating-point */ # define INFINITE_LOWER "inf" # define INFINITE_UPPER "INF" # define LONG_INFINITE_LOWER "infinite" # define LONG_INFINITE_UPPER "INFINITE" # define NAN_LOWER "nan" # define NAN_UPPER "NAN" #endif /* Various constants */ enum { TYPE_PRINT = 1, #if TRIO_FEATURE_SCANF TYPE_SCAN = 2, #endif /* Flags. FLAGS_LAST must be less than ULONG_MAX */ FLAGS_NEW = 0, FLAGS_STICKY = 1, FLAGS_SPACE = 2 * FLAGS_STICKY, FLAGS_SHOWSIGN = 2 * FLAGS_SPACE, FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN, FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST, FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE, FLAGS_SHORTSHORT = 2 * FLAGS_SHORT, FLAGS_LONG = 2 * FLAGS_SHORTSHORT, FLAGS_QUAD = 2 * FLAGS_LONG, FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD, FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE, FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T, FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T, FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T, FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING, FLAGS_UPPER = 2 * FLAGS_UNSIGNED, FLAGS_WIDTH = 2 * FLAGS_UPPER, FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH, FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER, FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION, FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER, FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE, FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER, FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E, FLAGS_QUOTE = 2 * FLAGS_FLOAT_G, FLAGS_WIDECHAR = 2 * FLAGS_QUOTE, FLAGS_IGNORE = 2 * FLAGS_WIDECHAR, FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE, FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER, FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER, FLAGS_LAST = FLAGS_FIXED_SIZE, /* Reused flags */ FLAGS_EXCLUDE = FLAGS_SHORT, FLAGS_USER_DEFINED = FLAGS_IGNORE, FLAGS_USER_DEFINED_PARAMETER = FLAGS_IGNORE_PARAMETER, FLAGS_ROUNDING = FLAGS_INTMAX_T, /* Compounded flags */ FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T, FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT, NO_POSITION = -1, NO_WIDTH = 0, NO_PRECISION = -1, NO_SIZE = -1, /* Do not change these */ NO_BASE = -1, MIN_BASE = 2, MAX_BASE = 36, BASE_BINARY = 2, BASE_OCTAL = 8, BASE_DECIMAL = 10, BASE_HEX = 16, /* Maximal number of allowed parameters */ MAX_PARAMETERS = 64, /* Maximal number of characters in class */ MAX_CHARACTER_CLASS = UCHAR_MAX + 1, #if TRIO_FEATURE_USER_DEFINED /* Maximal string lengths for user-defined specifiers */ MAX_USER_NAME = 64, MAX_USER_DATA = 256, #endif /* Maximal length of locale separator strings */ MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX, /* Maximal number of integers in grouping */ MAX_LOCALE_GROUPS = 64 }; #define NO_GROUPING ((int)CHAR_MAX) /* Fundamental formatting parameter types */ #define FORMAT_SENTINEL -1 /* marks end of parameters array */ #define FORMAT_UNKNOWN 0 #define FORMAT_INT 1 #define FORMAT_DOUBLE 2 #define FORMAT_CHAR 3 #define FORMAT_STRING 4 #define FORMAT_POINTER 5 #define FORMAT_COUNT 6 #define FORMAT_PARAMETER 7 #define FORMAT_GROUP 8 #define FORMAT_ERRNO 9 #define FORMAT_USER_DEFINED 10 /* Character constants */ #define CHAR_IDENTIFIER '%' #define CHAR_ALT_IDENTIFIER '$' #define CHAR_BACKSLASH '\\' #define CHAR_QUOTE '\"' #define CHAR_ADJUST ' ' #if TRIO_EXTENSION /* Character class expressions */ # define CLASS_ALNUM "[:alnum:]" # define CLASS_ALPHA "[:alpha:]" # define CLASS_BLANK "[:blank:]" # define CLASS_CNTRL "[:cntrl:]" # define CLASS_DIGIT "[:digit:]" # define CLASS_GRAPH "[:graph:]" # define CLASS_LOWER "[:lower:]" # define CLASS_PRINT "[:print:]" # define CLASS_PUNCT "[:punct:]" # define CLASS_SPACE "[:space:]" # define CLASS_UPPER "[:upper:]" # define CLASS_XDIGIT "[:xdigit:]" #endif /* * SPECIFIERS: * * * a Hex-float * A Hex-float * c Character * C Widechar character (wint_t) * d Decimal * e Float * E Float * F Float * F Float * g Float * G Float * i Integer * m Error message * n Count * o Octal * p Pointer * s String * S Widechar string (wchar_t *) * u Unsigned * x Hex * X Hex * [] Group * <> User-defined * * Reserved: * * D Binary Coded Decimal %D(length,precision) (OS/390) */ #define SPECIFIER_CHAR 'c' #define SPECIFIER_STRING 's' #define SPECIFIER_DECIMAL 'd' #define SPECIFIER_INTEGER 'i' #define SPECIFIER_UNSIGNED 'u' #define SPECIFIER_OCTAL 'o' #define SPECIFIER_HEX 'x' #define SPECIFIER_HEX_UPPER 'X' #if TRIO_FEATURE_FLOAT # define SPECIFIER_FLOAT_E 'e' # define SPECIFIER_FLOAT_E_UPPER 'E' # define SPECIFIER_FLOAT_F 'f' # define SPECIFIER_FLOAT_F_UPPER 'F' # define SPECIFIER_FLOAT_G 'g' # define SPECIFIER_FLOAT_G_UPPER 'G' #endif #define SPECIFIER_POINTER 'p' #if TRIO_FEATURE_SCANF # define SPECIFIER_GROUP '[' # define SPECIFIER_UNGROUP ']' #endif #define SPECIFIER_COUNT 'n' #if TRIO_UNIX98 # define SPECIFIER_CHAR_UPPER 'C' # define SPECIFIER_STRING_UPPER 'S' #endif #define SPECIFIER_HEXFLOAT 'a' #define SPECIFIER_HEXFLOAT_UPPER 'A' #define SPECIFIER_ERRNO 'm' #if TRIO_FEATURE_BINARY # define SPECIFIER_BINARY 'b' # define SPECIFIER_BINARY_UPPER 'B' #endif #if TRIO_FEATURE_USER_DEFINED # define SPECIFIER_USER_DEFINED_BEGIN '<' # define SPECIFIER_USER_DEFINED_END '>' # define SPECIFIER_USER_DEFINED_SEPARATOR ':' # define SPECIFIER_USER_DEFINED_EXTRA '|' #endif /* * QUALIFIERS: * * * Numbers = d,i,o,u,x,X * Float = a,A,e,E,f,F,g,G * String = s * Char = c * * * 9$ Position * Use the 9th parameter. 9 can be any number between 1 and * the maximal argument * * 9 Width * Set width to 9. 9 can be any number, but must not be postfixed * by '$' * * h Short * Numbers: * (unsigned) short int * * hh Short short * Numbers: * (unsigned) char * * l Long * Numbers: * (unsigned) long int * String: * as the S specifier * Char: * as the C specifier * * ll Long Long * Numbers: * (unsigned) long long int * * L Long Double * Float * long double * * # Alternative * Float: * Decimal-point is always present * String: * non-printable characters are handled as \number * * Spacing * * + Sign * * - Alignment * * . Precision * * * Parameter * print: use parameter * scan: no parameter (ignore) * * q Quad * * Z size_t * * w Widechar * * ' Thousands/quote * Numbers: * Integer part grouped in thousands * Binary numbers: * Number grouped in nibbles (4 bits) * String: * Quoted string * * j intmax_t * t prtdiff_t * z size_t * * ! Sticky * @ Parameter (for both print and scan) * * I n-bit Integer * Numbers: * The following options exists * I8 = 8-bit integer * I16 = 16-bit integer * I32 = 32-bit integer * I64 = 64-bit integer */ #define QUALIFIER_POSITION '$' #define QUALIFIER_SHORT 'h' #define QUALIFIER_LONG 'l' #define QUALIFIER_LONG_UPPER 'L' #define QUALIFIER_ALTERNATIVE '#' #define QUALIFIER_SPACE ' ' #define QUALIFIER_PLUS '+' #define QUALIFIER_MINUS '-' #define QUALIFIER_DOT '.' #define QUALIFIER_STAR '*' #define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */ #define QUALIFIER_SIZE_T 'z' #define QUALIFIER_PTRDIFF_T 't' #define QUALIFIER_INTMAX_T 'j' #define QUALIFIER_QUAD 'q' #define QUALIFIER_SIZE_T_UPPER 'Z' #if TRIO_MISC # define QUALIFIER_WIDECHAR 'w' #endif #define QUALIFIER_FIXED_SIZE 'I' #define QUALIFIER_QUOTE '\'' #define QUALIFIER_STICKY '!' #define QUALIFIER_VARSIZE '&' /* This should remain undocumented */ #define QUALIFIER_ROUNDING_UPPER 'R' #if TRIO_EXTENSION # define QUALIFIER_PARAM '@' /* Experimental */ # define QUALIFIER_COLON ':' /* For scanlists */ # define QUALIFIER_EQUAL '=' /* For scanlists */ #endif /************************************************************************* * * Internal Structures * *************************************************************************/ /* Parameters */ typedef struct { /* An indication of which entry in the data union is used */ int type; /* The flags */ trio_flags_t flags; /* The width qualifier */ int width; /* The precision qualifier */ int precision; /* The base qualifier */ int base; /* Base from specifier */ int baseSpecifier; /* The size for the variable size qualifier */ int varsize; /* Offset of the first character of the specifier */ int beginOffset; /* Offset of the first character after the specifier */ int endOffset; /* Position in the argument list that this parameter refers to */ int position; /* The data from the argument list */ union { char *string; #if TRIO_FEATURE_WIDECHAR trio_wchar_t *wstring; #endif trio_pointer_t pointer; union { trio_intmax_t as_signed; trio_uintmax_t as_unsigned; } number; #if TRIO_FEATURE_FLOAT double doubleNumber; double *doublePointer; trio_long_double_t longdoubleNumber; trio_long_double_t *longdoublePointer; #endif int errorNumber; } data; #if TRIO_FEATURE_USER_DEFINED /* For the user-defined specifier */ union { char namespace[MAX_USER_NAME]; int handler; /* if flags & FLAGS_USER_DEFINED_PARAMETER */ } user_defined; char user_data[MAX_USER_DATA]; #endif } trio_parameter_t; /* Container for customized functions */ typedef struct { union { trio_outstream_t out; trio_instream_t in; } stream; trio_pointer_t closure; } trio_custom_t; /* General trio "class" */ typedef struct _trio_class_t { /* * The function to write characters to a stream. */ void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int)); /* * The function to read characters from a stream. */ void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *)); /* * The current location in the stream. */ trio_pointer_t location; /* * The character currently being processed. */ int current; /* * The number of characters that would have been written/read * if there had been sufficient space. */ int processed; /* * The number of characters that are actually written/read. * Processed and committed will only differ for the *nprintf * and *nscanf functions. */ int committed; /* * The upper limit of characters that may be written/read. */ int max; /* * The last output error that was detected. */ int error; } trio_class_t; /* References (for user-defined callbacks) */ typedef struct _trio_reference_t { trio_class_t *data; trio_parameter_t *parameter; } trio_reference_t; #if TRIO_FEATURE_USER_DEFINED /* Registered entries (for user-defined callbacks) */ typedef struct _trio_userdef_t { struct _trio_userdef_t *next; trio_callback_t callback; char *name; } trio_userdef_t; #endif /************************************************************************* * * Internal Variables * *************************************************************************/ static TRIO_CONST char rcsid[] = "@(#)$Id: trio.c,v 1.112 2008/11/09 10:52:26 breese Exp $"; #if TRIO_FEATURE_FLOAT /* * Need this to workaround a parser bug in HP C/iX compiler that fails * to resolves macro definitions that includes type 'long double', * e.g: va_arg(arg_ptr, long double) */ # if defined(TRIO_PLATFORM_MPEIX) static TRIO_CONST trio_long_double_t ___dummy_long_double = 0; # endif #endif static TRIO_CONST char internalNullString[] = "(nil)"; #if defined(USE_LOCALE) static struct lconv *internalLocaleValues = NULL; #endif /* * UNIX98 says "in a locale where the radix character is not defined, * the radix character defaults to a period (.)" */ #if TRIO_FEATURE_FLOAT || TRIO_FEATURE_LOCALE || defined(USE_LOCALE) static int internalDecimalPointLength = 1; static char internalDecimalPoint = '.'; static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = "."; #endif #if TRIO_FEATURE_QUOTE || TRIO_FEATURE_LOCALE || TRIO_EXTENSION static int internalThousandSeparatorLength = 1; static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ","; static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING }; #endif static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; #if TRIO_FEATURE_SCANF static BOOLEAN_T internalDigitsUnconverted = TRUE; static int internalDigitArray[128]; # if TRIO_EXTENSION static BOOLEAN_T internalCollationUnconverted = TRUE; static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS]; # endif #endif #if TRIO_FEATURE_USER_DEFINED static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL; static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL; static trio_userdef_t *internalUserDef = NULL; #endif /************************************************************************* * * Internal Functions * ************************************************************************/ #if defined(TRIO_EMBED_NAN) # include "trionan.c" #endif #if defined(TRIO_EMBED_STRING) # include "triostr.c" #endif /************************************************************************* * TrioIsQualifier * * Description: * Remember to add all new qualifiers to this function. * QUALIFIER_POSITION must not be added. */ TRIO_PRIVATE BOOLEAN_T TrioIsQualifier TRIO_ARGS1((character), TRIO_CONST char character) { /* QUALIFIER_POSITION is not included */ switch (character) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case QUALIFIER_PLUS: case QUALIFIER_MINUS: case QUALIFIER_SPACE: case QUALIFIER_DOT: case QUALIFIER_STAR: case QUALIFIER_ALTERNATIVE: case QUALIFIER_SHORT: case QUALIFIER_LONG: case QUALIFIER_CIRCUMFLEX: case QUALIFIER_LONG_UPPER: case QUALIFIER_SIZE_T: case QUALIFIER_PTRDIFF_T: case QUALIFIER_INTMAX_T: case QUALIFIER_QUAD: case QUALIFIER_SIZE_T_UPPER: #if defined(QUALIFIER_WIDECHAR) case QUALIFIER_WIDECHAR: #endif case QUALIFIER_QUOTE: case QUALIFIER_STICKY: case QUALIFIER_VARSIZE: #if defined(QUALIFIER_PARAM) case QUALIFIER_PARAM: #endif case QUALIFIER_FIXED_SIZE: case QUALIFIER_ROUNDING_UPPER: return TRUE; default: return FALSE; } } /************************************************************************* * TrioSetLocale */ #if defined(USE_LOCALE) TRIO_PRIVATE void TrioSetLocale(TRIO_NOARGS) { internalLocaleValues = (struct lconv *)localeconv(); if (internalLocaleValues) { if ((internalLocaleValues->decimal_point) && (internalLocaleValues->decimal_point[0] != NIL)) { internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point); if (internalDecimalPointLength == 1) { internalDecimalPoint = internalLocaleValues->decimal_point[0]; } else { internalDecimalPoint = NIL; trio_copy_max(internalDecimalPointString, sizeof(internalDecimalPointString), internalLocaleValues->decimal_point); } } # if TRIO_EXTENSION if ((internalLocaleValues->thousands_sep) && (internalLocaleValues->thousands_sep[0] != NIL)) { trio_copy_max(internalThousandSeparator, sizeof(internalThousandSeparator), internalLocaleValues->thousands_sep); internalThousandSeparatorLength = trio_length(internalThousandSeparator); } # endif # if TRIO_EXTENSION if ((internalLocaleValues->grouping) && (internalLocaleValues->grouping[0] != NIL)) { trio_copy_max(internalGrouping, sizeof(internalGrouping), internalLocaleValues->grouping); } # endif } } #endif /* defined(USE_LOCALE) */ #if TRIO_FEATURE_FLOAT && TRIO_FEATURE_QUOTE TRIO_PRIVATE int TrioCalcThousandSeparatorLength TRIO_ARGS1((digits), int digits) { int count = 0; int step = NO_GROUPING; char *groupingPointer = internalGrouping; while (digits > 0) { if (*groupingPointer == CHAR_MAX) { /* Disable grouping */ break; /* while */ } else if (*groupingPointer == 0) { /* Repeat last group */ if (step == NO_GROUPING) { /* Error in locale */ break; /* while */ } } else { step = *groupingPointer++; } if (digits > step) count += internalThousandSeparatorLength; digits -= step; } return count; } #endif /* TRIO_FEATURE_FLOAT && TRIO_FEATURE_QUOTE */ #if TRIO_FEATURE_QUOTE TRIO_PRIVATE BOOLEAN_T TrioFollowedBySeparator TRIO_ARGS1((position), int position) { int step = 0; char *groupingPointer = internalGrouping; position--; if (position == 0) return FALSE; while (position > 0) { if (*groupingPointer == CHAR_MAX) { /* Disable grouping */ break; /* while */ } else if (*groupingPointer != 0) { step = *groupingPointer++; } if (step == 0) break; position -= step; } return (position == 0); } #endif /* TRIO_FEATURE_QUOTE */ /************************************************************************* * TrioGetPosition * * Get the %n$ position. */ TRIO_PRIVATE int TrioGetPosition TRIO_ARGS2((format, offsetPointer), TRIO_CONST char *format, int *offsetPointer) { #if TRIO_FEATURE_POSITIONAL char *tmpformat; int number = 0; int offset = *offsetPointer; number = (int)trio_to_long(&format[offset], &tmpformat, BASE_DECIMAL); offset = (int)(tmpformat - format); if ((number != 0) && (QUALIFIER_POSITION == format[offset++])) { *offsetPointer = offset; /* * number is decreased by 1, because n$ starts from 1, whereas * the array it is indexing starts from 0. */ return number - 1; } #endif return NO_POSITION; } /************************************************************************* * TrioFindNamespace * * Find registered user-defined specifier. * The prev argument is used for optimization only. */ #if TRIO_FEATURE_USER_DEFINED TRIO_PRIVATE trio_userdef_t * TrioFindNamespace TRIO_ARGS2((name, prev), TRIO_CONST char *name, trio_userdef_t **prev) { trio_userdef_t *def; if (internalEnterCriticalRegion) (void)internalEnterCriticalRegion(NULL); for (def = internalUserDef; def; def = def->next) { /* Case-sensitive string comparison */ if (trio_equal_case(def->name, name)) break; if (prev) *prev = def; } if (internalLeaveCriticalRegion) (void)internalLeaveCriticalRegion(NULL); return def; } #endif /************************************************************************* * TrioPower * * Description: * Calculate pow(base, exponent), where number and exponent are integers. */ #if TRIO_FEATURE_FLOAT TRIO_PRIVATE trio_long_double_t TrioPower TRIO_ARGS2((number, exponent), int number, int exponent) { trio_long_double_t result; if (number == 10) { switch (exponent) { /* Speed up calculation of common cases */ case 0: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1); break; case 1: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0); break; case 2: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1); break; case 3: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2); break; case 4: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3); break; case 5: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4); break; case 6: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5); break; case 7: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6); break; case 8: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7); break; case 9: result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8); break; default: result = trio_pow((trio_long_double_t)number, (trio_long_double_t)exponent); break; } } else { return trio_pow((trio_long_double_t)number, (trio_long_double_t)exponent); } return result; } #endif /* TRIO_FEATURE_FLOAT */ /************************************************************************* * TrioLogarithm */ #if TRIO_FEATURE_FLOAT TRIO_PRIVATE trio_long_double_t TrioLogarithm TRIO_ARGS2((number, base), trio_long_double_t number, int base) { trio_long_double_t result; if (number <= 0.0) { /* xlC crashes on log(0) */ result = (number == 0.0) ? trio_ninf() : trio_nan(); } else { if (base == 10) { result = trio_log10(number); } else { result = trio_log10(number) / trio_log10((double)base); } } return result; } #endif /* TRIO_FEATURE_FLOAT */ /************************************************************************* * TrioLogarithmBase */ #if TRIO_FEATURE_FLOAT TRIO_PRIVATE double TrioLogarithmBase TRIO_ARGS1((base), int base) { switch (base) { case BASE_BINARY : return 1.0; case BASE_OCTAL : return 3.0; case BASE_DECIMAL: return 3.321928094887362345; case BASE_HEX : return 4.0; default : return TrioLogarithm((double)base, 2); } } #endif /* TRIO_FEATURE_FLOAT */ /************************************************************************* * TrioParseQualifiers * * Description: * Parse the qualifiers of a potential conversion specifier */ TRIO_PRIVATE int TrioParseQualifiers TRIO_ARGS4((type, format, offset, parameter), int type, TRIO_CONST char *format, int offset, trio_parameter_t *parameter) { char ch; int dots = 0; /* Count number of dots in modifier part */ char *tmpformat; parameter->beginOffset = offset - 1; parameter->flags = FLAGS_NEW; parameter->position = TrioGetPosition(format, &offset); /* Default values */ parameter->width = NO_WIDTH; parameter->precision = NO_PRECISION; parameter->base = NO_BASE; parameter->varsize = NO_SIZE; while (TrioIsQualifier(format[offset])) { ch = format[offset++]; switch (ch) { case QUALIFIER_SPACE: parameter->flags |= FLAGS_SPACE; break; case QUALIFIER_PLUS: parameter->flags |= FLAGS_SHOWSIGN; break; case QUALIFIER_MINUS: parameter->flags |= FLAGS_LEFTADJUST; parameter->flags &= ~FLAGS_NILPADDING; break; case QUALIFIER_ALTERNATIVE: parameter->flags |= FLAGS_ALTERNATIVE; break; case QUALIFIER_DOT: if (dots == 0) /* Precision */ { dots++; /* Skip if no precision */ if (QUALIFIER_DOT == format[offset]) break; /* After the first dot we have the precision */ parameter->flags |= FLAGS_PRECISION; if ((QUALIFIER_STAR == format[offset]) #if defined(QUALIFIER_PARAM) || (QUALIFIER_PARAM == format[offset]) #endif ) { offset++; parameter->flags |= FLAGS_PRECISION_PARAMETER; parameter->precision = TrioGetPosition(format, &offset); } else { parameter->precision = trio_to_long(&format[offset], &tmpformat, BASE_DECIMAL); offset = (int)(tmpformat - format); } } else if (dots == 1) /* Base */ { dots++; /* After the second dot we have the base */ parameter->flags |= FLAGS_BASE; if ((QUALIFIER_STAR == format[offset]) #if defined(QUALIFIER_PARAM) || (QUALIFIER_PARAM == format[offset]) #endif ) { offset++; parameter->flags |= FLAGS_BASE_PARAMETER; parameter->base = TrioGetPosition(format, &offset); } else { parameter->base = trio_to_long(&format[offset], &tmpformat, BASE_DECIMAL); if (parameter->base > MAX_BASE) return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); offset = (int)(tmpformat - format); } } else { return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); } break; /* QUALIFIER_DOT */ #if defined(QUALIFIER_PARAM) case QUALIFIER_PARAM: parameter->type = TYPE_PRINT; /* FALLTHROUGH */ #endif case QUALIFIER_STAR: /* This has different meanings for print and scan */ if (TYPE_PRINT == type) { /* Read with from parameter */ parameter->flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER); int width = TrioGetPosition(format, &offset); if (NO_POSITION != width) parameter->width = width; /* else keep parameter->width = NO_WIDTH which != NO_POSITION */ } #if TRIO_FEATURE_SCANF else { /* Scan, but do not store result */ parameter->flags |= FLAGS_IGNORE; } #endif break; /* QUALIFIER_STAR */ case '0': if (! (parameter->flags & FLAGS_LEFTADJUST)) parameter->flags |= FLAGS_NILPADDING; /* FALLTHROUGH */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': parameter->flags |= FLAGS_WIDTH; /* * &format[offset - 1] is used to "rewind" the read * character from format */ parameter->width = trio_to_long(&format[offset - 1], &tmpformat, BASE_DECIMAL); offset = (int)(tmpformat - format); break; case QUALIFIER_SHORT: if (parameter->flags & FLAGS_SHORTSHORT) return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); else if (parameter->flags & FLAGS_SHORT) parameter->flags |= FLAGS_SHORTSHORT; else parameter->flags |= FLAGS_SHORT; break; case QUALIFIER_LONG: if (parameter->flags & FLAGS_QUAD) return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); else if (parameter->flags & FLAGS_LONG) parameter->flags |= FLAGS_QUAD; else parameter->flags |= FLAGS_LONG; break; #if TRIO_FEATURE_LONGDOUBLE case QUALIFIER_LONG_UPPER: parameter->flags |= FLAGS_LONGDOUBLE; break; #endif #if TRIO_FEATURE_SIZE_T case QUALIFIER_SIZE_T: parameter->flags |= FLAGS_SIZE_T; /* Modify flags for later truncation of number */ if (sizeof(size_t) == sizeof(trio_ulonglong_t)) parameter->flags |= FLAGS_QUAD; else if (sizeof(size_t) == sizeof(long)) parameter->flags |= FLAGS_LONG; break; #endif #if TRIO_FEATURE_PTRDIFF_T case QUALIFIER_PTRDIFF_T: parameter->flags |= FLAGS_PTRDIFF_T; if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t)) parameter->flags |= FLAGS_QUAD; else if (sizeof(ptrdiff_t) == sizeof(long)) parameter->flags |= FLAGS_LONG; break; #endif #if TRIO_FEATURE_INTMAX_T case QUALIFIER_INTMAX_T: parameter->flags |= FLAGS_INTMAX_T; if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t)) parameter->flags |= FLAGS_QUAD; else if (sizeof(trio_intmax_t) == sizeof(long)) parameter->flags |= FLAGS_LONG; break; #endif #if TRIO_FEATURE_QUAD case QUALIFIER_QUAD: parameter->flags |= FLAGS_QUAD; break; #endif #if TRIO_FEATURE_FIXED_SIZE case QUALIFIER_FIXED_SIZE: if (parameter->flags & FLAGS_FIXED_SIZE) return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); if (parameter->flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE | FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER)) return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); if ((format[offset] == '6') && (format[offset + 1] == '4')) { parameter->varsize = sizeof(trio_int64_t); offset += 2; } else if ((format[offset] == '3') && (format[offset + 1] == '2')) { parameter->varsize = sizeof(trio_int32_t); offset += 2; } else if ((format[offset] == '1') && (format[offset + 1] == '6')) { parameter->varsize = sizeof(trio_int16_t); offset += 2; } else if (format[offset] == '8') { parameter->varsize = sizeof(trio_int8_t); offset++; } else return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); parameter->flags |= FLAGS_FIXED_SIZE; break; #endif /* TRIO_FEATURE_FIXED_SIZE */ #if defined(QUALIFIER_WIDECHAR) case QUALIFIER_WIDECHAR: parameter->flags |= FLAGS_WIDECHAR; break; #endif #if TRIO_FEATURE_SIZE_T_UPPER case QUALIFIER_SIZE_T_UPPER: break; #endif #if TRIO_FEATURE_QUOTE case QUALIFIER_QUOTE: parameter->flags |= FLAGS_QUOTE; break; #endif #if TRIO_FEATURE_STICKY case QUALIFIER_STICKY: parameter->flags |= FLAGS_STICKY; break; #endif #if TRIO_FEATURE_VARSIZE case QUALIFIER_VARSIZE: parameter->flags |= FLAGS_VARSIZE_PARAMETER; break; #endif #if TRIO_FEATURE_ROUNDING case QUALIFIER_ROUNDING_UPPER: parameter->flags |= FLAGS_ROUNDING; break; #endif default: /* Bail out completely to make the error more obvious */ return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); } } /* while qualifier */ parameter->endOffset = offset; return 0; } /************************************************************************* * TrioParseSpecifier * * Description: * Parse the specifier part of a potential conversion specifier */ TRIO_PRIVATE int TrioParseSpecifier TRIO_ARGS4((type, format, offset, parameter), int type, TRIO_CONST char *format, int offset, trio_parameter_t *parameter) { parameter->baseSpecifier = NO_BASE; switch (format[offset++]) { #if defined(SPECIFIER_CHAR_UPPER) case SPECIFIER_CHAR_UPPER: parameter->flags |= FLAGS_WIDECHAR; /* FALLTHROUGH */ #endif case SPECIFIER_CHAR: if (parameter->flags & FLAGS_LONG) parameter->flags |= FLAGS_WIDECHAR; else if (parameter->flags & FLAGS_SHORT) parameter->flags &= ~FLAGS_WIDECHAR; parameter->type = FORMAT_CHAR; break; #if defined(SPECIFIER_STRING_UPPER) case SPECIFIER_STRING_UPPER: parameter->flags |= FLAGS_WIDECHAR; /* FALLTHROUGH */ #endif case SPECIFIER_STRING: if (parameter->flags & FLAGS_LONG) parameter->flags |= FLAGS_WIDECHAR; else if (parameter->flags & FLAGS_SHORT) parameter->flags &= ~FLAGS_WIDECHAR; parameter->type = FORMAT_STRING; break; #if defined(SPECIFIER_GROUP) case SPECIFIER_GROUP: if (TYPE_SCAN == type) { int depth = 1; parameter->type = FORMAT_GROUP; if (format[offset] == QUALIFIER_CIRCUMFLEX) offset++; if (format[offset] == SPECIFIER_UNGROUP) offset++; if (format[offset] == QUALIFIER_MINUS) offset++; /* Skip nested brackets */ while (format[offset] != NIL) { if (format[offset] == SPECIFIER_GROUP) { depth++; } else if (format[offset] == SPECIFIER_UNGROUP) { if (--depth <= 0) { offset++; break; } } offset++; } } break; #endif /* defined(SPECIFIER_GROUP) */ case SPECIFIER_INTEGER: parameter->type = FORMAT_INT; break; case SPECIFIER_UNSIGNED: parameter->flags |= FLAGS_UNSIGNED; parameter->type = FORMAT_INT; break; case SPECIFIER_DECIMAL: parameter->baseSpecifier = BASE_DECIMAL; parameter->type = FORMAT_INT; break; case SPECIFIER_OCTAL: parameter->flags |= FLAGS_UNSIGNED; parameter->baseSpecifier = BASE_OCTAL; parameter->type = FORMAT_INT; break; #if TRIO_FEATURE_BINARY case SPECIFIER_BINARY_UPPER: parameter->flags |= FLAGS_UPPER; /* FALLTHROUGH */ case SPECIFIER_BINARY: parameter->flags |= FLAGS_NILPADDING; parameter->baseSpecifier = BASE_BINARY; parameter->type = FORMAT_INT; break; #endif case SPECIFIER_HEX_UPPER: parameter->flags |= FLAGS_UPPER; /* FALLTHROUGH */ case SPECIFIER_HEX: parameter->flags |= FLAGS_UNSIGNED; parameter->baseSpecifier = BASE_HEX; parameter->type = FORMAT_INT; break; #if defined(SPECIFIER_FLOAT_E) # if defined(SPECIFIER_FLOAT_E_UPPER) case SPECIFIER_FLOAT_E_UPPER: parameter->flags |= FLAGS_UPPER; /* FALLTHROUGH */ # endif case SPECIFIER_FLOAT_E: parameter->flags |= FLAGS_FLOAT_E; parameter->type = FORMAT_DOUBLE; break; #endif #if defined(SPECIFIER_FLOAT_G) # if defined(SPECIFIER_FLOAT_G_UPPER) case SPECIFIER_FLOAT_G_UPPER: parameter->flags |= FLAGS_UPPER; /* FALLTHROUGH */ # endif case SPECIFIER_FLOAT_G: parameter->flags |= FLAGS_FLOAT_G; parameter->type = FORMAT_DOUBLE; break; #endif #if defined(SPECIFIER_FLOAT_F) # if defined(SPECIFIER_FLOAT_F_UPPER) case SPECIFIER_FLOAT_F_UPPER: parameter->flags |= FLAGS_UPPER; /* FALLTHROUGH */ # endif case SPECIFIER_FLOAT_F: parameter->type = FORMAT_DOUBLE; break; #endif #if defined(TRIO_COMPILER_VISUALC) # pragma warning( push ) # pragma warning( disable : 4127 ) /* Conditional expression is constant */ #endif case SPECIFIER_POINTER: if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t)) parameter->flags |= FLAGS_QUAD; else if (sizeof(trio_pointer_t) == sizeof(long)) parameter->flags |= FLAGS_LONG; parameter->type = FORMAT_POINTER; break; #if defined(TRIO_COMPILER_VISUALC) # pragma warning( pop ) #endif case SPECIFIER_COUNT: parameter->type = FORMAT_COUNT; break; #if TRIO_FEATURE_HEXFLOAT case SPECIFIER_HEXFLOAT_UPPER: parameter->flags |= FLAGS_UPPER; /* FALLTHROUGH */ case SPECIFIER_HEXFLOAT: parameter->baseSpecifier = BASE_HEX; parameter->type = FORMAT_DOUBLE; break; #endif #if TRIO_FEATURE_ERRNO case SPECIFIER_ERRNO: parameter->type = FORMAT_ERRNO; break; #endif #if TRIO_FEATURE_USER_DEFINED case SPECIFIER_USER_DEFINED_BEGIN: { unsigned int max; int without_namespace = TRUE; char* tmpformat = (char *)&format[offset]; int ch; parameter->type = FORMAT_USER_DEFINED; parameter->user_defined.namespace[0] = NIL; while ((ch = format[offset]) != NIL) { offset++; if ((ch == SPECIFIER_USER_DEFINED_END) || (ch == SPECIFIER_USER_DEFINED_EXTRA)) { if (without_namespace) /* No namespace, handler will be passed as an argument */ parameter->flags |= FLAGS_USER_DEFINED_PARAMETER; /* Copy the user data */ max = (unsigned int)(&format[offset] - tmpformat); if (max > MAX_USER_DATA) max = MAX_USER_DATA; trio_copy_max(parameter->user_data, max, tmpformat); /* Skip extra data (which is only there to keep the compiler happy) */ while ((ch != NIL) && (ch != SPECIFIER_USER_DEFINED_END)) ch = format[offset++]; break; /* while */ } if (ch == SPECIFIER_USER_DEFINED_SEPARATOR) { without_namespace = FALSE; /* Copy the namespace for later looking-up */ max = (int)(&format[offset] - tmpformat); if (max > MAX_USER_NAME) max = MAX_USER_NAME; trio_copy_max(parameter->user_defined.namespace, max, tmpformat); tmpformat = (char *)&format[offset]; } } if (ch != SPECIFIER_USER_DEFINED_END) return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); } break; #endif /* TRIO_FEATURE_USER_DEFINED */ default: /* Bail out completely to make the error more obvious */ return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); } parameter->endOffset = offset; return 0; } /************************************************************************* * TrioParse * * Description: * Parse the format string */ TRIO_PRIVATE int TrioParse TRIO_ARGS5((type, format, parameters, arglist, argarray), int type, TRIO_CONST char *format, trio_parameter_t *parameters, va_list arglist, trio_pointer_t *argarray) { /* Count the number of times a parameter is referenced */ unsigned short usedEntries[MAX_PARAMETERS]; /* Parameter counters */ int parameterPosition; int maxParam = -1; /* Utility variables */ int offset; /* Offset into formatting string */ BOOLEAN_T positional; /* Does the specifier have a positional? */ #if TRIO_FEATURE_STICKY BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */ #endif /* * indices specifies the order in which the parameters must be * read from the va_args (this is necessary to handle positionals) */ int indices[MAX_PARAMETERS]; int pos = 0; /* Various variables */ #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) int charlen; #endif int save_errno; int i = -1; int num; /* * The 'parameters' array is not initialized, but we need to * know which entries we have used. */ memset(usedEntries, 0, sizeof(usedEntries)); save_errno = errno; offset = 0; parameterPosition = 0; #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) (void)mblen(NULL, 0); #endif while (format[offset]) { trio_parameter_t parameter = {}; int status; #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) if (! isascii(format[offset])) { /* * Multibyte characters cannot be legal specifiers or * modifiers, so we skip over them. */ charlen = mblen(&format[offset], MB_LEN_MAX); offset += (charlen > 0) ? charlen : 1; continue; /* while */ } #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */ switch(format[offset++]) { case CHAR_IDENTIFIER: { if (CHAR_IDENTIFIER == format[offset]) { /* skip double "%" */ offset++; continue; /* while */ } status = TrioParseQualifiers(type, format, offset, ¶meter); if (status < 0) return status; /* Return qualifier syntax error */ status = TrioParseSpecifier(type, format, parameter.endOffset, ¶meter); if (status < 0) return status; /* Return specifier syntax error */ } break; #if TRIO_EXTENSION case CHAR_ALT_IDENTIFIER: { status = TrioParseQualifiers(type, format, offset, ¶meter); if (status < 0) continue; /* False alert, not a user defined specifier */ status = TrioParseSpecifier(type, format, parameter.endOffset, ¶meter); if ((status < 0) || (FORMAT_USER_DEFINED != parameter.type)) continue; /* False alert, not a user defined specifier */ } break; #endif default: continue; /* while */ } /* now handle the parsed conversion specification */ positional = (NO_POSITION != parameter.position); /* * Parameters only need the type and value. The value is * read later. */ if (parameter.flags & FLAGS_WIDTH_PARAMETER) { if (parameter.width == NO_WIDTH) { parameter.width = parameterPosition++; } else { if (! positional) parameter.position = parameter.width + 1; } usedEntries[parameter.width] += 1; if (parameter.width > maxParam) maxParam = parameter.width; parameters[pos].type = FORMAT_PARAMETER; parameters[pos].flags = 0; indices[parameter.width] = pos; parameter.width = pos++; } if (parameter.flags & FLAGS_PRECISION_PARAMETER) { if (parameter.precision == NO_PRECISION) { parameter.precision = parameterPosition++; } else { if (! positional) parameter.position = parameter.precision + 1; } usedEntries[parameter.precision] += 1; if (parameter.precision > maxParam) maxParam = parameter.precision; parameters[pos].type = FORMAT_PARAMETER; parameters[pos].flags = 0; indices[parameter.precision] = pos; parameter.precision = pos++; } if (parameter.flags & FLAGS_BASE_PARAMETER) { if (parameter.base == NO_BASE) { parameter.base = parameterPosition++; } else { if (! positional) parameter.position = parameter.base + 1; } usedEntries[parameter.base] += 1; if (parameter.base > maxParam) maxParam = parameter.base; parameters[pos].type = FORMAT_PARAMETER; parameters[pos].flags = 0; indices[parameter.base] = pos; parameter.base = pos++; } #if TRIO_FEATURE_VARSIZE if (parameter.flags & FLAGS_VARSIZE_PARAMETER) { parameter.varsize = parameterPosition++; usedEntries[parameter.varsize] += 1; if (parameter.varsize > maxParam) maxParam = parameter.varsize; parameters[pos].type = FORMAT_PARAMETER; parameters[pos].flags = 0; indices[parameter.varsize] = pos; parameter.varsize = pos++; } #endif #if TRIO_FEATURE_USER_DEFINED if (parameter.flags & FLAGS_USER_DEFINED_PARAMETER) { parameter.user_defined.handler = parameterPosition++; usedEntries[parameter.user_defined.handler] += 1; if (parameter.user_defined.handler > maxParam) maxParam = parameter.user_defined.handler; parameters[pos].type = FORMAT_PARAMETER; parameters[pos].flags = FLAGS_USER_DEFINED; indices[parameter.user_defined.handler] = pos; parameter.user_defined.handler = pos++; } #endif if (NO_POSITION == parameter.position) { parameter.position = parameterPosition++; } if (parameter.position > maxParam) maxParam = parameter.position; if (parameter.position >= MAX_PARAMETERS) { /* Bail out completely to make the error more obvious */ return TRIO_ERROR_RETURN(TRIO_ETOOMANY, offset); } indices[parameter.position] = pos; /* Count the number of times this entry has been used */ usedEntries[parameter.position] += 1; /* Find last sticky parameters */ #if TRIO_FEATURE_STICKY if (parameter.flags & FLAGS_STICKY) { gotSticky = TRUE; } else if (gotSticky) { for (i = pos - 1; i >= 0; i--) { if (parameters[i].type == FORMAT_PARAMETER) continue; if ((parameters[i].flags & FLAGS_STICKY) && (parameters[i].type == parameter.type)) { /* Do not overwrite current qualifiers */ parameter.flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY); if (parameter.width == NO_WIDTH) parameter.width = parameters[i].width; if (parameter.precision == NO_PRECISION) parameter.precision = parameters[i].precision; if (parameter.base == NO_BASE) parameter.base = parameters[i].base; break; } } } #endif if (parameter.base == NO_BASE) parameter.base = BASE_DECIMAL; offset = parameter.endOffset; memcpy(¶meters[pos++], ¶meter, sizeof(parameter)); } /* while format characters left */ parameters[pos].type = FORMAT_SENTINEL; /* end parameter array with sentinel */ parameters[pos].beginOffset = offset; for (num = 0; num <= maxParam; num++) { if (usedEntries[num] != 1) { if (usedEntries[num] == 0) /* gap detected */ return TRIO_ERROR_RETURN(TRIO_EGAP, num); else /* double references detected */ return TRIO_ERROR_RETURN(TRIO_EDBLREF, num); } i = indices[num]; /* * FORMAT_PARAMETERS are only present if they must be read, * so it makes no sense to check the ignore flag (besides, * the flags variable is not set for that particular type) */ if ((parameters[i].type != FORMAT_PARAMETER) && (parameters[i].flags & FLAGS_IGNORE)) continue; /* for all arguments */ /* * The stack arguments are read according to ANSI C89 * default argument promotions: * * char = int * short = int * unsigned char = unsigned int * unsigned short = unsigned int * float = double * * In addition to the ANSI C89 these types are read (the * default argument promotions of C99 has not been * considered yet) * * long long * long double * size_t * ptrdiff_t * intmax_t */ switch (parameters[i].type) { case FORMAT_GROUP: case FORMAT_STRING: #if TRIO_FEATURE_WIDECHAR if (parameters[i].flags & FLAGS_WIDECHAR) { parameters[i].data.wstring = (argarray == NULL) ? va_arg(arglist, trio_wchar_t *) : (trio_wchar_t *)(argarray[num]); } else #endif { parameters[i].data.string = (argarray == NULL) ? va_arg(arglist, char *) : (char *)(argarray[num]); } break; #if TRIO_FEATURE_USER_DEFINED case FORMAT_USER_DEFINED: #endif case FORMAT_POINTER: case FORMAT_COUNT: case FORMAT_UNKNOWN: parameters[i].data.pointer = (argarray == NULL) ? va_arg(arglist, trio_pointer_t ) : argarray[num]; break; case FORMAT_CHAR: case FORMAT_INT: #if TRIO_FEATURE_SCANF if (TYPE_SCAN == type) { if (argarray == NULL) parameters[i].data.pointer = (trio_pointer_t)va_arg(arglist, trio_pointer_t); else { if (parameters[i].type == FORMAT_CHAR) parameters[i].data.pointer = (trio_pointer_t)((char *)argarray[num]); else if (parameters[i].flags & FLAGS_SHORT) parameters[i].data.pointer = (trio_pointer_t)((short *)argarray[num]); else parameters[i].data.pointer = (trio_pointer_t)((int *)argarray[num]); } } else #endif /* TRIO_FEATURE_SCANF */ { #if TRIO_FEATURE_VARSIZE || TRIO_FEATURE_FIXED_SIZE if (parameters[i].flags & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE)) { int varsize; if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER) { /* * Variable sizes are mapped onto the fixed sizes, in * accordance with integer promotion. * * Please note that this may not be portable, as we * only guess the size, not the layout of the numbers. * For example, if int is little-endian, and long is * big-endian, then this will fail. */ varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned; } else { /* Used for the I modifiers */ varsize = parameters[i].varsize; } parameters[i].flags &= ~FLAGS_ALL_VARSIZES; if (varsize <= (int)sizeof(int)) ; else if (varsize <= (int)sizeof(long)) parameters[i].flags |= FLAGS_LONG; #if TRIO_FEATURE_INTMAX_T else if (varsize <= (int)sizeof(trio_longlong_t)) parameters[i].flags |= FLAGS_QUAD; else parameters[i].flags |= FLAGS_INTMAX_T; #else else parameters[i].flags |= FLAGS_QUAD; #endif } #endif /* TRIO_FEATURE_VARSIZE */ #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER if (parameters[i].flags & FLAGS_SIZE_T) parameters[i].data.number.as_unsigned = (argarray == NULL) ? (trio_uintmax_t)va_arg(arglist, size_t) : (trio_uintmax_t)(*((size_t *)argarray[num])); else #endif #if TRIO_FEATURE_PTRDIFF_T if (parameters[i].flags & FLAGS_PTRDIFF_T) parameters[i].data.number.as_unsigned = (argarray == NULL) ? (trio_uintmax_t)va_arg(arglist, ptrdiff_t) : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num])); else #endif #if TRIO_FEATURE_INTMAX_T if (parameters[i].flags & FLAGS_INTMAX_T) parameters[i].data.number.as_unsigned = (argarray == NULL) ? (trio_uintmax_t)va_arg(arglist, trio_intmax_t) : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num])); else #endif if (parameters[i].flags & FLAGS_QUAD) parameters[i].data.number.as_unsigned = (argarray == NULL) ? (trio_uintmax_t)va_arg(arglist, trio_ulonglong_t) : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num])); else if (parameters[i].flags & FLAGS_LONG) parameters[i].data.number.as_unsigned = (argarray == NULL) ? (trio_uintmax_t)va_arg(arglist, long) : (trio_uintmax_t)(*((long *)argarray[num])); else { if (argarray == NULL) parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(arglist, int); else { if (parameters[i].type == FORMAT_CHAR) parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num])); else if (parameters[i].flags & FLAGS_SHORT) parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num])); else parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num])); } } } break; case FORMAT_PARAMETER: /* * The parameter for the user-defined specifier is a pointer, * whereas the rest (width, precision, base) uses an integer. */ if (parameters[i].flags & FLAGS_USER_DEFINED) parameters[i].data.pointer = (argarray == NULL) ? va_arg(arglist, trio_pointer_t ) : argarray[num]; else parameters[i].data.number.as_unsigned = (argarray == NULL) ? (trio_uintmax_t)va_arg(arglist, int) : (trio_uintmax_t)(*((int *)argarray[num])); break; #if TRIO_FEATURE_FLOAT case FORMAT_DOUBLE: # if TRIO_FEATURE_SCANF if (TYPE_SCAN == type) { if (parameters[i].flags & FLAGS_LONGDOUBLE) parameters[i].data.longdoublePointer = (argarray == NULL) ? va_arg(arglist, trio_long_double_t *) : (trio_long_double_t *)argarray[num]; else { if (parameters[i].flags & FLAGS_LONG) parameters[i].data.doublePointer = (argarray == NULL) ? va_arg(arglist, double *) : (double *)argarray[num]; else parameters[i].data.doublePointer = (argarray == NULL) ? (double *)va_arg(arglist, float *) : (double *)((float *)argarray[num]); } } else # endif /* TRIO_FEATURE_SCANF */ { if (parameters[i].flags & FLAGS_LONGDOUBLE) parameters[i].data.longdoubleNumber = (argarray == NULL) ? va_arg(arglist, trio_long_double_t) : (trio_long_double_t)(*((trio_long_double_t *)argarray[num])); else { if (argarray == NULL) parameters[i].data.longdoubleNumber = (trio_long_double_t)va_arg(arglist, double); else { if (parameters[i].flags & FLAGS_SHORT) parameters[i].data.longdoubleNumber = (trio_long_double_t)(*((float *)argarray[num])); else parameters[i].data.longdoubleNumber = (trio_long_double_t)(*((double *)argarray[num])); } } } break; #endif /* TRIO_FEATURE_FLOAT */ #if TRIO_FEATURE_ERRNO case FORMAT_ERRNO: parameters[i].data.errorNumber = save_errno; break; #endif default: break; } } /* for all specifiers */ return num; } /************************************************************************* * * FORMATTING * ************************************************************************/ /************************************************************************* * TrioWriteNumber * * Description: * Output a number. * The complexity of this function is a result of the complexity * of the dependencies of the flags. */ TRIO_PRIVATE void TrioWriteNumber TRIO_ARGS6((self, number, flags, width, precision, base), trio_class_t *self, trio_uintmax_t number, trio_flags_t flags, int width, int precision, int base) { BOOLEAN_T isNegative; BOOLEAN_T isNumberZero; BOOLEAN_T isPrecisionZero; BOOLEAN_T ignoreNumber; char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1]; char *bufferend; char *pointer; TRIO_CONST char *digits; int i; #if TRIO_FEATURE_QUOTE int length; char *p; #endif int count; int digitOffset; assert(VALID(self)); assert(VALID(self->OutStream)); assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE)); digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower; if (base == NO_BASE) base = BASE_DECIMAL; isNumberZero = (number == 0); isPrecisionZero = (precision == 0); ignoreNumber = (isNumberZero && isPrecisionZero && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL))); if (flags & FLAGS_UNSIGNED) { isNegative = FALSE; flags &= ~FLAGS_SHOWSIGN; } else { isNegative = ((trio_intmax_t)number < 0); if (isNegative) number = -((trio_intmax_t)number); } if (flags & FLAGS_QUAD) number &= (trio_ulonglong_t)-1; else if (flags & FLAGS_LONG) number &= (unsigned long)-1; else number &= (unsigned int)-1; /* Build number */ pointer = bufferend = &buffer[sizeof(buffer) - 1]; *pointer-- = NIL; for (i = 1; i < (int)sizeof(buffer); i++) { digitOffset = number % base; *pointer-- = digits[digitOffset]; number /= base; if (number == 0) break; #if TRIO_FEATURE_QUOTE if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1)) { /* * We are building the number from the least significant * to the most significant digit, so we have to copy the * thousand separator backwards */ length = internalThousandSeparatorLength; if (((int)(pointer - buffer) - length) > 0) { p = &internalThousandSeparator[length - 1]; while (length-- > 0) *pointer-- = *p--; } } #endif } if (! ignoreNumber) { /* Adjust width */ width -= (bufferend - pointer) - 1; } /* Adjust precision */ if (NO_PRECISION != precision) { precision -= (bufferend - pointer) - 1; if (precision < 0) precision = 0; flags |= FLAGS_NILPADDING; } /* Calculate padding */ count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION))) ? precision : 0; /* Adjust width further */ if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) width--; if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero) { switch (base) { case BASE_BINARY: case BASE_HEX: width -= 2; break; case BASE_OCTAL: if (!(flags & FLAGS_NILPADDING) || (count == 0)) width--; break; default: break; } } /* Output prefixes spaces if needed */ if (! ((flags & FLAGS_LEFTADJUST) || ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION)))) { while (width-- > count) self->OutStream(self, CHAR_ADJUST); } /* width has been adjusted for signs and alternatives */ if (isNegative) self->OutStream(self, '-'); else if (flags & FLAGS_SHOWSIGN) self->OutStream(self, '+'); else if (flags & FLAGS_SPACE) self->OutStream(self, ' '); /* Prefix is not written when the value is zero */ if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero) { switch (base) { case BASE_BINARY: self->OutStream(self, '0'); self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b'); break; case BASE_OCTAL: if (!(flags & FLAGS_NILPADDING) || (count == 0)) self->OutStream(self, '0'); break; case BASE_HEX: self->OutStream(self, '0'); self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); break; default: break; } /* switch base */ } /* Output prefixed zero padding if needed */ if (flags & FLAGS_NILPADDING) { if (precision == NO_PRECISION) precision = width; while (precision-- > 0) { self->OutStream(self, '0'); width--; } } if (! ignoreNumber) { /* Output the number itself */ while (*(++pointer)) { self->OutStream(self, *pointer); } } /* Output trailing spaces if needed */ if (flags & FLAGS_LEFTADJUST) { while (width-- > 0) self->OutStream(self, CHAR_ADJUST); } } /************************************************************************* * TrioWriteStringCharacter * * Description: * Output a single character of a string */ TRIO_PRIVATE void TrioWriteStringCharacter TRIO_ARGS3((self, ch, flags), trio_class_t *self, int ch, trio_flags_t flags) { if (flags & FLAGS_ALTERNATIVE) { if (! isprint(ch)) { /* * Non-printable characters are converted to C escapes or * \number, if no C escape exists. */ self->OutStream(self, CHAR_BACKSLASH); switch (ch) { case '\007': self->OutStream(self, 'a'); break; case '\b': self->OutStream(self, 'b'); break; case '\f': self->OutStream(self, 'f'); break; case '\n': self->OutStream(self, 'n'); break; case '\r': self->OutStream(self, 'r'); break; case '\t': self->OutStream(self, 't'); break; case '\v': self->OutStream(self, 'v'); break; case '\\': self->OutStream(self, '\\'); break; default: self->OutStream(self, 'x'); TrioWriteNumber(self, (trio_uintmax_t)ch, FLAGS_UNSIGNED | FLAGS_NILPADDING, 2, 2, BASE_HEX); break; } } else if (ch == CHAR_BACKSLASH) { self->OutStream(self, CHAR_BACKSLASH); self->OutStream(self, CHAR_BACKSLASH); } else { self->OutStream(self, ch); } } else { self->OutStream(self, ch); } } /************************************************************************* * TrioWriteString * * Description: * Output a string */ TRIO_PRIVATE void TrioWriteString TRIO_ARGS5((self, string, flags, width, precision), trio_class_t *self, TRIO_CONST char *string, trio_flags_t flags, int width, int precision) { int length; int ch; assert(VALID(self)); assert(VALID(self->OutStream)); if (string == NULL) { string = internalNullString; length = sizeof(internalNullString) - 1; #if TRIO_FEATURE_QUOTE /* Disable quoting for the null pointer */ flags &= (~FLAGS_QUOTE); #endif width = 0; } else { if (precision == 0) { length = trio_length(string); } else { length = trio_length_max(string, precision); } } if ((NO_PRECISION != precision) && (precision < length)) { length = precision; } width -= length; #if TRIO_FEATURE_QUOTE if (flags & FLAGS_QUOTE) self->OutStream(self, CHAR_QUOTE); #endif if (! (flags & FLAGS_LEFTADJUST)) { while (width-- > 0) self->OutStream(self, CHAR_ADJUST); } while (length-- > 0) { /* The ctype parameters must be an unsigned char (or EOF) */ ch = (int)((unsigned char)(*string++)); TrioWriteStringCharacter(self, ch, flags); } if (flags & FLAGS_LEFTADJUST) { while (width-- > 0) self->OutStream(self, CHAR_ADJUST); } #if TRIO_FEATURE_QUOTE if (flags & FLAGS_QUOTE) self->OutStream(self, CHAR_QUOTE); #endif } /************************************************************************* * TrioWriteWideStringCharacter * * Description: * Output a wide string as a multi-byte sequence */ #if TRIO_FEATURE_WIDECHAR TRIO_PRIVATE int TrioWriteWideStringCharacter TRIO_ARGS4((self, wch, flags, width), trio_class_t *self, trio_wchar_t wch, trio_flags_t flags, int width) { int size; int i; int ch; char *string; char buffer[MB_LEN_MAX + 1]; if (width == NO_WIDTH) width = sizeof(buffer); size = wctomb(buffer, wch); if ((size <= 0) || (size > width) || (buffer[0] == NIL)) return 0; string = buffer; i = size; while ((width >= i) && (width-- > 0) && (i-- > 0)) { /* The ctype parameters must be an unsigned char (or EOF) */ ch = (int)((unsigned char)(*string++)); TrioWriteStringCharacter(self, ch, flags); } return size; } #endif /* TRIO_FEATURE_WIDECHAR */ /************************************************************************* * TrioWriteWideString * * Description: * Output a wide character string as a multi-byte string */ #if TRIO_FEATURE_WIDECHAR TRIO_PRIVATE void TrioWriteWideString TRIO_ARGS5((self, wstring, flags, width, precision), trio_class_t *self, TRIO_CONST trio_wchar_t *wstring, trio_flags_t flags, int width, int precision) { int length; int size; assert(VALID(self)); assert(VALID(self->OutStream)); #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) /* Required by TrioWriteWideStringCharacter */ (void)mblen(NULL, 0); #endif if (wstring == NULL) { TrioWriteString(self, NULL, flags, width, precision); return; } if (NO_PRECISION == precision) { length = INT_MAX; } else { length = precision; width -= length; } #if TRIO_FEATURE_QUOTE if (flags & FLAGS_QUOTE) self->OutStream(self, CHAR_QUOTE); #endif if (! (flags & FLAGS_LEFTADJUST)) { while (width-- > 0) self->OutStream(self, CHAR_ADJUST); } while (length > 0) { size = TrioWriteWideStringCharacter(self, *wstring++, flags, length); if (size == 0) break; /* while */ length -= size; } if (flags & FLAGS_LEFTADJUST) { while (width-- > 0) self->OutStream(self, CHAR_ADJUST); } #if TRIO_FEATURE_QUOTE if (flags & FLAGS_QUOTE) self->OutStream(self, CHAR_QUOTE); #endif } #endif /* TRIO_FEATURE_WIDECHAR */ /************************************************************************* * TrioWriteDouble * * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm * * "5.2.4.2.2 paragraph #4 * * The accuracy [...] is implementation defined, as is the accuracy * of the conversion between floating-point internal representations * and string representations performed by the libray routine in * " */ /* FIXME: handle all instances of constant long-double number (L) * and *l() math functions. */ #if TRIO_FEATURE_FLOAT TRIO_PRIVATE void TrioWriteDouble TRIO_ARGS6((self, number, flags, width, precision, base), trio_class_t *self, trio_long_double_t number, trio_flags_t flags, int width, int precision, int base) { trio_long_double_t integerNumber; trio_long_double_t fractionNumber; trio_long_double_t workNumber; int integerDigits; int fractionDigits; int exponentDigits; int workDigits; int baseDigits; int integerThreshold; int fractionThreshold; int expectedWidth; int exponent = 0; unsigned int uExponent = 0; int exponentBase; trio_long_double_t dblBase; trio_long_double_t dblFractionBase; trio_long_double_t integerAdjust; trio_long_double_t fractionAdjust; trio_long_double_t workFractionNumber; trio_long_double_t workFractionAdjust; int fractionDigitsInspect; BOOLEAN_T isNegative; BOOLEAN_T isExponentNegative = FALSE; BOOLEAN_T requireTwoDigitExponent; BOOLEAN_T isHex; TRIO_CONST char *digits; # if TRIO_FEATURE_QUOTE char *groupingPointer; # endif int i; int offset; BOOLEAN_T hasOnlyZeroes; int leadingFractionZeroes = -1; register int trailingZeroes; BOOLEAN_T keepTrailingZeroes; BOOLEAN_T keepDecimalPoint; trio_long_double_t epsilon; BOOLEAN_T adjustNumber = FALSE; assert(VALID(self)); assert(VALID(self->OutStream)); assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE)); /* Determine sign and look for special quantities */ switch (trio_fpclassify_and_signbit(number, &isNegative)) { case TRIO_FP_NAN: TrioWriteString(self, (flags & FLAGS_UPPER) ? NAN_UPPER : NAN_LOWER, flags, width, precision); return; case TRIO_FP_INFINITE: if (isNegative) { /* Negative infinity */ TrioWriteString(self, (flags & FLAGS_UPPER) ? "-" INFINITE_UPPER : "-" INFINITE_LOWER, flags, width, precision); return; } else { /* Positive infinity */ TrioWriteString(self, (flags & FLAGS_UPPER) ? INFINITE_UPPER : INFINITE_LOWER, flags, width, precision); return; } default: /* Finitude */ break; } /* Normal numbers */ if (flags & FLAGS_LONGDOUBLE) { baseDigits = (base == 10) ? LDBL_DIG : (int)trio_floor(LDBL_MANT_DIG / TrioLogarithmBase(base)); epsilon = LDBL_EPSILON; } else if (flags & FLAGS_SHORT) { baseDigits = (base == BASE_DECIMAL) ? FLT_DIG : (int)trio_floor(FLT_MANT_DIG / TrioLogarithmBase(base)); epsilon = FLT_EPSILON; } else { baseDigits = (base == BASE_DECIMAL) ? DBL_DIG : (int)trio_floor(DBL_MANT_DIG / TrioLogarithmBase(base)); epsilon = DBL_EPSILON; } digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower; isHex = (base == BASE_HEX); if (base == NO_BASE) base = BASE_DECIMAL; dblBase = (trio_long_double_t)base; keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) || ( (flags & FLAGS_FLOAT_G) && !(flags & FLAGS_ALTERNATIVE) ) ); # if TRIO_FEATURE_ROUNDING if (flags & FLAGS_ROUNDING) { precision = baseDigits; } # endif if (precision == NO_PRECISION) { if (isHex) { keepTrailingZeroes = FALSE; precision = FLT_MANT_DIG; } else { precision = FLT_DIG; } } if (isNegative) { number = -number; } if (isHex) { flags |= FLAGS_FLOAT_E; } reprocess: if (flags & FLAGS_FLOAT_G) { if (precision == 0) precision = 1; if ( (number < 1.0E-4) || (number >= trio_pow(base, (trio_long_double_t)precision)) ) { /* Use scientific notation */ flags |= FLAGS_FLOAT_E; } else if (number < 1.0) { /* * Use normal notation. If the integer part of the number is * zero, then adjust the precision to include leading fractional * zeros. */ workNumber = TrioLogarithm(number, base); workNumber = TRIO_FABS(workNumber); if (workNumber - trio_floor(workNumber) < epsilon) workNumber--; leadingFractionZeroes = (int)trio_floor(workNumber); } } if (flags & FLAGS_FLOAT_E) { /* Scale the number */ workNumber = TrioLogarithm(number, base); if (trio_isinf(workNumber) == -1) { exponent = 0; /* Undo setting */ if (flags & FLAGS_FLOAT_G) flags &= ~FLAGS_FLOAT_E; } else { exponent = (int)trio_floor(workNumber); /* * The expression A * 10^-B is equivalent to A / 10^B but the former * usually gives better accuracy. */ workNumber = number * trio_pow(dblBase, (trio_long_double_t)-exponent); if (trio_isinf(workNumber)) { workNumber = number / trio_pow(dblBase, (trio_long_double_t)exponent); } number = workNumber; isExponentNegative = (exponent < 0); uExponent = (isExponentNegative) ? -exponent : exponent; if (isHex) uExponent *= 4; /* log16(2) */ #if TRIO_FEATURE_QUOTE /* No thousand separators */ flags &= ~FLAGS_QUOTE; #endif } } integerNumber = trio_floor(number); fractionNumber = number - integerNumber; /* * Truncated number. * * Precision is number of significant digits for FLOAT_G and number of * fractional digits for others. */ integerDigits = 1; if (integerNumber > epsilon) { integerDigits += (int)TrioLogarithm(integerNumber, base); } fractionDigits = precision; if (flags & FLAGS_FLOAT_G) { if (leadingFractionZeroes > 0) { fractionDigits += leadingFractionZeroes; } if ((integerNumber > epsilon) || (number <= epsilon)) { fractionDigits -= integerDigits; } } dblFractionBase = TrioPower(base, fractionDigits); if (integerNumber < 1.0) { workNumber = number * dblFractionBase + 0.5; if (trio_floor(number * dblFractionBase) != trio_floor(workNumber)) { adjustNumber = TRUE; /* Remove a leading fraction zero if fraction is rounded up */ if ((int)TrioLogarithm(number * dblFractionBase, base) != (int)TrioLogarithm(workNumber, base)) { --leadingFractionZeroes; } } workNumber /= dblFractionBase; } else { workNumber = number + 0.5 / dblFractionBase; adjustNumber = (trio_floor(number) != trio_floor(workNumber)); } if (adjustNumber) { if ((flags & FLAGS_FLOAT_G) && !(flags & FLAGS_FLOAT_E)) { /* The adjustment may require a change to scientific notation */ if ( (workNumber < 1.0E-4) || (workNumber >= trio_pow(base, (trio_long_double_t)precision)) ) { /* Use scientific notation */ flags |= FLAGS_FLOAT_E; goto reprocess; } } if (flags & FLAGS_FLOAT_E) { workDigits = 1 + TrioLogarithm(trio_floor(workNumber), base); if (integerDigits == workDigits) { /* Adjust if the same number of digits are used */ number += 0.5 / dblFractionBase; integerNumber = trio_floor(number); fractionNumber = number - integerNumber; } else { /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */ exponent++; isExponentNegative = (exponent < 0); uExponent = (isExponentNegative) ? -exponent : exponent; if (isHex) uExponent *= 4; /* log16(2) */ workNumber = (number + 0.5 / dblFractionBase) / dblBase; integerNumber = trio_floor(workNumber); fractionNumber = workNumber - integerNumber; } } else { if (workNumber > 1.0) { /* Adjust if number was rounded up one digit (ie. 99 to 100) */ integerNumber = trio_floor(workNumber); fractionNumber = 0.0; integerDigits = (integerNumber > epsilon) ? 1 + (int)TrioLogarithm(integerNumber, base) : 1; if (flags & FLAGS_FLOAT_G) { if (flags & FLAGS_ALTERNATIVE) { if ((integerNumber > epsilon) || (number <= epsilon)) { fractionDigits -= integerDigits; } } else { fractionDigits = 0; } } } else { integerNumber = trio_floor(workNumber); fractionNumber = workNumber - integerNumber; if (flags & FLAGS_FLOAT_G) { if (flags & FLAGS_ALTERNATIVE) { fractionDigits = precision; if (leadingFractionZeroes > 0) { fractionDigits += leadingFractionZeroes; } if ((integerNumber > epsilon) || (number <= epsilon)) { fractionDigits -= integerDigits; } } } } } } /* Estimate accuracy */ integerAdjust = fractionAdjust = 0.5; # if TRIO_FEATURE_ROUNDING if (flags & FLAGS_ROUNDING) { if (integerDigits > baseDigits) { integerThreshold = baseDigits; fractionDigits = 0; dblFractionBase = 1.0; fractionThreshold = 0; precision = 0; /* Disable decimal-point */ integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1); fractionAdjust = 0.0; } else { integerThreshold = integerDigits; fractionThreshold = fractionDigits - integerThreshold; fractionAdjust = 1.0; } } else # endif { integerThreshold = INT_MAX; fractionThreshold = INT_MAX; } /* * Calculate expected width. * sign + integer part + thousands separators + decimal point * + fraction + exponent */ fractionAdjust /= dblFractionBase; hasOnlyZeroes = (trio_floor((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon); keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) || !((precision == 0) || (!keepTrailingZeroes && hasOnlyZeroes)) ); expectedWidth = integerDigits + fractionDigits; if (!keepTrailingZeroes) { trailingZeroes = 0; workFractionNumber = fractionNumber; workFractionAdjust = fractionAdjust; fractionDigitsInspect = fractionDigits; if (integerDigits > integerThreshold) { fractionDigitsInspect = 0; } else if (fractionThreshold <= fractionDigits) { fractionDigitsInspect = fractionThreshold + 1; } trailingZeroes = fractionDigits - fractionDigitsInspect; for (i = 0; i < fractionDigitsInspect; i++) { workFractionNumber *= dblBase; workFractionAdjust *= dblBase; workNumber = trio_floor(workFractionNumber + workFractionAdjust); workFractionNumber -= workNumber; offset = (int)trio_fmod(workNumber, dblBase); if (offset == 0) { trailingZeroes++; } else { trailingZeroes = 0; } } expectedWidth -= trailingZeroes; } if (keepDecimalPoint) { expectedWidth += internalDecimalPointLength; } #if TRIO_FEATURE_QUOTE if (flags & FLAGS_QUOTE) { expectedWidth += TrioCalcThousandSeparatorLength(integerDigits); } #endif if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) { expectedWidth += sizeof("-") - 1; } exponentDigits = 0; if (flags & FLAGS_FLOAT_E) { exponentDigits = (uExponent == 0) ? 1 : (int)trio_ceil(TrioLogarithm((double)(uExponent + 1), (isHex) ? 10 : base)); } requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1)); if (exponentDigits > 0) { expectedWidth += exponentDigits; expectedWidth += (requireTwoDigitExponent ? sizeof("E+0") - 1 : sizeof("E+") - 1); } if (isHex) { expectedWidth += sizeof("0X") - 1; } /* Output prefixing */ if (flags & FLAGS_NILPADDING) { /* Leading zeros must be after sign */ if (isNegative) self->OutStream(self, '-'); else if (flags & FLAGS_SHOWSIGN) self->OutStream(self, '+'); else if (flags & FLAGS_SPACE) self->OutStream(self, ' '); if (isHex) { self->OutStream(self, '0'); self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); } if (!(flags & FLAGS_LEFTADJUST)) { for (i = expectedWidth; i < width; i++) { self->OutStream(self, '0'); } } } else { /* Leading spaces must be before sign */ if (!(flags & FLAGS_LEFTADJUST)) { for (i = expectedWidth; i < width; i++) { self->OutStream(self, CHAR_ADJUST); } } if (isNegative) self->OutStream(self, '-'); else if (flags & FLAGS_SHOWSIGN) self->OutStream(self, '+'); else if (flags & FLAGS_SPACE) self->OutStream(self, ' '); if (isHex) { self->OutStream(self, '0'); self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); } } /* Output the integer part and thousand separators */ for (i = 0; i < integerDigits; i++) { workNumber = trio_floor(((integerNumber + integerAdjust) / TrioPower(base, integerDigits - i - 1))); if (i > integerThreshold) { /* Beyond accuracy */ self->OutStream(self, digits[0]); } else { self->OutStream(self, digits[(int)trio_fmod(workNumber, dblBase)]); } #if TRIO_FEATURE_QUOTE if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE) && TrioFollowedBySeparator(integerDigits - i)) { for (groupingPointer = internalThousandSeparator; *groupingPointer != NIL; groupingPointer++) { self->OutStream(self, *groupingPointer); } } #endif } /* Insert decimal point and build the fraction part */ trailingZeroes = 0; if (keepDecimalPoint) { if (internalDecimalPoint) { self->OutStream(self, internalDecimalPoint); } else { for (i = 0; i < internalDecimalPointLength; i++) { self->OutStream(self, internalDecimalPointString[i]); } } } for (i = 0; i < fractionDigits; i++) { if ((integerDigits > integerThreshold) || (i > fractionThreshold)) { /* Beyond accuracy */ trailingZeroes++; } else { fractionNumber *= dblBase; fractionAdjust *= dblBase; workNumber = trio_floor(fractionNumber + fractionAdjust); if (workNumber > fractionNumber) { /* fractionNumber should never become negative */ fractionNumber = 0.0; fractionAdjust = 0.0; } else { fractionNumber -= workNumber; } offset = (int)trio_fmod(workNumber, dblBase); if (offset == 0) { trailingZeroes++; } else { while (trailingZeroes > 0) { /* Not trailing zeroes after all */ self->OutStream(self, digits[0]); trailingZeroes--; } self->OutStream(self, digits[offset]); } } } if (keepTrailingZeroes) { while (trailingZeroes > 0) { self->OutStream(self, digits[0]); trailingZeroes--; } } /* Output exponent */ if (exponentDigits > 0) { self->OutStream(self, isHex ? ((flags & FLAGS_UPPER) ? 'P' : 'p') : ((flags & FLAGS_UPPER) ? 'E' : 'e')); self->OutStream(self, (isExponentNegative) ? '-' : '+'); /* The exponent must contain at least two digits */ if (requireTwoDigitExponent) self->OutStream(self, '0'); if (isHex) base = 10; exponentBase = (int)TrioPower(base, exponentDigits - 1); for (i = 0; i < exponentDigits; i++) { self->OutStream(self, digits[(uExponent / exponentBase) % base]); exponentBase /= base; } } /* Output trailing spaces */ if (flags & FLAGS_LEFTADJUST) { for (i = expectedWidth; i < width; i++) { self->OutStream(self, CHAR_ADJUST); } } } #endif /* TRIO_FEATURE_FLOAT */ /************************************************************************* * TrioFormatProcess * * Description: * This is the main engine for formatting output */ TRIO_PRIVATE int TrioFormatProcess TRIO_ARGS3((data, format, parameters), trio_class_t *data, TRIO_CONST char *format, trio_parameter_t *parameters) { int i; #if TRIO_FEATURE_ERRNO TRIO_CONST char *string; #endif trio_pointer_t pointer; trio_flags_t flags; int width; int precision; int base; int offset; offset = 0; i = 0; for (;;) { /* Skip the parameter entries */ while (parameters[i].type == FORMAT_PARAMETER) i++; /* Copy non conversion-specifier part of format string */ while (offset < parameters[i].beginOffset) { if (CHAR_IDENTIFIER == format[offset] && CHAR_IDENTIFIER == format[offset + 1]) { data->OutStream(data, CHAR_IDENTIFIER); offset += 2; } else { data->OutStream(data, format[offset++]); } } /* Abort if we reached end of format string */ if (parameters[i].type == FORMAT_SENTINEL) break; /* Ouput parameter */ flags = parameters[i].flags; /* Find width */ width = parameters[i].width; if (flags & FLAGS_WIDTH_PARAMETER) { /* Get width from parameter list */ width = (int)parameters[width].data.number.as_signed; if (width < 0) { /* * A negative width is the same as the - flag and * a positive width. */ flags |= FLAGS_LEFTADJUST; flags &= ~FLAGS_NILPADDING; width = -width; } } /* Find precision */ if (flags & FLAGS_PRECISION) { precision = parameters[i].precision; if (flags & FLAGS_PRECISION_PARAMETER) { /* Get precision from parameter list */ precision = (int)parameters[precision].data.number.as_signed; if (precision < 0) { /* * A negative precision is the same as no * precision */ precision = NO_PRECISION; } } } else { precision = NO_PRECISION; } /* Find base */ if (NO_BASE != parameters[i].baseSpecifier) { /* Base from specifier has priority */ base = parameters[i].baseSpecifier; } else if (flags & FLAGS_BASE_PARAMETER) { /* Get base from parameter list */ base = parameters[i].base; base = (int)parameters[base].data.number.as_signed; } else { /* Use base from format string */ base = parameters[i].base; } switch (parameters[i].type) { case FORMAT_CHAR: #if TRIO_FEATURE_QUOTE if (flags & FLAGS_QUOTE) data->OutStream(data, CHAR_QUOTE); #endif if (! (flags & FLAGS_LEFTADJUST)) { while (--width > 0) data->OutStream(data, CHAR_ADJUST); } #if TRIO_FEATURE_WIDECHAR if (flags & FLAGS_WIDECHAR) { TrioWriteWideStringCharacter(data, (trio_wchar_t)parameters[i].data.number.as_signed, flags, NO_WIDTH); } else #endif { TrioWriteStringCharacter(data, (int)parameters[i].data.number.as_signed, flags); } if (flags & FLAGS_LEFTADJUST) { while(--width > 0) data->OutStream(data, CHAR_ADJUST); } #if TRIO_FEATURE_QUOTE if (flags & FLAGS_QUOTE) data->OutStream(data, CHAR_QUOTE); #endif break; /* FORMAT_CHAR */ case FORMAT_INT: TrioWriteNumber(data, parameters[i].data.number.as_unsigned, flags, width, precision, base); break; /* FORMAT_INT */ #if TRIO_FEATURE_FLOAT case FORMAT_DOUBLE: TrioWriteDouble(data, parameters[i].data.longdoubleNumber, flags, width, precision, base); break; /* FORMAT_DOUBLE */ #endif case FORMAT_STRING: #if TRIO_FEATURE_WIDECHAR if (flags & FLAGS_WIDECHAR) { TrioWriteWideString(data, parameters[i].data.wstring, flags, width, precision); } else #endif { TrioWriteString(data, parameters[i].data.string, flags, width, precision); } break; /* FORMAT_STRING */ case FORMAT_POINTER: { trio_reference_t reference; reference.data = data; reference.parameter = ¶meters[i]; trio_print_pointer(&reference, parameters[i].data.pointer); } break; /* FORMAT_POINTER */ case FORMAT_COUNT: pointer = parameters[i].data.pointer; if (NULL != pointer) { /* * C99 paragraph 7.19.6.1.8 says "the number of * characters written to the output stream so far by * this call", which is data->committed */ #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER if (flags & FLAGS_SIZE_T) *(size_t *)pointer = (size_t)data->committed; else #endif #if TRIO_FEATURE_PTRDIFF_T if (flags & FLAGS_PTRDIFF_T) *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed; else #endif #if TRIO_FEATURE_INTMAX_T if (flags & FLAGS_INTMAX_T) *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed; else #endif if (flags & FLAGS_QUAD) { *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed; } else if (flags & FLAGS_LONG) { *(long int *)pointer = (long int)data->committed; } else if (flags & FLAGS_SHORT) { *(short int *)pointer = (short int)data->committed; } else { *(int *)pointer = (int)data->committed; } } break; /* FORMAT_COUNT */ case FORMAT_PARAMETER: break; /* FORMAT_PARAMETER */ #if TRIO_FEATURE_ERRNO case FORMAT_ERRNO: string = trio_error(parameters[i].data.errorNumber); if (string) { TrioWriteString(data, string, flags, width, precision); } else { data->OutStream(data, '#'); TrioWriteNumber(data, (trio_uintmax_t)parameters[i].data.errorNumber, flags, width, precision, BASE_DECIMAL); } break; /* FORMAT_ERRNO */ #endif /* TRIO_FEATURE_ERRNO */ #if TRIO_FEATURE_USER_DEFINED case FORMAT_USER_DEFINED: { trio_reference_t reference; trio_userdef_t *def = NULL; if (parameters[i].flags & FLAGS_USER_DEFINED_PARAMETER) { /* Use handle */ if ((i > 0) || (parameters[i - 1].type == FORMAT_PARAMETER)) def = (trio_userdef_t *)parameters[i - 1].data.pointer; } else { /* Look up namespace */ def = TrioFindNamespace(parameters[i].user_defined.namespace, NULL); } if (def) { reference.data = data; reference.parameter = ¶meters[i]; def->callback(&reference); } } break; #endif /* TRIO_FEATURE_USER_DEFINED */ default: break; } /* switch parameter type */ /* Prepare for next */ offset = parameters[i].endOffset; i++; } return data->processed; } /************************************************************************* * TrioFormatRef */ #if TRIO_EXTENSION TRIO_PRIVATE int TrioFormatRef TRIO_ARGS4((reference, format, arglist, argarray), trio_reference_t *reference, TRIO_CONST char *format, va_list arglist, trio_pointer_t *argarray) { int status; trio_parameter_t parameters[MAX_PARAMETERS]; status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray); if (status < 0) return status; status = TrioFormatProcess(reference->data, format, parameters); if (reference->data->error != 0) { status = reference->data->error; } return status; } #endif /* TRIO_EXTENSION */ /************************************************************************* * TrioFormat */ TRIO_PRIVATE int TrioFormat TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray), trio_pointer_t destination, size_t destinationSize, void (*OutStream) TRIO_PROTO((trio_class_t *, int)), TRIO_CONST char *format, va_list arglist, trio_pointer_t *argarray) { int status; trio_class_t data; trio_parameter_t parameters[MAX_PARAMETERS]; assert(VALID(OutStream)); assert(VALID(format)); memset(&data, 0, sizeof(data)); data.OutStream = OutStream; data.location = destination; data.max = destinationSize; data.error = 0; #if defined(USE_LOCALE) if (NULL == internalLocaleValues) { TrioSetLocale(); } #endif status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray); if (status < 0) return status; status = TrioFormatProcess(&data, format, parameters); if (data.error != 0) { status = data.error; } return status; } /************************************************************************* * TrioOutStreamFile */ #if TRIO_FEATURE_FILE || TRIO_FEATURE_STDIO TRIO_PRIVATE void TrioOutStreamFile TRIO_ARGS2((self, output), trio_class_t *self, int output) { FILE *file; assert(VALID(self)); assert(VALID(self->location)); file = (FILE *)self->location; self->processed++; if (fputc(output, file) == EOF) { self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0); } else { self->committed++; } } #endif /* TRIO_FEATURE_FILE || TRIO_FEATURE_STDIO */ /************************************************************************* * TrioOutStreamFileDescriptor */ #if TRIO_FEATURE_FD TRIO_PRIVATE void TrioOutStreamFileDescriptor TRIO_ARGS2((self, output), trio_class_t *self, int output) { int fd; char ch; assert(VALID(self)); fd = *((int *)self->location); ch = (char)output; self->processed++; if (write(fd, &ch, sizeof(char)) == -1) { self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0); } else { self->committed++; } } #endif /* TRIO_FEATURE_FD */ /************************************************************************* * TrioOutStreamCustom */ #if TRIO_FEATURE_CLOSURE TRIO_PRIVATE void TrioOutStreamCustom TRIO_ARGS2((self, output), trio_class_t *self, int output) { int status; trio_custom_t *data; assert(VALID(self)); assert(VALID(self->location)); data = (trio_custom_t *)self->location; if (data->stream.out) { status = (data->stream.out)(data->closure, output); if (status >= 0) { self->committed++; } else { if (self->error == 0) { self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status); } } } self->processed++; } #endif /* TRIO_FEATURE_CLOSURE */ /************************************************************************* * TrioOutStreamString */ TRIO_PRIVATE void TrioOutStreamString TRIO_ARGS2((self, output), trio_class_t *self, int output) { char **buffer; assert(VALID(self)); assert(VALID(self->location)); buffer = (char **)self->location; **buffer = (char)output; (*buffer)++; self->processed++; self->committed++; } /************************************************************************* * TrioOutStreamStringMax */ TRIO_PRIVATE void TrioOutStreamStringMax TRIO_ARGS2((self, output), trio_class_t *self, int output) { char **buffer; assert(VALID(self)); assert(VALID(self->location)); buffer = (char **)self->location; if (self->processed < self->max) { **buffer = (char)output; (*buffer)++; self->committed++; } self->processed++; } /************************************************************************* * TrioOutStreamStringDynamic */ #if TRIO_FEATURE_DYNAMICSTRING TRIO_PRIVATE void TrioOutStreamStringDynamic TRIO_ARGS2((self, output), trio_class_t *self, int output) { assert(VALID(self)); assert(VALID(self->location)); if (self->error == 0) { trio_xstring_append_char((trio_string_t *)self->location, (char)output); self->committed++; } /* The processed variable must always be increased */ self->processed++; } #endif /* TRIO_FEATURE_DYNAMICSTRING */ /************************************************************************* * * Formatted printing functions * ************************************************************************/ #if defined(TRIO_DOCUMENTATION) # include "doc/doc_printf.h" #endif /** @addtogroup Printf @{ */ /************************************************************************* * printf */ /** Print to standard output stream. @param format Formatting string. @param ... Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_STDIO TRIO_PUBLIC int printf TRIO_VARGS2((format, va_alist), TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(format)); TRIO_VA_START(args, format); status = TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL); TRIO_VA_END(args); fflush( stdout ); return status; } #endif /* TRIO_FEATURE_STDIO */ /** Print to standard output stream. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_STDIO TRIO_PUBLIC int vprintf TRIO_ARGS2((format, args), TRIO_CONST char *format, va_list args) { int ret; assert(VALID(format)); ret = TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL); fflush( stdout ); return ret; } #endif /* TRIO_FEATURE_STDIO */ /** Print to standard output stream. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_STDIO TRIO_PUBLIC int trio_printfv TRIO_ARGS2((format, args), TRIO_CONST char *format, trio_pointer_t * args) { static va_list unused; assert(VALID(format)); return TrioFormat(stdout, 0, TrioOutStreamFile, format, unused, args); } #endif /* TRIO_FEATURE_STDIO */ /************************************************************************* * fprintf */ /** Print to file. @param file File pointer. @param format Formatting string. @param ... Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_FILE TRIO_PUBLIC int fprintf TRIO_VARGS3((file, format, va_alist), FILE *file, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(file)); assert(VALID(format)); TRIO_VA_START(args, format); status = TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL); TRIO_VA_END(args); return status; } #endif /* TRIO_FEATURE_FILE */ /** Print to file. @param file File pointer. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_FILE TRIO_PUBLIC int vfprintf TRIO_ARGS3((file, format, args), FILE *file, TRIO_CONST char *format, va_list args) { assert(VALID(file)); assert(VALID(format)); return TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL); } #endif /* TRIO_FEATURE_FILE */ /** Print to file. @param file File pointer. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_FILE TRIO_PUBLIC int trio_fprintfv TRIO_ARGS3((file, format, args), FILE *file, TRIO_CONST char *format, trio_pointer_t * args) { static va_list unused; assert(VALID(file)); assert(VALID(format)); return TrioFormat(file, 0, TrioOutStreamFile, format, unused, args); } #endif /* TRIO_FEATURE_FILE */ /************************************************************************* * dprintf */ /** Print to file descriptor. @param fd File descriptor. @param format Formatting string. @param ... Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_FD TRIO_PUBLIC int trio_dprintf TRIO_VARGS3((fd, format, va_alist), int fd, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(format)); TRIO_VA_START(args, format); status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL); TRIO_VA_END(args); return status; } #endif /* TRIO_FEATURE_FD */ /** Print to file descriptor. @param fd File descriptor. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_FD TRIO_PUBLIC int trio_vdprintf TRIO_ARGS3((fd, format, args), int fd, TRIO_CONST char *format, va_list args) { assert(VALID(format)); return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL); } #endif /* TRIO_FEATURE_FD */ /** Print to file descriptor. @param fd File descriptor. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_FD TRIO_PUBLIC int trio_dprintfv TRIO_ARGS3((fd, format, args), int fd, TRIO_CONST char *format, trio_pointer_t *args) { static va_list unused; assert(VALID(format)); return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, unused, args); } #endif /* TRIO_FEATURE_FD */ /************************************************************************* * cprintf */ #if TRIO_FEATURE_CLOSURE TRIO_PUBLIC int trio_cprintf TRIO_VARGS4((stream, closure, format, va_alist), trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; trio_custom_t data; assert(VALID(stream)); assert(VALID(format)); TRIO_VA_START(args, format); data.stream.out = stream; data.closure = closure; status = TrioFormat(&data, 0, TrioOutStreamCustom, format, args, NULL); TRIO_VA_END(args); return status; } #endif /* TRIO_FEATURE_CLOSURE */ #if TRIO_FEATURE_CLOSURE TRIO_PUBLIC int trio_vcprintf TRIO_ARGS4((stream, closure, format, args), trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, va_list args) { trio_custom_t data; assert(VALID(stream)); assert(VALID(format)); data.stream.out = stream; data.closure = closure; return TrioFormat(&data, 0, TrioOutStreamCustom, format, args, NULL); } #endif /* TRIO_FEATURE_CLOSURE */ #if TRIO_FEATURE_CLOSURE TRIO_PUBLIC int trio_cprintfv TRIO_ARGS4((stream, closure, format, args), trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, void **args) { static va_list unused; trio_custom_t data; assert(VALID(stream)); assert(VALID(format)); data.stream.out = stream; data.closure = closure; return TrioFormat(&data, 0, TrioOutStreamCustom, format, unused, args); } #endif /* TRIO_FEATURE_CLOSURE */ /************************************************************************* * sprintf */ /** Print to string. @param buffer Output string. @param format Formatting string. @param ... Arguments. @return Number of printed characters. */ TRIO_PUBLIC int sprintf TRIO_VARGS3((buffer, format, va_alist), char *buffer, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(buffer)); assert(VALID(format)); TRIO_VA_START(args, format); status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL); *buffer = NIL; /* Terminate with NIL character */ TRIO_VA_END(args); return status; } /** Print to string. @param buffer Output string. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ TRIO_PUBLIC int vsprintf TRIO_ARGS3((buffer, format, args), char *buffer, TRIO_CONST char *format, va_list args) { int status; assert(VALID(buffer)); assert(VALID(format)); status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL); *buffer = NIL; return status; } /** Print to string. @param buffer Output string. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ TRIO_PUBLIC int trio_sprintfv TRIO_ARGS3((buffer, format, args), char *buffer, TRIO_CONST char *format, trio_pointer_t *args) { static va_list unused; int status; assert(VALID(buffer)); assert(VALID(format)); status = TrioFormat(&buffer, 0, TrioOutStreamString, format, unused, args); *buffer = NIL; return status; } /************************************************************************* * snprintf */ /** Print at most @p max characters to string. @param buffer Output string. @param max Maximum number of characters to print. @param format Formatting string. @param ... Arguments. @return Number of printed characters. */ TRIO_PUBLIC int snprintf TRIO_VARGS4((buffer, max, format, va_alist), char *buffer, size_t max, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(buffer)); assert(VALID(format)); TRIO_VA_START(args, format); status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, TrioOutStreamStringMax, format, args, NULL); if (max > 0) *buffer = NIL; TRIO_VA_END(args); return status; } /** Print at most @p max characters to string. @param buffer Output string. @param max Maximum number of characters to print. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ TRIO_PUBLIC int vsnprintf TRIO_ARGS4((buffer, max, format, args), char *buffer, size_t max, TRIO_CONST char *format, va_list args) { int status; assert(VALID(buffer)); assert(VALID(format)); status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, TrioOutStreamStringMax, format, args, NULL); if (max > 0) *buffer = NIL; return status; } /** Print at most @p max characters to string. @param buffer Output string. @param max Maximum number of characters to print. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ TRIO_PUBLIC int trio_snprintfv TRIO_ARGS4((buffer, max, format, args), char *buffer, size_t max, TRIO_CONST char *format, trio_pointer_t *args) { static va_list unused; int status; assert(VALID(buffer)); assert(VALID(format)); status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, TrioOutStreamStringMax, format, unused, args); if (max > 0) *buffer = NIL; return status; } /************************************************************************* * snprintfcat * Appends the new string to the buffer string overwriting the '\0' * character at the end of buffer. */ #if TRIO_EXTENSION TRIO_PUBLIC int trio_snprintfcat TRIO_VARGS4((buffer, max, format, va_alist), char *buffer, size_t max, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; size_t buf_len; TRIO_VA_START(args, format); assert(VALID(buffer)); assert(VALID(format)); buf_len = trio_length(buffer); buffer = &buffer[buf_len]; status = TrioFormat(&buffer, max - 1 - buf_len, TrioOutStreamStringMax, format, args, NULL); TRIO_VA_END(args); *buffer = NIL; return status; } #endif #if TRIO_EXTENSION TRIO_PUBLIC int trio_vsnprintfcat TRIO_ARGS4((buffer, max, format, args), char *buffer, size_t max, TRIO_CONST char *format, va_list args) { int status; size_t buf_len; assert(VALID(buffer)); assert(VALID(format)); buf_len = trio_length(buffer); buffer = &buffer[buf_len]; status = TrioFormat(&buffer, max - 1 - buf_len, TrioOutStreamStringMax, format, args, NULL); *buffer = NIL; return status; } #endif /************************************************************************* * trio_aprintf */ #if TRIO_DEPRECATED && TRIO_FEATURE_DYNAMICSTRING TRIO_PUBLIC char * trio_aprintf TRIO_VARGS2((format, va_alist), TRIO_CONST char *format, TRIO_VA_DECL) { va_list args; trio_string_t *info; char *result = NULL; assert(VALID(format)); info = trio_xstring_duplicate(""); if (info) { TRIO_VA_START(args, format); (void)TrioFormat(info, 0, TrioOutStreamStringDynamic, format, args, NULL); TRIO_VA_END(args); trio_string_terminate(info); result = trio_string_extract(info); trio_string_destroy(info); } return result; } #endif /* TRIO_DEPRECATED && TRIO_FEATURE_DYNAMICSTRING */ #if TRIO_DEPRECATED && TRIO_FEATURE_DYNAMICSTRING TRIO_PUBLIC char * trio_vaprintf TRIO_ARGS2((format, args), TRIO_CONST char *format, va_list args) { trio_string_t *info; char *result = NULL; assert(VALID(format)); info = trio_xstring_duplicate(""); if (info) { (void)TrioFormat(info, 0, TrioOutStreamStringDynamic, format, args, NULL); trio_string_terminate(info); result = trio_string_extract(info); trio_string_destroy(info); } return result; } #endif /* TRIO_DEPRECATED && TRIO_FEATURE_DYNAMICSTRING */ /** Allocate and print to string. The memory allocated and returned by @p result must be freed by the calling application. @param result Output string. @param format Formatting string. @param ... Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_DYNAMICSTRING TRIO_PUBLIC int asprintf TRIO_VARGS3((result, format, va_alist), char **result, TRIO_CONST char *format, TRIO_VA_DECL) { va_list args; int status; trio_string_t *info; assert(VALID(format)); *result = NULL; info = trio_xstring_duplicate(""); if (info == NULL) { status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0); } else { TRIO_VA_START(args, format); status = TrioFormat(info, 0, TrioOutStreamStringDynamic, format, args, NULL); TRIO_VA_END(args); if (status >= 0) { trio_string_terminate(info); *result = trio_string_extract(info); } trio_string_destroy(info); } return status; } #endif /* TRIO_FEATURE_DYNAMICSTRING */ /** Allocate and print to string. The memory allocated and returned by @p result must be freed by the calling application. @param result Output string. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_DYNAMICSTRING TRIO_PUBLIC int trio_vasprintf TRIO_ARGS3((result, format, args), char **result, TRIO_CONST char *format, va_list args) { int status; trio_string_t *info; assert(VALID(format)); *result = NULL; info = trio_xstring_duplicate(""); if (info == NULL) { status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0); } else { status = TrioFormat(info, 0, TrioOutStreamStringDynamic, format, args, NULL); if (status >= 0) { trio_string_terminate(info); *result = trio_string_extract(info); } trio_string_destroy(info); } return status; } #endif /* TRIO_FEATURE_DYNAMICSTRING */ /** Allocate and print to string. The memory allocated and returned by @p result must be freed by the calling application. @param result Output string. @param format Formatting string. @param args Arguments. @return Number of printed characters. */ #if TRIO_FEATURE_DYNAMICSTRING TRIO_PUBLIC int trio_asprintfv TRIO_ARGS3((result, format, args), char **result, TRIO_CONST char *format, trio_pointer_t * args) { static va_list unused; int status; trio_string_t *info; assert(VALID(format)); *result = NULL; info = trio_xstring_duplicate(""); if (info == NULL) { status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0); } else { status = TrioFormat(info, 0, TrioOutStreamStringDynamic, format, unused, args); if (status >= 0) { trio_string_terminate(info); *result = trio_string_extract(info); } trio_string_destroy(info); } return status; } #endif /* TRIO_FEATURE_DYNAMICSTRING */ /** @} End of Printf documentation module */ /************************************************************************* * * CALLBACK * ************************************************************************/ #if defined(TRIO_DOCUMENTATION) # include "doc/doc_register.h" #endif /** @addtogroup UserDefined @{ */ #if TRIO_FEATURE_USER_DEFINED /************************************************************************* * trio_register */ /** Register new user-defined specifier. @param callback @param name @return Handle. */ TRIO_PUBLIC trio_pointer_t trio_register TRIO_ARGS2((callback, name), trio_callback_t callback, TRIO_CONST char *name) { trio_userdef_t *def; trio_userdef_t *prev = NULL; if (callback == NULL) return NULL; if (name) { /* Handle built-in namespaces */ if (name[0] == ':') { if (trio_equal(name, ":enter")) { internalEnterCriticalRegion = callback; } else if (trio_equal(name, ":leave")) { internalLeaveCriticalRegion = callback; } return NULL; } /* Bail out if namespace is too long */ if (trio_length(name) >= MAX_USER_NAME) return NULL; /* Bail out if namespace already is registered */ def = TrioFindNamespace(name, &prev); if (def) return NULL; } def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t)); if (def) { if (internalEnterCriticalRegion) (void)internalEnterCriticalRegion(NULL); if (name) { /* Link into internal list */ if (prev == NULL) internalUserDef = def; else prev->next = def; } /* Initialize */ def->callback = callback; def->name = (name == NULL) ? NULL : trio_duplicate(name); def->next = NULL; if (internalLeaveCriticalRegion) (void)internalLeaveCriticalRegion(NULL); } return (trio_pointer_t)def; } /** Unregister an existing user-defined specifier. @param handle */ void trio_unregister TRIO_ARGS1((handle), trio_pointer_t handle) { trio_userdef_t *self = (trio_userdef_t *)handle; trio_userdef_t *def; trio_userdef_t *prev = NULL; assert(VALID(self)); if (self->name) { def = TrioFindNamespace(self->name, &prev); if (def) { if (internalEnterCriticalRegion) (void)internalEnterCriticalRegion(NULL); if (prev == NULL) internalUserDef = internalUserDef->next; else prev->next = def->next; if (internalLeaveCriticalRegion) (void)internalLeaveCriticalRegion(NULL); } trio_destroy(self->name); } TRIO_FREE(self); } /************************************************************************* * trio_get_format [public] */ TRIO_CONST char * trio_get_format TRIO_ARGS1((ref), trio_pointer_t ref) { #if TRIO_FEATURE_USER_DEFINED assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED); #endif return (((trio_reference_t *)ref)->parameter->user_data); } /************************************************************************* * trio_get_argument [public] */ trio_pointer_t trio_get_argument TRIO_ARGS1((ref), trio_pointer_t ref) { #if TRIO_FEATURE_USER_DEFINED assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED); #endif return ((trio_reference_t *)ref)->parameter->data.pointer; } /************************************************************************* * trio_get_width / trio_set_width [public] */ int trio_get_width TRIO_ARGS1((ref), trio_pointer_t ref) { return ((trio_reference_t *)ref)->parameter->width; } void trio_set_width TRIO_ARGS2((ref, width), trio_pointer_t ref, int width) { ((trio_reference_t *)ref)->parameter->width = width; } /************************************************************************* * trio_get_precision / trio_set_precision [public] */ int trio_get_precision TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->precision); } void trio_set_precision TRIO_ARGS2((ref, precision), trio_pointer_t ref, int precision) { ((trio_reference_t *)ref)->parameter->precision = precision; } /************************************************************************* * trio_get_base / trio_set_base [public] */ int trio_get_base TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->base); } void trio_set_base TRIO_ARGS2((ref, base), trio_pointer_t ref, int base) { ((trio_reference_t *)ref)->parameter->base = base; } /************************************************************************* * trio_get_long / trio_set_long [public] */ int trio_get_long TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG) ? TRUE : FALSE; } void trio_set_long TRIO_ARGS2((ref, is_long), trio_pointer_t ref, int is_long) { if (is_long) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG; } /************************************************************************* * trio_get_longlong / trio_set_longlong [public] */ int trio_get_longlong TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD) ? TRUE : FALSE; } void trio_set_longlong TRIO_ARGS2((ref, is_longlong), trio_pointer_t ref, int is_longlong) { if (is_longlong) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD; } /************************************************************************* * trio_get_longdouble / trio_set_longdouble [public] */ # if TRIO_FEATURE_FLOAT int trio_get_longdouble TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE) ? TRUE : FALSE; } void trio_set_longdouble TRIO_ARGS2((ref, is_longdouble), trio_pointer_t ref, int is_longdouble) { if (is_longdouble) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE; } # endif /* TRIO_FEATURE_FLOAT */ /************************************************************************* * trio_get_short / trio_set_short [public] */ int trio_get_short TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT) ? TRUE : FALSE; } void trio_set_short TRIO_ARGS2((ref, is_short), trio_pointer_t ref, int is_short) { if (is_short) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT; } /************************************************************************* * trio_get_shortshort / trio_set_shortshort [public] */ int trio_get_shortshort TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT) ? TRUE : FALSE; } void trio_set_shortshort TRIO_ARGS2((ref, is_shortshort), trio_pointer_t ref, int is_shortshort) { if (is_shortshort) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT; } /************************************************************************* * trio_get_alternative / trio_set_alternative [public] */ int trio_get_alternative TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE) ? TRUE : FALSE; } void trio_set_alternative TRIO_ARGS2((ref, is_alternative), trio_pointer_t ref, int is_alternative) { if (is_alternative) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE; } /************************************************************************* * trio_get_alignment / trio_set_alignment [public] */ int trio_get_alignment TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST) ? TRUE : FALSE; } void trio_set_alignment TRIO_ARGS2((ref, is_leftaligned), trio_pointer_t ref, int is_leftaligned) { if (is_leftaligned) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST; } /************************************************************************* * trio_get_spacing /trio_set_spacing [public] */ int trio_get_spacing TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE) ? TRUE : FALSE; } void trio_set_spacing TRIO_ARGS2((ref, is_space), trio_pointer_t ref, int is_space) { if (is_space) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE; } /************************************************************************* * trio_get_sign / trio_set_sign [public] */ int trio_get_sign TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN) ? TRUE : FALSE; } void trio_set_sign TRIO_ARGS2((ref, is_sign), trio_pointer_t ref, int is_sign) { if (is_sign) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN; } /************************************************************************* * trio_get_padding / trio_set_padding [public] */ int trio_get_padding TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING) ? TRUE : FALSE; } void trio_set_padding TRIO_ARGS2((ref, is_padding), trio_pointer_t ref, int is_padding) { if (is_padding) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING; } /************************************************************************* * trio_get_quote / trio_set_quote [public] */ # if TRIO_FEATURE_QUOTE int trio_get_quote TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE) ? TRUE : FALSE; } void trio_set_quote TRIO_ARGS2((ref, is_quote), trio_pointer_t ref, int is_quote) { if (is_quote) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE; } #endif /* TRIO_FEATURE_QUOTE */ /************************************************************************* * trio_get_upper / trio_set_upper [public] */ int trio_get_upper TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER) ? TRUE : FALSE; } void trio_set_upper TRIO_ARGS2((ref, is_upper), trio_pointer_t ref, int is_upper) { if (is_upper) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER; } /************************************************************************* * trio_get_largest / trio_set_largest [public] */ #if TRIO_FEATURE_INTMAX_T int trio_get_largest TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T) ? TRUE : FALSE; } void trio_set_largest TRIO_ARGS2((ref, is_largest), trio_pointer_t ref, int is_largest) { if (is_largest) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T; } #endif /* TRIO_FEATURE_INTMAX_T */ /************************************************************************* * trio_get_ptrdiff / trio_set_ptrdiff [public] */ #if TRIO_FEATURE_PTRDIFF_T int trio_get_ptrdiff TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T) ? TRUE : FALSE; } void trio_set_ptrdiff TRIO_ARGS2((ref, is_ptrdiff), trio_pointer_t ref, int is_ptrdiff) { if (is_ptrdiff) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T; } #endif /* TRIO_FEATURE_PTRDIFF_T */ /************************************************************************* * trio_get_size / trio_set_size [public] */ #if TRIO_FEATURE_SIZE_T int trio_get_size TRIO_ARGS1((ref), trio_pointer_t ref) { return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T) ? TRUE : FALSE; } void trio_set_size TRIO_ARGS2((ref, is_size), trio_pointer_t ref, int is_size) { if (is_size) ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T; else ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T; } #endif /* TRIO_FEATURE_SIZE_T */ /************************************************************************* * trio_print_int [public] */ void trio_print_int TRIO_ARGS2((ref, number), trio_pointer_t ref, int number) { trio_reference_t *self = (trio_reference_t *)ref; TrioWriteNumber(self->data, (trio_uintmax_t)number, self->parameter->flags, self->parameter->width, self->parameter->precision, self->parameter->base); } /************************************************************************* * trio_print_uint [public] */ void trio_print_uint TRIO_ARGS2((ref, number), trio_pointer_t ref, unsigned int number) { trio_reference_t *self = (trio_reference_t *)ref; TrioWriteNumber(self->data, (trio_uintmax_t)number, self->parameter->flags | FLAGS_UNSIGNED, self->parameter->width, self->parameter->precision, self->parameter->base); } /************************************************************************* * trio_print_double [public] */ #if TRIO_FEATURE_FLOAT void trio_print_double TRIO_ARGS2((ref, number), trio_pointer_t ref, double number) { trio_reference_t *self = (trio_reference_t *)ref; TrioWriteDouble(self->data, number, self->parameter->flags, self->parameter->width, self->parameter->precision, self->parameter->base); } #endif /* TRIO_FEATURE_FLOAT */ /************************************************************************* * trio_print_string [public] */ void trio_print_string TRIO_ARGS2((ref, string), trio_pointer_t ref, char *string) { trio_reference_t *self = (trio_reference_t *)ref; TrioWriteString(self->data, string, self->parameter->flags, self->parameter->width, self->parameter->precision); } /************************************************************************* * trio_print_ref [public] */ int trio_print_ref TRIO_VARGS3((ref, format, va_alist), trio_pointer_t ref, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list arglist; assert(VALID(format)); TRIO_VA_START(arglist, format); status = TrioFormatRef((trio_reference_t *)ref, format, arglist, NULL); TRIO_VA_END(arglist); return status; } /************************************************************************* * trio_vprint_ref [public] */ int trio_vprint_ref TRIO_ARGS3((ref, format, arglist), trio_pointer_t ref, TRIO_CONST char *format, va_list arglist) { assert(VALID(format)); return TrioFormatRef((trio_reference_t *)ref, format, arglist, NULL); } /************************************************************************* * trio_printv_ref [public] */ int trio_printv_ref TRIO_ARGS3((ref, format, argarray), trio_pointer_t ref, TRIO_CONST char *format, trio_pointer_t *argarray) { static va_list unused; assert(VALID(format)); return TrioFormatRef((trio_reference_t *)ref, format, unused, argarray); } #endif /************************************************************************* * trio_print_pointer [public] */ void trio_print_pointer TRIO_ARGS2((ref, pointer), trio_pointer_t ref, trio_pointer_t pointer) { trio_reference_t *self = (trio_reference_t *)ref; trio_flags_t flags; trio_uintmax_t number; if (NULL == pointer) { TRIO_CONST char *string = internalNullString; while (*string) self->data->OutStream(self->data, *string++); } else { /* * The subtraction of the null pointer is a workaround * to avoid a compiler warning. The performance overhead * is negligible (and likely to be removed by an * optimizing compiler). The (char *) casting is done * to please ANSI C++. */ number = (trio_uintmax_t)((char *)pointer - (char *)0); /* Shrink to size of pointer */ number &= (trio_uintmax_t)-1; flags = self->parameter->flags; flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING); TrioWriteNumber(self->data, number, flags, POINTER_WIDTH, NO_PRECISION, BASE_HEX); } } /** @} End of UserDefined documentation module */ /************************************************************************* * * LOCALES * ************************************************************************/ /************************************************************************* * trio_locale_set_decimal_point * * Decimal point can only be one character. The input argument is a * string to enable multibyte characters. At most MB_LEN_MAX characters * will be used. */ #if TRIO_FEATURE_LOCALE TRIO_PUBLIC void trio_locale_set_decimal_point TRIO_ARGS1((decimalPoint), char *decimalPoint) { #if defined(USE_LOCALE) if (NULL == internalLocaleValues) { TrioSetLocale(); } #endif internalDecimalPointLength = trio_length(decimalPoint); if (internalDecimalPointLength == 1) { internalDecimalPoint = *decimalPoint; } else { internalDecimalPoint = NIL; trio_copy_max(internalDecimalPointString, sizeof(internalDecimalPointString), decimalPoint); } } #endif /************************************************************************* * trio_locale_set_thousand_separator * * See trio_locale_set_decimal_point */ #if TRIO_FEATURE_LOCALE || TRIO_EXTENSION TRIO_PUBLIC void trio_locale_set_thousand_separator TRIO_ARGS1((thousandSeparator), char *thousandSeparator) { # if defined(USE_LOCALE) if (NULL == internalLocaleValues) { TrioSetLocale(); } # endif trio_copy_max(internalThousandSeparator, sizeof(internalThousandSeparator), thousandSeparator); internalThousandSeparatorLength = trio_length(internalThousandSeparator); } #endif /************************************************************************* * trio_locale_set_grouping * * Array of bytes. Reversed order. * * CHAR_MAX : No further grouping * 0 : Repeat last group for the remaining digits (not necessary * as C strings are zero-terminated) * n : Set current group to n * * Same order as the grouping attribute in LC_NUMERIC. */ #if TRIO_FEATURE_LOCALE || TRIO_EXTENSION TRIO_PUBLIC void trio_locale_set_grouping TRIO_ARGS1((grouping), char *grouping) { # if defined(USE_LOCALE) if (NULL == internalLocaleValues) { TrioSetLocale(); } # endif trio_copy_max(internalGrouping, sizeof(internalGrouping), grouping); } #endif /************************************************************************* * * SCANNING * ************************************************************************/ #if TRIO_FEATURE_SCANF /************************************************************************* * TrioSkipWhitespaces */ TRIO_PRIVATE int TrioSkipWhitespaces TRIO_ARGS1((self), trio_class_t *self) { int ch; ch = self->current; while (isspace(ch)) { self->InStream(self, &ch); } return ch; } /************************************************************************* * TrioGetCollation */ #if TRIO_EXTENSION TRIO_PRIVATE void TrioGetCollation(TRIO_NOARGS) { int i; int j; int k; char first[2]; char second[2]; /* This is computationally expensive */ first[1] = NIL; second[1] = NIL; for (i = 0; i < MAX_CHARACTER_CLASS; i++) { k = 0; first[0] = (char)i; for (j = 0; j < MAX_CHARACTER_CLASS; j++) { second[0] = (char)j; if (trio_equal_locale(first, second)) internalCollationArray[i][k++] = (char)j; } internalCollationArray[i][k] = NIL; } } #endif /************************************************************************* * TrioGetCharacterClass * * FIXME: * multibyte */ TRIO_PRIVATE int TrioGetCharacterClass TRIO_ARGS4((format, offsetPointer, flagsPointer, characterclass), TRIO_CONST char *format, int *offsetPointer, trio_flags_t *flagsPointer, int *characterclass) { int offset = *offsetPointer; int i; char ch; char range_begin; char range_end; *flagsPointer &= ~FLAGS_EXCLUDE; if (format[offset] == QUALIFIER_CIRCUMFLEX) { *flagsPointer |= FLAGS_EXCLUDE; offset++; } /* * If the ungroup character is at the beginning of the scanlist, * it will be part of the class, and a second ungroup character * must follow to end the group. */ if (format[offset] == SPECIFIER_UNGROUP) { characterclass[(int)SPECIFIER_UNGROUP]++; offset++; } /* * Minus is used to specify ranges. To include minus in the class, * it must be at the beginning of the list */ if (format[offset] == QUALIFIER_MINUS) { characterclass[(int)QUALIFIER_MINUS]++; offset++; } /* Collect characters */ for (ch = format[offset]; (ch != SPECIFIER_UNGROUP) && (ch != NIL); ch = format[++offset]) { switch (ch) { case QUALIFIER_MINUS: /* Scanlist ranges */ /* * Both C99 and UNIX98 describes ranges as implementation- * defined. * * We support the following behaviour (although this may * change as we become wiser) * - only increasing ranges, ie. [a-b] but not [b-a] * - transitive ranges, ie. [a-b-c] == [a-c] * - trailing minus, ie. [a-] is interpreted as an 'a' * and a '-' * - duplicates (although we can easily convert these * into errors) */ range_begin = format[offset - 1]; range_end = format[++offset]; if (range_end == SPECIFIER_UNGROUP) { /* Trailing minus is included */ characterclass[(int)ch]++; ch = range_end; break; /* for */ } if (range_end == NIL) return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); if (range_begin > range_end) return TRIO_ERROR_RETURN(TRIO_ERANGE, offset); for (i = (int)range_begin; i <= (int)range_end; i++) characterclass[i]++; ch = range_end; break; #if TRIO_EXTENSION case SPECIFIER_GROUP: switch (format[offset + 1]) { case QUALIFIER_DOT: /* Collating symbol */ /* * FIXME: This will be easier to implement when multibyte * characters have been implemented. Until now, we ignore * this feature. */ for (i = offset + 2; ; i++) { if (format[i] == NIL) /* Error in syntax */ return -1; else if (format[i] == QUALIFIER_DOT) break; /* for */ } if (format[++i] != SPECIFIER_UNGROUP) return -1; offset = i; break; case QUALIFIER_EQUAL: /* Equivalence class expressions */ { unsigned int j; unsigned int k; if (internalCollationUnconverted) { /* Lazy evaluation of collation array */ TrioGetCollation(); internalCollationUnconverted = FALSE; } for (i = offset + 2; ; i++) { if (format[i] == NIL) /* Error in syntax */ return -1; else if (format[i] == QUALIFIER_EQUAL) break; /* for */ else { /* Mark any equivalent character */ k = (unsigned int)format[i]; for (j = 0; internalCollationArray[k][j] != NIL; j++) characterclass[(int)internalCollationArray[k][j]]++; } } if (format[++i] != SPECIFIER_UNGROUP) return -1; offset = i; } break; case QUALIFIER_COLON: /* Character class expressions */ if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (isalnum(i)) characterclass[i]++; offset += sizeof(CLASS_ALNUM) - 1; } else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (isalpha(i)) characterclass[i]++; offset += sizeof(CLASS_ALPHA) - 1; } else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (iscntrl(i)) characterclass[i]++; offset += sizeof(CLASS_CNTRL) - 1; } else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (isdigit(i)) characterclass[i]++; offset += sizeof(CLASS_DIGIT) - 1; } else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (isgraph(i)) characterclass[i]++; offset += sizeof(CLASS_GRAPH) - 1; } else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (islower(i)) characterclass[i]++; offset += sizeof(CLASS_LOWER) - 1; } else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (isprint(i)) characterclass[i]++; offset += sizeof(CLASS_PRINT) - 1; } else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (ispunct(i)) characterclass[i]++; offset += sizeof(CLASS_PUNCT) - 1; } else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (isspace(i)) characterclass[i]++; offset += sizeof(CLASS_SPACE) - 1; } else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (isupper(i)) characterclass[i]++; offset += sizeof(CLASS_UPPER) - 1; } else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1, &format[offset])) { for (i = 0; i < MAX_CHARACTER_CLASS; i++) if (isxdigit(i)) characterclass[i]++; offset += sizeof(CLASS_XDIGIT) - 1; } else { characterclass[(int)ch]++; } break; default: characterclass[(int)ch]++; break; } break; #endif /* TRIO_EXTENSION */ default: characterclass[(int)ch]++; break; } } return 0; } /************************************************************************* * TrioReadNumber * * We implement our own number conversion in preference of strtol and * strtoul, because we must handle 'long long' and thousand separators. */ TRIO_PRIVATE BOOLEAN_T TrioReadNumber TRIO_ARGS5((self, target, flags, width, base), trio_class_t *self, trio_uintmax_t *target, trio_flags_t flags, int width, int base) { trio_uintmax_t number = 0; int digit; int count; BOOLEAN_T isNegative = FALSE; BOOLEAN_T gotNumber = FALSE; int j; assert(VALID(self)); assert(VALID(self->InStream)); assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE)); if (internalDigitsUnconverted) { /* Lazy evaluation of digits array */ memset(internalDigitArray, -1, sizeof(internalDigitArray)); for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++) { internalDigitArray[(int)internalDigitsLower[j]] = j; internalDigitArray[(int)internalDigitsUpper[j]] = j; } internalDigitsUnconverted = FALSE; } TrioSkipWhitespaces(self); if (!(flags & FLAGS_UNSIGNED)) { /* Leading sign */ if (self->current == '+') { self->InStream(self, NULL); } else if (self->current == '-') { self->InStream(self, NULL); isNegative = TRUE; } } count = self->processed; if (flags & FLAGS_ALTERNATIVE) { switch (base) { case NO_BASE: case BASE_OCTAL: case BASE_HEX: case BASE_BINARY: if (self->current == '0') { self->InStream(self, NULL); if (self->current) { if ((base == BASE_HEX) && (trio_to_upper(self->current) == 'X')) { self->InStream(self, NULL); } else if ((base == BASE_BINARY) && (trio_to_upper(self->current) == 'B')) { self->InStream(self, NULL); } } } else return FALSE; break; default: break; } } while (((width == NO_WIDTH) || (self->processed - count < width)) && (! ((self->current == EOF) || isspace(self->current)))) { if (isascii(self->current)) { digit = internalDigitArray[self->current]; /* Abort if digit is not allowed in the specified base */ if ((digit == -1) || (digit >= base)) break; } #if TRIO_FEATURE_QUOTE else if (flags & FLAGS_QUOTE) { /* Compare with thousands separator */ for (j = 0; internalThousandSeparator[j] && self->current; j++) { if (internalThousandSeparator[j] != self->current) break; self->InStream(self, NULL); } if (internalThousandSeparator[j]) break; /* Mismatch */ else continue; /* Match */ } #endif else break; number *= base; number += digit; gotNumber = TRUE; /* we need at least one digit */ self->InStream(self, NULL); } /* Was anything read at all? */ if (!gotNumber) return FALSE; if (target) *target = (isNegative) ? (trio_uintmax_t)(-((trio_intmax_t)number)) : number; return TRUE; } /************************************************************************* * TrioReadChar */ TRIO_PRIVATE int TrioReadChar TRIO_ARGS4((self, target, flags, width), trio_class_t *self, char *target, trio_flags_t flags, int width) { int i; char ch; trio_uintmax_t number; assert(VALID(self)); assert(VALID(self->InStream)); for (i = 0; (self->current != EOF) && (i < width); i++) { ch = (char)self->current; self->InStream(self, NULL); if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH)) { switch (self->current) { case '\\': ch = '\\'; break; case 'a': ch = '\007'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case 'v': ch = '\v'; break; default: if (isdigit(self->current)) { /* Read octal number */ if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL)) return 0; ch = (char)number; } else if (trio_to_upper(self->current) == 'X') { /* Read hexadecimal number */ self->InStream(self, NULL); if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX)) return 0; ch = (char)number; } else { ch = (char)self->current; } break; } } if (target) target[i] = ch; } return i + 1; } /************************************************************************* * TrioReadString */ TRIO_PRIVATE BOOLEAN_T TrioReadString TRIO_ARGS4((self, target, flags, width), trio_class_t *self, char *target, trio_flags_t flags, int width) { int i; assert(VALID(self)); assert(VALID(self->InStream)); TrioSkipWhitespaces(self); /* * Continue until end of string is reached, a whitespace is encountered, * or width is exceeded */ for (i = 0; ((width == NO_WIDTH) || (i < width)) && (! ((self->current == EOF) || isspace(self->current))); i++) { if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0) break; /* for */ } if (target) target[i] = NIL; return TRUE; } /************************************************************************* * TrioReadWideChar */ #if TRIO_FEATURE_WIDECHAR TRIO_PRIVATE int TrioReadWideChar TRIO_ARGS4((self, target, flags, width), trio_class_t *self, trio_wchar_t *target, trio_flags_t flags, int width) { int i; int j; int size; int amount = 0; trio_wchar_t wch; char buffer[MB_LEN_MAX + 1]; assert(VALID(self)); assert(VALID(self->InStream)); for (i = 0; (self->current != EOF) && (i < width); i++) { if (isascii(self->current)) { if (TrioReadChar(self, buffer, flags, 1) == 0) return 0; buffer[1] = NIL; } else { /* * Collect a multibyte character, by enlarging buffer until * it contains a fully legal multibyte character, or the * buffer is full. */ j = 0; do { buffer[j++] = (char)self->current; buffer[j] = NIL; self->InStream(self, NULL); } while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j)); } if (target) { size = mbtowc(&wch, buffer, sizeof(buffer)); if (size > 0) target[i] = wch; } amount += size; self->InStream(self, NULL); } return amount; } #endif /* TRIO_FEATURE_WIDECHAR */ /************************************************************************* * TrioReadWideString */ #if TRIO_FEATURE_WIDECHAR TRIO_PRIVATE BOOLEAN_T TrioReadWideString TRIO_ARGS4((self, target, flags, width), trio_class_t *self, trio_wchar_t *target, trio_flags_t flags, int width) { int i; int size; assert(VALID(self)); assert(VALID(self->InStream)); TrioSkipWhitespaces(self); #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) /* Required by TrioReadWideChar */ (void)mblen(NULL, 0); #endif /* * Continue until end of string is reached, a whitespace is encountered, * or width is exceeded */ for (i = 0; ((width == NO_WIDTH) || (i < width)) && (! ((self->current == EOF) || isspace(self->current))); ) { size = TrioReadWideChar(self, &target[i], flags, 1); if (size == 0) break; /* for */ i += size; } if (target) target[i] = WCONST('\0'); return TRUE; } #endif /* TRIO_FEATURE_WIDECHAR */ /************************************************************************* * TrioReadGroup * * FIXME: characterclass does not work with multibyte characters */ TRIO_PRIVATE BOOLEAN_T TrioReadGroup TRIO_ARGS5((self, target, characterclass, flags, width), trio_class_t *self, char *target, int *characterclass, trio_flags_t flags, int width) { int ch; int i; assert(VALID(self)); assert(VALID(self->InStream)); ch = self->current; for (i = 0; ((width == NO_WIDTH) || (i < width)) && (! ((ch == EOF) || (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0)))); i++) { if (target) target[i] = (char)ch; self->InStream(self, &ch); } if (target) target[i] = NIL; return TRUE; } /************************************************************************* * TrioReadDouble * * FIXME: * add long double * handle base */ #if TRIO_FEATURE_FLOAT TRIO_PRIVATE BOOLEAN_T TrioReadDouble TRIO_ARGS4((self, target, flags, width), trio_class_t *self, trio_pointer_t target, trio_flags_t flags, int width) { int ch; char doubleString[512]; int offset = 0; int start; # if TRIO_FEATURE_QUOTE int j; # endif BOOLEAN_T isHex = FALSE; trio_long_double_t infinity; doubleString[0] = 0; if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1)) width = sizeof(doubleString) - 1; TrioSkipWhitespaces(self); /* * Read entire double number from stream. trio_to_double requires * a string as input, but InStream can be anything, so we have to * collect all characters. */ ch = self->current; if ((ch == '+') || (ch == '-')) { doubleString[offset++] = (char)ch; self->InStream(self, &ch); width--; } start = offset; switch (ch) { case 'n': case 'N': /* Not-a-number */ if (offset != 0) break; /* FALLTHROUGH */ case 'i': case 'I': /* Infinity */ while (isalpha(ch) && (offset - start < width)) { doubleString[offset++] = (char)ch; self->InStream(self, &ch); } doubleString[offset] = NIL; /* Case insensitive string comparison */ if (trio_equal(&doubleString[start], INFINITE_UPPER) || trio_equal(&doubleString[start], LONG_INFINITE_UPPER)) { infinity = ((start == 1) && (doubleString[0] == '-')) ? trio_ninf() : trio_pinf(); if (flags & FLAGS_LONGDOUBLE) { *((trio_long_double_t *)target) = infinity; } else if (flags & FLAGS_LONG) { *((double *)target) = infinity; } else { *((float *)target) = infinity; } return TRUE; } if (trio_equal(doubleString, NAN_UPPER)) { /* NaN must not have a preceeding + nor - */ if (flags & FLAGS_LONGDOUBLE) { *((trio_long_double_t *)target) = trio_nan(); } else if (flags & FLAGS_LONG) { *((double *)target) = trio_nan(); } else { *((float *)target) = trio_nan(); } return TRUE; } return FALSE; case '0': doubleString[offset++] = (char)ch; self->InStream(self, &ch); if (trio_to_upper(ch) == 'X') { isHex = TRUE; doubleString[offset++] = (char)ch; self->InStream(self, &ch); } break; default: break; } while ((ch != EOF) && (offset - start < width)) { /* Integer part */ if (isHex ? isxdigit(ch) : isdigit(ch)) { doubleString[offset++] = (char)ch; self->InStream(self, &ch); } # if TRIO_FEATURE_QUOTE else if (flags & FLAGS_QUOTE) { /* Compare with thousands separator */ for (j = 0; internalThousandSeparator[j] && self->current; j++) { if (internalThousandSeparator[j] != self->current) break; self->InStream(self, &ch); } if (internalThousandSeparator[j]) break; /* Mismatch */ else continue; /* Match */ } # endif else break; /* while */ } if (ch == '.') { /* Decimal part */ doubleString[offset++] = (char)ch; self->InStream(self, &ch); while ((isHex ? isxdigit(ch) : isdigit(ch)) && (offset - start < width)) { doubleString[offset++] = (char)ch; self->InStream(self, &ch); } } if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E')) { /* Exponent */ doubleString[offset++] = (char)ch; self->InStream(self, &ch); if ((ch == '+') || (ch == '-')) { doubleString[offset++] = (char)ch; self->InStream(self, &ch); } while (isdigit(ch) && (offset - start < width)) { doubleString[offset++] = (char)ch; self->InStream(self, &ch); } } if ((offset == start) || (*doubleString == NIL)) return FALSE; doubleString[offset] = 0; if (flags & FLAGS_LONGDOUBLE) { *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL); } else if (flags & FLAGS_LONG) { *((double *)target) = trio_to_double(doubleString, NULL); } else { *((float *)target) = trio_to_float(doubleString, NULL); } return TRUE; } #endif /* TRIO_FEATURE_FLOAT */ /************************************************************************* * TrioReadPointer */ TRIO_PRIVATE BOOLEAN_T TrioReadPointer TRIO_ARGS3((self, target, flags), trio_class_t *self, trio_pointer_t *target, trio_flags_t flags) { trio_uintmax_t number; char buffer[sizeof(internalNullString)]; flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING); if (TrioReadNumber(self, &number, flags, POINTER_WIDTH, BASE_HEX)) { if (target) { #if defined(TRIO_COMPILER_GCC) || defined(TRIO_COMPILER_MIPSPRO) /* * The strange assignment of number is a workaround for a compiler * warning */ *target = &((char *)0)[number]; #else *target = (trio_pointer_t)number; #endif } return TRUE; } else if (TrioReadString(self, (flags & FLAGS_IGNORE) ? NULL : buffer, 0, sizeof(internalNullString) - 1)) { if (trio_equal_case(buffer, internalNullString)) { if (target) *target = NULL; return TRUE; } } return FALSE; } /************************************************************************* * TrioScanProcess */ TRIO_PRIVATE int TrioScanProcess TRIO_ARGS3((data, format, parameters), trio_class_t *data, TRIO_CONST char *format, trio_parameter_t *parameters) { int assignment; int ch; int offset; /* Offset of format string */ int i; /* Offset of current parameter */ trio_flags_t flags; int width; int base; trio_pointer_t pointer; assignment = 0; i = 0; offset = 0; data->InStream(data, &ch); for (;;) { /* Skip the parameter entries */ while (parameters[i].type == FORMAT_PARAMETER) { assert(i <= MAX_PARAMETERS); i++; } /* Compare non conversion-specifier part of format string */ while (offset < parameters[i].beginOffset) { if ((CHAR_IDENTIFIER == format[offset]) && (CHAR_IDENTIFIER == format[offset + 1])) { /* Two % in format matches one % in input stream */ if (CHAR_IDENTIFIER == ch) { data->InStream(data, &ch); offset += 2; continue; /* while format chars left */ } else return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); } else /* Not an % identifier */ { if (isspace((int)format[offset])) { /* Whitespaces may match any amount of whitespaces */ ch = TrioSkipWhitespaces(data); } else if (ch == format[offset]) { data->InStream(data, &ch); } else return assignment; offset++; } } if (parameters[i].type == FORMAT_SENTINEL) break; if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT)) return (assignment > 0) ? assignment : EOF; flags = parameters[i].flags; /* Find width */ width = parameters[i].width; if (flags & FLAGS_WIDTH_PARAMETER) { /* Get width from parameter list */ width = (int)parameters[width].data.number.as_signed; } /* Find base */ if (NO_BASE != parameters[i].baseSpecifier) { /* Base from specifier has priority */ base = parameters[i].baseSpecifier; } else if (flags & FLAGS_BASE_PARAMETER) { /* Get base from parameter list */ base = parameters[i].base; base = (int)parameters[base].data.number.as_signed; } else { /* Use base from format string */ base = parameters[i].base; } switch (parameters[i].type) { case FORMAT_INT: { trio_uintmax_t number; if (0 == base) base = BASE_DECIMAL; if (!TrioReadNumber(data, &number, flags, width, base)) return assignment; if (!(flags & FLAGS_IGNORE)) { assignment++; pointer = parameters[i].data.pointer; #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER if (flags & FLAGS_SIZE_T) *(size_t *)pointer = (size_t)number; else #endif #if TRIO_FEATURE_PTRDIFF_T if (flags & FLAGS_PTRDIFF_T) *(ptrdiff_t *)pointer = (ptrdiff_t)number; else #endif #if TRIO_FEATURE_INTMAX_T if (flags & FLAGS_INTMAX_T) *(trio_intmax_t *)pointer = (trio_intmax_t)number; else #endif if (flags & FLAGS_QUAD) *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number; else if (flags & FLAGS_LONG) *(long int *)pointer = (long int)number; else if (flags & FLAGS_SHORT) *(short int *)pointer = (short int)number; else *(int *)pointer = (int)number; } } break; /* FORMAT_INT */ case FORMAT_STRING: #if TRIO_FEATURE_WIDECHAR if (flags & FLAGS_WIDECHAR) { if (!TrioReadWideString(data, (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.wstring, flags, width)) return assignment; } else #endif { if (!TrioReadString(data, (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.string, flags, width)) return assignment; } if (!(flags & FLAGS_IGNORE)) assignment++; break; /* FORMAT_STRING */ #if TRIO_FEATURE_FLOAT case FORMAT_DOUBLE: { if (flags & FLAGS_IGNORE) { pointer = NULL; } else { pointer = (flags & FLAGS_LONGDOUBLE) ? (trio_pointer_t)parameters[i].data.longdoublePointer : (trio_pointer_t)parameters[i].data.doublePointer; } if (!TrioReadDouble(data, pointer, flags, width)) { return assignment; } if (!(flags & FLAGS_IGNORE)) { assignment++; } break; /* FORMAT_DOUBLE */ } #endif case FORMAT_GROUP: { int characterclass[MAX_CHARACTER_CLASS + 1]; int rc; /* Skip over modifiers */ while (format[offset] != SPECIFIER_GROUP) { offset++; } /* Skip over group specifier */ offset++; memset(characterclass, 0, sizeof(characterclass)); rc = TrioGetCharacterClass(format, &offset, &flags, characterclass); if (rc < 0) return rc; if (!TrioReadGroup(data, (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.string, characterclass, flags, parameters[i].width)) return assignment; if (!(flags & FLAGS_IGNORE)) assignment++; } break; /* FORMAT_GROUP */ case FORMAT_COUNT: pointer = parameters[i].data.pointer; if (NULL != pointer) { int count = data->committed; if (ch != EOF) count--; /* a character is read, but is not consumed yet */ #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER if (flags & FLAGS_SIZE_T) *(size_t *)pointer = (size_t)count; else #endif #if TRIO_FEATURE_PTRDIFF_T if (flags & FLAGS_PTRDIFF_T) *(ptrdiff_t *)pointer = (ptrdiff_t)count; else #endif #if TRIO_FEATURE_INTMAX_T if (flags & FLAGS_INTMAX_T) *(trio_intmax_t *)pointer = (trio_intmax_t)count; else #endif if (flags & FLAGS_QUAD) { *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count; } else if (flags & FLAGS_LONG) { *(long int *)pointer = (long int)count; } else if (flags & FLAGS_SHORT) { *(short int *)pointer = (short int)count; } else { *(int *)pointer = (int)count; } } break; /* FORMAT_COUNT */ case FORMAT_CHAR: #if TRIO_FEATURE_WIDECHAR if (flags & FLAGS_WIDECHAR) { if (TrioReadWideChar(data, (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.wstring, flags, (width == NO_WIDTH) ? 1 : width) == 0) return assignment; } else #endif { if (TrioReadChar(data, (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.string, flags, (width == NO_WIDTH) ? 1 : width) == 0) return assignment; } if (!(flags & FLAGS_IGNORE)) assignment++; break; /* FORMAT_CHAR */ case FORMAT_POINTER: if (!TrioReadPointer(data, (flags & FLAGS_IGNORE) ? NULL : (trio_pointer_t *)parameters[i].data.pointer, flags)) return assignment; if (!(flags & FLAGS_IGNORE)) assignment++; break; /* FORMAT_POINTER */ case FORMAT_PARAMETER: break; /* FORMAT_PARAMETER */ default: return TRIO_ERROR_RETURN(TRIO_EINVAL, offset); } ch = data->current; offset = parameters[i].endOffset; i++; } return assignment; } /************************************************************************* * TrioScan */ TRIO_PRIVATE int TrioScan TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray), trio_pointer_t source, size_t sourceSize, void (*InStream) TRIO_PROTO((trio_class_t *, int *)), TRIO_CONST char *format, va_list arglist, trio_pointer_t *argarray) { int status; trio_parameter_t parameters[MAX_PARAMETERS]; trio_class_t data; assert(VALID(InStream)); assert(VALID(format)); memset(&data, 0, sizeof(data)); data.InStream = InStream; data.location = (trio_pointer_t)source; data.max = sourceSize; data.error = 0; #if defined(USE_LOCALE) if (NULL == internalLocaleValues) { TrioSetLocale(); } #endif status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray); if (status < 0) return status; status = TrioScanProcess(&data, format, parameters); if (data.error != 0) { status = data.error; } return status; } /************************************************************************* * TrioInStreamFile */ #if TRIO_FEATURE_FILE || TRIO_FEATURE_STDIO TRIO_PRIVATE void TrioInStreamFile TRIO_ARGS2((self, intPointer), trio_class_t *self, int *intPointer) { FILE *file = (FILE *)self->location; assert(VALID(self)); assert(VALID(file)); self->current = fgetc(file); if (self->current == EOF) { self->error = (ferror(file)) ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0) : TRIO_ERROR_RETURN(TRIO_EOF, 0); } else { self->processed++; self->committed++; } if (VALID(intPointer)) { *intPointer = self->current; } } #endif /* TRIO_FEATURE_FILE || TRIO_FEATURE_STDIO */ /************************************************************************* * TrioInStreamFileDescriptor */ #if TRIO_FEATURE_FD TRIO_PRIVATE void TrioInStreamFileDescriptor TRIO_ARGS2((self, intPointer), trio_class_t *self, int *intPointer) { int fd = *((int *)self->location); int size; unsigned char input; assert(VALID(self)); size = read(fd, &input, sizeof(char)); if (size == -1) { self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0); self->current = EOF; } else { self->current = (size == 0) ? EOF : input; } if (self->current != EOF) { self->committed++; self->processed++; } if (VALID(intPointer)) { *intPointer = self->current; } } #endif /* TRIO_FEATURE_FD */ /************************************************************************* * TrioInStreamCustom */ #if TRIO_FEATURE_CLOSURE TRIO_PRIVATE void TrioInStreamCustom TRIO_ARGS2((self, intPointer), trio_class_t *self, int *intPointer) { trio_custom_t *data; assert(VALID(self)); assert(VALID(self->location)); data = (trio_custom_t *)self->location; self->current = (data->stream.in == NULL) ? NIL : (data->stream.in)(data->closure); if (self->current == NIL) { self->current = EOF; } else { self->processed++; self->committed++; } if (VALID(intPointer)) { *intPointer = self->current; } } #endif /* TRIO_FEATURE_CLOSURE */ /************************************************************************* * TrioInStreamString */ TRIO_PRIVATE void TrioInStreamString TRIO_ARGS2((self, intPointer), trio_class_t *self, int *intPointer) { unsigned char **buffer; assert(VALID(self)); assert(VALID(self->location)); buffer = (unsigned char **)self->location; self->current = (*buffer)[0]; if (self->current == NIL) { self->current = EOF; } else { (*buffer)++; self->processed++; self->committed++; } if (VALID(intPointer)) { *intPointer = self->current; } } /************************************************************************* * * Formatted scanning functions * ************************************************************************/ #if defined(TRIO_DOCUMENTATION) # include "doc/doc_scanf.h" #endif /** @addtogroup Scanf @{ */ /************************************************************************* * scanf */ /** Scan characters from standard input stream. @param format Formatting string. @param ... Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_STDIO TRIO_PUBLIC int scanf TRIO_VARGS2((format, va_alist), TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(format)); TRIO_VA_START(args, format); status = TrioScan((trio_pointer_t)stdin, 0, TrioInStreamFile, format, args, NULL); TRIO_VA_END(args); return status; } #endif /* TRIO_FEATURE_STDIO */ /** Scan characters from standard input stream. @param format Formatting string. @param args Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_STDIO TRIO_PUBLIC int vscanf TRIO_ARGS2((format, args), TRIO_CONST char *format, va_list args) { assert(VALID(format)); return TrioScan((trio_pointer_t)stdin, 0, TrioInStreamFile, format, args, NULL); } #endif /* TRIO_FEATURE_STDIO */ /** Scan characters from standard input stream. @param format Formatting string. @param args Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_STDIO TRIO_PUBLIC int trio_scanfv TRIO_ARGS2((format, args), TRIO_CONST char *format, trio_pointer_t *args) { static va_list unused; assert(VALID(format)); return TrioScan((trio_pointer_t)stdin, 0, TrioInStreamFile, format, unused, args); } #endif /* TRIO_FEATURE_STDIO */ /************************************************************************* * fscanf */ /** Scan characters from file. @param file File pointer. @param format Formatting string. @param ... Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_FILE TRIO_PUBLIC int fscanf TRIO_VARGS3((file, format, va_alist), FILE *file, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(file)); assert(VALID(format)); TRIO_VA_START(args, format); status = TrioScan((trio_pointer_t)file, 0, TrioInStreamFile, format, args, NULL); TRIO_VA_END(args); return status; } #endif /* TRIO_FEATURE_FILE */ /** Scan characters from file. @param file File pointer. @param format Formatting string. @param args Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_FILE TRIO_PUBLIC int vfscanf TRIO_ARGS3((file, format, args), FILE *file, TRIO_CONST char *format, va_list args) { assert(VALID(file)); assert(VALID(format)); return TrioScan((trio_pointer_t)file, 0, TrioInStreamFile, format, args, NULL); } #endif /* TRIO_FEATURE_FILE */ /** Scan characters from file. @param file File pointer. @param format Formatting string. @param args Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_FILE TRIO_PUBLIC int trio_fscanfv TRIO_ARGS3((file, format, args), FILE *file, TRIO_CONST char *format, trio_pointer_t *args) { static va_list unused; assert(VALID(file)); assert(VALID(format)); return TrioScan((trio_pointer_t)file, 0, TrioInStreamFile, format, unused, args); } #endif /* TRIO_FEATURE_FILE */ /************************************************************************* * dscanf */ /** Scan characters from file descriptor. @param fd File descriptor. @param format Formatting string. @param ... Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_FD TRIO_PUBLIC int trio_dscanf TRIO_VARGS3((fd, format, va_alist), int fd, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(format)); TRIO_VA_START(args, format); status = TrioScan((trio_pointer_t)&fd, 0, TrioInStreamFileDescriptor, format, args, NULL); TRIO_VA_END(args); return status; } #endif /* TRIO_FEATURE_FD */ /** Scan characters from file descriptor. @param fd File descriptor. @param format Formatting string. @param args Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_FD TRIO_PUBLIC int trio_vdscanf TRIO_ARGS3((fd, format, args), int fd, TRIO_CONST char *format, va_list args) { assert(VALID(format)); return TrioScan((trio_pointer_t)&fd, 0, TrioInStreamFileDescriptor, format, args, NULL); } #endif /* TRIO_FEATURE_FD */ /** Scan characters from file descriptor. @param fd File descriptor. @param format Formatting string. @param args Arguments. @return Number of scanned characters. */ #if TRIO_FEATURE_FD TRIO_PUBLIC int trio_dscanfv TRIO_ARGS3((fd, format, args), int fd, TRIO_CONST char *format, trio_pointer_t *args) { static va_list unused; assert(VALID(format)); return TrioScan((trio_pointer_t)&fd, 0, TrioInStreamFileDescriptor, format, unused, args); } #endif /* TRIO_FEATURE_FD */ /************************************************************************* * cscanf */ #if TRIO_FEATURE_CLOSURE TRIO_PUBLIC int trio_cscanf TRIO_VARGS4((stream, closure, format, va_alist), trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; trio_custom_t data; assert(VALID(stream)); assert(VALID(format)); TRIO_VA_START(args, format); data.stream.in = stream; data.closure = closure; status = TrioScan(&data, 0, TrioInStreamCustom, format, args, NULL); TRIO_VA_END(args); return status; } #endif /* TRIO_FEATURE_CLOSURE */ #if TRIO_FEATURE_CLOSURE TRIO_PUBLIC int trio_vcscanf TRIO_ARGS4((stream, closure, format, args), trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, va_list args) { trio_custom_t data; assert(VALID(stream)); assert(VALID(format)); data.stream.in = stream; data.closure = closure; return TrioScan(&data, 0, TrioInStreamCustom, format, args, NULL); } #endif /* TRIO_FEATURE_CLOSURE */ #if TRIO_FEATURE_CLOSURE TRIO_PUBLIC int trio_cscanfv TRIO_ARGS4((stream, closure, format, args), trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, trio_pointer_t *args) { static va_list unused; trio_custom_t data; assert(VALID(stream)); assert(VALID(format)); data.stream.in = stream; data.closure = closure; return TrioScan(&data, 0, TrioInStreamCustom, format, unused, args); } #endif /* TRIO_FEATURE_CLOSURE */ /************************************************************************* * sscanf */ /** Scan characters from string. @param buffer Input string. @param format Formatting string. @param ... Arguments. @return Number of scanned characters. */ TRIO_PUBLIC int sscanf TRIO_VARGS3((buffer, format, va_alist), TRIO_CONST char *buffer, TRIO_CONST char *format, TRIO_VA_DECL) { int status; va_list args; assert(VALID(buffer)); assert(VALID(format)); TRIO_VA_START(args, format); status = TrioScan((trio_pointer_t)&buffer, 0, TrioInStreamString, format, args, NULL); TRIO_VA_END(args); return status; } /** Scan characters from string. @param buffer Input string. @param format Formatting string. @param args Arguments. @return Number of scanned characters. */ TRIO_PUBLIC int vsscanf TRIO_ARGS3((buffer, format, args), TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args) { assert(VALID(buffer)); assert(VALID(format)); return TrioScan((trio_pointer_t)&buffer, 0, TrioInStreamString, format, args, NULL); } /** Scan characters from string. @param buffer Input string. @param format Formatting string. @param args Arguments. @return Number of scanned characters. */ TRIO_PUBLIC int trio_sscanfv TRIO_ARGS3((buffer, format, args), TRIO_CONST char *buffer, TRIO_CONST char *format, trio_pointer_t *args) { static va_list unused; assert(VALID(buffer)); assert(VALID(format)); return TrioScan((trio_pointer_t)&buffer, 0, TrioInStreamString, format, unused, args); } #endif /* TRIO_FEATURE_SCANF */ /** @} End of Scanf documentation module */ /************************************************************************* * trio_strerror */ TRIO_PUBLIC TRIO_CONST char * trio_strerror TRIO_ARGS1((errorcode), int errorcode) { #if TRIO_FEATURE_STRERR /* Textual versions of the error codes */ switch (TRIO_ERROR_CODE(errorcode)) { case TRIO_EOF: return "End of file"; case TRIO_EINVAL: return "Invalid argument"; case TRIO_ETOOMANY: return "Too many arguments"; case TRIO_EDBLREF: return "Double reference"; case TRIO_EGAP: return "Reference gap"; case TRIO_ENOMEM: return "Out of memory"; case TRIO_ERANGE: return "Invalid range"; case TRIO_ECUSTOM: return "Custom error"; default: return "Unknown"; } #else return "Unknown"; #endif } ================================================ FILE: src/sdk/src/libc/src/trio/trio.h ================================================ #ifndef TRIO_TRIO_H #define TRIO_TRIO_H #if !defined(WITHOUT_TRIO) /* * Use autoconf defines if present. Packages using trio must define * HAVE_CONFIG_H as a compiler option themselves. */ #if defined(HAVE_CONFIG_H) # include #endif #include "triop.h" #include #ifdef __cplusplus extern "C" { #endif /* * Error codes. * * Remember to add a textual description to trio_strerror. */ enum { TRIO_EOF = 1, TRIO_EINVAL = 2, TRIO_ETOOMANY = 3, TRIO_EDBLREF = 4, TRIO_EGAP = 5, TRIO_ENOMEM = 6, TRIO_ERANGE = 7, TRIO_ERRNO = 8, TRIO_ECUSTOM = 9 }; /* Error macros */ #define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF) #define TRIO_ERROR_POSITION(x) ((-(x)) >> 8) #define TRIO_ERROR_NAME(x) trio_strerror(x) typedef int (*trio_outstream_t) TRIO_PROTO((trio_pointer_t, int)); typedef int (*trio_instream_t) TRIO_PROTO((trio_pointer_t)); TRIO_CONST char *trio_strerror TRIO_PROTO((int)); /************************************************************************* * Print Functions */ int trio_printf TRIO_PROTO((TRIO_CONST char *format, ...)); int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args)); int trio_printfv TRIO_PROTO((TRIO_CONST char *format, void **args)); int trio_fprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...)); int trio_vfprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args)); int trio_fprintfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args)); int trio_dprintf TRIO_PROTO((int fd, TRIO_CONST char *format, ...)); int trio_vdprintf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args)); int trio_dprintfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args)); int trio_cprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, ...)); int trio_vcprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, va_list args)); int trio_cprintfv TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, TRIO_CONST char *format, void **args)); int trio_sprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, ...)); int trio_vsprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, va_list args)); int trio_sprintfv TRIO_PROTO((char *buffer, TRIO_CONST char *format, void **args)); int trio_snprintf TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...)); int trio_vsnprintf TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, va_list args)); int trio_snprintfv TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, void **args)); int trio_snprintfcat TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...)); int trio_vsnprintfcat TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, va_list args)); #if defined(TRIO_DEPRECATED) char *trio_aprintf TRIO_PROTO((TRIO_CONST char *format, ...)); char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args)); #endif int trio_asprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, ...)); int trio_vasprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, va_list args)); int trio_asprintfv TRIO_PROTO((char **result, TRIO_CONST char *format, trio_pointer_t * args)); /************************************************************************* * Scan Functions */ int trio_scanf TRIO_PROTO((TRIO_CONST char *format, ...)); int trio_vscanf TRIO_PROTO((TRIO_CONST char *format, va_list args)); int trio_scanfv TRIO_PROTO((TRIO_CONST char *format, void **args)); int trio_fscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...)); int trio_vfscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args)); int trio_fscanfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args)); int trio_dscanf TRIO_PROTO((int fd, TRIO_CONST char *format, ...)); int trio_vdscanf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args)); int trio_dscanfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args)); int trio_cscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, ...)); int trio_vcscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, va_list args)); int trio_cscanfv TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, TRIO_CONST char *format, void **args)); int trio_sscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, ...)); int trio_vsscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args)); int trio_sscanfv TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, void **args)); /************************************************************************* * Locale Functions */ void trio_locale_set_decimal_point TRIO_PROTO((char *decimalPoint)); void trio_locale_set_thousand_separator TRIO_PROTO((char *thousandSeparator)); void trio_locale_set_grouping TRIO_PROTO((char *grouping)); /************************************************************************* * Renaming */ #ifdef TRIO_REPLACE_STDIO /* Replace the functions */ #ifndef HAVE_PRINTF # define printf trio_printf #endif #ifndef HAVE_VPRINTF # define vprintf trio_vprintf #endif #ifndef HAVE_FPRINTF # define fprintf trio_fprintf #endif #ifndef HAVE_VFPRINTF # define vfprintf trio_vfprintf #endif #ifndef HAVE_SPRINTF # define sprintf trio_sprintf #endif #ifndef HAVE_VSPRINTF # define vsprintf trio_vsprintf #endif #ifndef HAVE_SNPRINTF # define snprintf trio_snprintf #endif #ifndef HAVE_VSNPRINTF # define vsnprintf trio_vsnprintf #endif #ifndef HAVE_SCANF # define scanf trio_scanf #endif #ifndef HAVE_VSCANF # define vscanf trio_vscanf #endif #ifndef HAVE_FSCANF # define fscanf trio_fscanf #endif #ifndef HAVE_VFSCANF # define vfscanf trio_vfscanf #endif #ifndef HAVE_SSCANF # define sscanf trio_sscanf #endif #ifndef HAVE_VSSCANF # define vsscanf trio_vsscanf #endif /* These aren't stdio functions, but we make them look similar */ #define dprintf trio_dprintf #define vdprintf trio_vdprintf #define aprintf trio_aprintf #define vaprintf trio_vaprintf #define asprintf trio_asprintf #define vasprintf trio_vasprintf #define dscanf trio_dscanf #define vdscanf trio_vdscanf #endif #ifdef __cplusplus } /* extern "C" */ #endif #endif /* WITHOUT_TRIO */ #endif /* TRIO_TRIO_H */ ================================================ FILE: src/sdk/src/libc/src/trio/triodef.h ================================================ #ifndef TRIO_TRIODEF_H #define TRIO_TRIODEF_H /************************************************************************* * Compiler support detection */ #if defined(__GNUC__) # define TRIO_COMPILER_GCC #endif #if defined(__SUNPRO_CC) # define TRIO_COMPILER_SUNPRO __SUNPRO_CC #else # if defined(__SUNPRO_C) # define TRIO_COMPILER_SUNPRO __SUNPRO_C # endif #endif #if defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__) # define TRIO_COMPILER_XLC #else # if defined(_AIX) && !defined(__GNUC__) # define TRIO_COMPILER_XLC /* Workaround for old xlc */ # endif #endif #if defined(__DECC) || defined(__DECCXX) # define TRIO_COMPILER_DECC #else # if defined(__osf__) && defined(__LANGUAGE_C__) && !defined(__GNUC__) # define TRIO_COMPILER_DECC /* Workaround for old DEC C compilers */ # endif #endif #if defined(__HP_aCC) || defined(__HP_cc) # define TRIO_COMPILER_HP #endif #if defined(sgi) || defined(__sgi) # define TRIO_COMPILER_MIPSPRO #endif #if defined(_MSC_VER) # define TRIO_COMPILER_MSVC #endif #if defined(__BORLANDC__) # define TRIO_COMPILER_BCB #endif /************************************************************************* * Platform support detection */ #if defined(VMS) || defined(__VMS) # define TRIO_PLATFORM_VMS #endif #if defined(unix) || defined(__unix) || defined(__unix__) # define TRIO_PLATFORM_UNIX #endif #if defined(TRIO_COMPILER_XLC) || defined(_AIX) # define TRIO_PLATFORM_UNIX #endif #if defined(TRIO_COMPILER_DECC) || defined(__osf___) # if !defined(TRIO_PLATFORM_VMS) # define TRIO_PLATFORM_UNIX # endif #endif #if defined(__NetBSD__) # define TRIO_PLATFORM_UNIX #endif #if defined(__Lynx__) # define TRIO_PLATFORM_UNIX # define TRIO_PLATFORM_LYNX #endif #if defined(__APPLE__) && defined(__MACH__) # define TRIO_PLATFORM_UNIX #endif #if defined(__QNX__) # define TRIO_PLATFORM_UNIX # define TRIO_PLATFORM_QNX #endif #if defined(__CYGWIN__) # define TRIO_PLATFORM_UNIX #endif #if defined(AMIGA) && defined(TRIO_COMPILER_GCC) # define TRIO_PLATFORM_UNIX #endif #if defined(TRIO_COMPILER_MSVC) || defined(WIN32) || defined(_WIN32) # define TRIO_PLATFORM_WIN32 #endif #if defined(_WIN32_WCE) # define TRIO_PLATFORM_WINCE #endif #if defined(mpeix) || defined(__mpexl) # define TRIO_PLATFORM_MPEIX #endif #if defined(_AIX) # define TRIO_PLATFORM_AIX #endif #if defined(__hpux) # define TRIO_PLATFORM_HPUX #endif #if defined(sun) || defined(__sun__) # if defined(__SVR4) || defined(__svr4__) # define TRIO_PLATFORM_SOLARIS # else # define TRIO_PLATFORM_SUNOS # endif #endif /************************************************************************* * Standards support detection */ #if defined(__STDC__) \ || defined(_MSC_EXTENSIONS) \ || defined(TRIO_COMPILER_BORLAND) # define PREDEF_STANDARD_C89 #endif #if defined(__STDC_VERSION__) # define PREDEF_STANDARD_C90 #endif #if (__STDC_VERSION__ - 0 >= 199409L) # define PREDEF_STANDARD_C94 #endif #if (__STDC_VERSION__ - 0 >= 199901L) # define PREDEF_STANDARD_C99 #endif #if defined(TRIO_COMPILER_SUNPRO) && (TRIO_COMPILER_SUNPRO >= 0x420) # if !defined(PREDEF_STANDARD_C94) # define PREDEF_STANDARD_C94 # endif #endif #if defined(__cplusplus) # define PREDEF_STANDARD_CXX #endif #if __cplusplus - 0 >= 199711L # define PREDEF_STANDARD_CXX89 #endif #if defined(TRIO_PLATFORM_UNIX) # include #endif #if defined(_POSIX_VERSION) # define PREDEF_STANDARD_POSIX _POSIX_VERSION # if (_POSIX_VERSION >= 199506L) # define PREDEF_STANDARD_POSIX_1996 # endif #endif #if (_XOPEN_VERSION - 0 >= 3) || defined(_XOPEN_XPG3) # define PREDEF_STANDARD_XPG3 #endif #if (_XOPEN_VERSION - 0 >= 4) || defined(_XOPEN_XPG4) # define PREDEF_STANDARD_XPG4 #endif #if (_XOPEN_VERSION - 0 > 4) \ || (defined(_XOPEN_UNIX) && (_XOPEN_VERSION - 0 == 4)) # define PREDEF_STANDARD_UNIX95 #endif #if (_XOPEN_VERSION - 0 >= 500) # define PREDEF_STANDARD_UNIX98 #endif #if (_XOPEN_VERSION - 0 >= 600) # define PREDEF_STANDARD_UNIX03 #endif /************************************************************************* * Generic defines */ #if !defined(TRIO_PUBLIC) # define TRIO_PUBLIC #endif #if !defined(TRIO_PRIVATE) # define TRIO_PRIVATE static #endif #if !(defined(PREDEF_STANDARD_C89) || defined(PREDEF_STANDARD_CXX)) # define TRIO_COMPILER_ANCIENT #endif #if defined(TRIO_COMPILER_ANCIENT) # define TRIO_CONST # define TRIO_VOLATILE # define TRIO_SIGNED typedef double trio_long_double_t; typedef char * trio_pointer_t; # define TRIO_SUFFIX_LONG(x) x # define TRIO_PROTO(x) () # define TRIO_NOARGS # define TRIO_ARGS1(list,a1) list a1; # define TRIO_ARGS2(list,a1,a2) list a1; a2; # define TRIO_ARGS3(list,a1,a2,a3) list a1; a2; a3; # define TRIO_ARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4; # define TRIO_ARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5; # define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) list a1; a2; a3; a4; a5; a6; # define TRIO_VARGS2(list,a1,a2) list a1; a2 # define TRIO_VARGS3(list,a1,a2,a3) list a1; a2; a3 # define TRIO_VARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4 # define TRIO_VARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5 # define TRIO_VA_DECL va_dcl # define TRIO_VA_START(x,y) va_start(x) # define TRIO_VA_END(x) va_end(x) #else /* ANSI C */ # define TRIO_CONST const # define TRIO_VOLATILE volatile # define TRIO_SIGNED signed typedef long double trio_long_double_t; typedef void * trio_pointer_t; # define TRIO_SUFFIX_LONG(x) x ## L # define TRIO_PROTO(x) x # define TRIO_NOARGS void # define TRIO_ARGS1(list,a1) (a1) # define TRIO_ARGS2(list,a1,a2) (a1,a2) # define TRIO_ARGS3(list,a1,a2,a3) (a1,a2,a3) # define TRIO_ARGS4(list,a1,a2,a3,a4) (a1,a2,a3,a4) # define TRIO_ARGS5(list,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5) # define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6) # define TRIO_VARGS2 TRIO_ARGS2 # define TRIO_VARGS3 TRIO_ARGS3 # define TRIO_VARGS4 TRIO_ARGS4 # define TRIO_VARGS5 TRIO_ARGS5 # define TRIO_VA_DECL ... # define TRIO_VA_START(x,y) va_start(x,y) # define TRIO_VA_END(x) va_end(x) #endif #if defined(PREDEF_STANDARD_C99) || defined(PREDEF_STANDARD_CXX) # define TRIO_INLINE inline #else # if defined(TRIO_COMPILER_GCC) # define TRIO_INLINE __inline__ # endif # if defined(TRIO_COMPILER_MSVC) # define TRIO_INLINE _inline # endif # if defined(TRIO_COMPILER_BCB) # define TRIO_INLINE __inline # endif #endif #if !defined(TRIO_INLINE) # define TRIO_INLINE #endif /************************************************************************* * Workarounds */ #if defined(TRIO_PLATFORM_VMS) /* * Computations done with constants at compile time can trigger these * even when compiling with IEEE enabled. */ # pragma message disable (UNDERFLOW, FLOATOVERFL) # if (__CRTL_VER < 80210001) /* * Although the compiler supports C99 language constructs, the C * run-time library does not contain all C99 functions. */ # if defined(PREDEF_STANDARD_C99) # undef PREDEF_STANDARD_C99 # endif # endif #endif /* * Not all preprocessors supports the LL token. */ #if defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB) #else # define TRIO_COMPILER_SUPPORTS_LL #endif #endif /* TRIO_TRIODEF_H */ ================================================ FILE: src/sdk/src/libc/src/trio/trionan.c ================================================ /************************************************************************* * Include files */ #include "triodef.h" #include "trionan.h" #include #include #include #if !defined(TRIO_PLATFORM_SYMBIAN) # include #endif #if defined(TRIO_PLATFORM_UNIX) # include #endif #if defined(TRIO_COMPILER_DECC) # include #endif #include #if defined(TRIO_DOCUMENTATION) # include "doc/doc_nan.h" #endif /** @addtogroup SpecialQuantities @{ */ /************************************************************************* * Definitions */ #if !defined(TRIO_PUBLIC_NAN) # define TRIO_PUBLIC_NAN TRIO_PUBLIC #endif #if !defined(TRIO_PRIVATE_NAN) # define TRIO_PRIVATE_NAN TRIO_PRIVATE #endif #define TRIO_TRUE (1 == 1) #define TRIO_FALSE (0 == 1) /* * We must enable IEEE floating-point on Alpha */ #if defined(__alpha) && !defined(_IEEE_FP) # if defined(TRIO_COMPILER_DECC) # if defined(TRIO_PLATFORM_VMS) # error "Must be compiled with option /IEEE_MODE=UNDERFLOW_TO_ZERO/FLOAT=IEEE" # else # if !defined(_CFE) # error "Must be compiled with option -ieee" # endif # endif # else # if defined(TRIO_COMPILER_GCC) # error "Must be compiled with option -mieee" # endif # endif #endif /* __alpha && ! _IEEE_FP */ /* * In ANSI/IEEE 754-1985 64-bits double format numbers have the * following properties (amoungst others) * * o FLT_RADIX == 2: binary encoding * o DBL_MAX_EXP == 1024: 11 bits exponent, where one bit is used * to indicate special numbers (e.g. NaN and Infinity), so the * maximum exponent is 10 bits wide (2^10 == 1024). * o DBL_MANT_DIG == 53: The mantissa is 52 bits wide, but because * numbers are normalized the initial binary 1 is represented * implicitly (the so-called "hidden bit"), which leaves us with * the ability to represent 53 bits wide mantissa. */ #if defined(__STDC_IEC_559__) # define TRIO_IEEE_754 #else # if (FLT_RADIX - 0 == 2) && (DBL_MAX_EXP - 0 == 1024) && (DBL_MANT_DIG - 0 == 53) # define TRIO_IEEE_754 # endif #endif /* * Determine which fpclassify_and_sign() function to use. */ #if defined(TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT) # if defined(PREDEF_STANDARD_C99) && defined(fpclassify) # define TRIO_FUNC_C99_FPCLASSIFY_AND_SIGNBIT # else # if defined(TRIO_COMPILER_DECC) # define TRIO_FUNC_DECC_FPCLASSIFY_AND_SIGNBIT # else # if defined(TRIO_COMPILER_VISUALC) || defined(TRIO_COMPILER_BORLAND) # define TRIO_FUNC_MS_FPCLASSIFY_AND_SIGNBIT # else # if defined(TRIO_COMPILER_HP) && defined(FP_PLUS_NORM) # define TRIO_FUNC_HP_FPCLASSIFY_AND_SIGNBIT # else # if defined(TRIO_COMPILER_XLC) && defined(FP_PLUS_NORM) # define TRIO_FUNC_XLC_FPCLASSIFY_AND_SIGNBIT # else # define TRIO_FUNC_INTERNAL_FPCLASSIFY_AND_SIGNBIT # endif # endif # endif # endif # endif #endif /* * Determine how to generate negative zero. */ #if defined(TRIO_FUNC_NZERO) # if defined(TRIO_IEEE_754) # define TRIO_NZERO_IEEE_754 # else # define TRIO_NZERO_FALLBACK # endif #endif /* * Determine how to generate positive infinity. */ #if defined(TRIO_FUNC_PINF) # if defined(INFINITY) && defined(__STDC_IEC_559__) # define TRIO_PINF_C99_MACRO # else # if defined(TRIO_IEEE_754) # define TRIO_PINF_IEEE_754 # else # define TRIO_PINF_FALLBACK # endif # endif #endif /* * Determine how to generate NaN. */ #if defined(TRIO_FUNC_NAN) # if defined(PREDEF_STANDARD_C99) && !defined(TRIO_COMPILER_DECC) # define TRIO_NAN_C99_FUNCTION # else # if defined(NAN) && defined(__STDC_IEC_559__) # define TRIO_NAN_C99_MACRO # else # if defined(TRIO_IEEE_754) # define TRIO_NAN_IEEE_754 # else # define TRIO_NAN_FALLBACK # endif # endif # endif #endif /* * Resolve internal dependencies. */ #if defined(TRIO_FUNC_INTERNAL_FPCLASSIFY_AND_SIGNBIT) # define TRIO_FUNC_INTERNAL_ISNAN # define TRIO_FUNC_INTERNAL_ISINF # if defined(TRIO_IEEE_754) # define TRIO_FUNC_INTERNAL_IS_SPECIAL_QUANTITY # define TRIO_FUNC_INTERNAL_IS_NEGATIVE # endif #endif #if defined(TRIO_NZERO_IEEE_754) \ || defined(TRIO_PINF_IEEE_754) \ || defined(TRIO_NAN_IEEE_754) # define TRIO_FUNC_INTERNAL_MAKE_DOUBLE #endif #if defined(TRIO_FUNC_INTERNAL_ISNAN) # if defined(PREDEF_STANDARD_XPG3) # define TRIO_INTERNAL_ISNAN_XPG3 # else # if defined(TRIO_IEEE_754) # define TRIO_INTERNAL_ISNAN_IEEE_754 # else # define TRIO_INTERNAL_ISNAN_FALLBACK # endif # endif #endif #if defined(TRIO_FUNC_INTERNAL_ISINF) # if defined(TRIO_IEEE_754) # define TRIO_INTERNAL_ISINF_IEEE_754 # else # define TRIO_INTERNAL_ISINF_FALLBACK # endif #endif /************************************************************************* * Constants */ #if !defined(TRIO_EMBED_NAN) static TRIO_CONST char rcsid[] = "@(#)$Id: trionan.c,v 1.33 2005/05/29 11:57:25 breese Exp $"; #endif #if defined(TRIO_FUNC_INTERNAL_MAKE_DOUBLE) \ || defined(TRIO_FUNC_INTERNAL_IS_SPECIAL_QUANTITY) \ || defined(TRIO_FUNC_INTERNAL_IS_NEGATIVE) /* * Endian-agnostic indexing macro. * * The value of internalEndianMagic, when converted into a 64-bit * integer, becomes 0x0706050403020100 (we could have used a 64-bit * integer value instead of a double, but not all platforms supports * that type). The value is automatically encoded with the correct * endianess by the compiler, which means that we can support any * kind of endianess. The individual bytes are then used as an index * for the IEEE 754 bit-patterns and masks. */ #define TRIO_DOUBLE_INDEX(x) (((unsigned char *)&internalEndianMagic)[7-(x)]) static TRIO_CONST double internalEndianMagic = 7.949928895127363e-275; #endif #if defined(TRIO_FUNC_INTERNAL_IS_SPECIAL_QUANTITY) /* Mask for the exponent */ static TRIO_CONST unsigned char ieee_754_exponent_mask[] = { 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* Mask for the mantissa */ static TRIO_CONST unsigned char ieee_754_mantissa_mask[] = { 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; #endif #if defined(TRIO_FUNC_INTERNAL_IS_NEGATIVE) /* Mask for the sign bit */ static TRIO_CONST unsigned char ieee_754_sign_mask[] = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #if defined(TRIO_NZERO_IEEE_754) /* Bit-pattern for negative zero */ static TRIO_CONST unsigned char ieee_754_negzero_array[] = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #if defined(TRIO_PINF_IEEE_754) /* Bit-pattern for infinity */ static TRIO_CONST unsigned char ieee_754_infinity_array[] = { 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #if defined(TRIO_NAN_IEEE_754) /* Bit-pattern for quiet NaN */ static TRIO_CONST unsigned char ieee_754_qnan_array[] = { 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif /************************************************************************* * Internal functions */ /* * internal_make_double */ #if defined(TRIO_FUNC_INTERNAL_MAKE_DOUBLE) TRIO_PRIVATE_NAN double internal_make_double TRIO_ARGS1((values), TRIO_CONST unsigned char *values) { TRIO_VOLATILE double result; int i; for (i = 0; i < (int)sizeof(double); i++) { ((TRIO_VOLATILE unsigned char *)&result)[TRIO_DOUBLE_INDEX(i)] = values[i]; } return result; } #endif /* * internal_is_special_quantity */ #if defined(TRIO_FUNC_INTERNAL_IS_SPECIAL_QUANTITY) TRIO_PRIVATE_NAN int internal_is_special_quantity TRIO_ARGS2((number, has_mantissa), double number, int *has_mantissa) { unsigned int i; unsigned char current; int is_special_quantity = TRIO_TRUE; *has_mantissa = 0; for (i = 0; i < (unsigned int)sizeof(double); i++) { current = ((unsigned char *)&number)[TRIO_DOUBLE_INDEX(i)]; is_special_quantity &= ((current & ieee_754_exponent_mask[i]) == ieee_754_exponent_mask[i]); *has_mantissa |= (current & ieee_754_mantissa_mask[i]); } return is_special_quantity; } #endif /* * internal_is_negative */ #if defined(TRIO_FUNC_INTERNAL_IS_NEGATIVE) TRIO_PRIVATE_NAN int internal_is_negative TRIO_ARGS1((number), double number) { unsigned int i; int is_negative = TRIO_FALSE; for (i = 0; i < (unsigned int)sizeof(double); i++) { is_negative |= (((unsigned char *)&number)[TRIO_DOUBLE_INDEX(i)] & ieee_754_sign_mask[i]); } return is_negative; } #endif #if defined(TRIO_FUNC_C99_FPCLASSIFY_AND_SIGNBIT) TRIO_PRIVATE_NAN TRIO_INLINE int c99_fpclassify_and_signbit TRIO_ARGS2((number, is_negative), double number, int *is_negative) { *is_negative = signbit(number); switch (fpclassify(number)) { case FP_NAN: return TRIO_FP_NAN; case FP_INFINITE: return TRIO_FP_INFINITE; case FP_SUBNORMAL: return TRIO_FP_SUBNORMAL; case FP_ZERO: return TRIO_FP_ZERO; default: return TRIO_FP_NORMAL; } } #endif /* TRIO_FUNC_C99_FPCLASSIFY_AND_SIGNBIT */ #if defined(TRIO_FUNC_DECC_FPCLASSIFY_AND_SIGNBIT) TRIO_PRIVATE_NAN TRIO_INLINE int decc_fpclassify_and_signbit TRIO_ARGS2((number, is_negative), double number, int *is_negative) { switch (fp_class(number)) { case FP_QNAN: case FP_SNAN: *is_negative = TRIO_FALSE; /* NaN has no sign */ return TRIO_FP_NAN; case FP_POS_INF: *is_negative = TRIO_FALSE; return TRIO_FP_INFINITE; case FP_NEG_INF: *is_negative = TRIO_TRUE; return TRIO_FP_INFINITE; case FP_POS_DENORM: *is_negative = TRIO_FALSE; return TRIO_FP_SUBNORMAL; case FP_NEG_DENORM: *is_negative = TRIO_TRUE; return TRIO_FP_SUBNORMAL; case FP_POS_ZERO: *is_negative = TRIO_FALSE; return TRIO_FP_ZERO; case FP_NEG_ZERO: *is_negative = TRIO_TRUE; return TRIO_FP_ZERO; case FP_POS_NORM: *is_negative = TRIO_FALSE; return TRIO_FP_NORMAL; case FP_NEG_NORM: *is_negative = TRIO_TRUE; return TRIO_FP_NORMAL; default: *is_negative = (number < 0.0); return TRIO_FP_NORMAL; } } #endif /* TRIO_FUNC_DECC_FPCLASSIFY_AND_SIGNBIT */ #if defined(TRIO_FUNC_MS_FPCLASSIFY_AND_SIGNBIT) TRIO_PRIVATE_NAN int ms_fpclassify_and_signbit TRIO_ARGS2((number, is_negative), double number, int *is_negative) { int result; # if defined(TRIO_COMPILER_BORLAND) /* * The floating-point precision may be changed by the Borland _fpclass() * function, so we have to save and restore the floating-point control mask. */ unsigned int mask; /* Remember the old mask */ mask = _control87(0, 0); # endif switch (_fpclass(number)) { case _FPCLASS_QNAN: case _FPCLASS_SNAN: *is_negative = TRIO_FALSE; /* NaN has no sign */ result = TRIO_FP_NAN; break; case _FPCLASS_PINF: *is_negative = TRIO_FALSE; result = TRIO_FP_INFINITE; break; case _FPCLASS_NINF: *is_negative = TRIO_TRUE; result = TRIO_FP_INFINITE; break; case _FPCLASS_PD: *is_negative = TRIO_FALSE; result = TRIO_FP_SUBNORMAL; break; case _FPCLASS_ND: *is_negative = TRIO_TRUE; result = TRIO_FP_SUBNORMAL; break; case _FPCLASS_PZ: *is_negative = TRIO_FALSE; result = TRIO_FP_ZERO; break; case _FPCLASS_NZ: *is_negative = TRIO_TRUE; result = TRIO_FP_ZERO; break; case _FPCLASS_PN: *is_negative = TRIO_FALSE; result = TRIO_FP_NORMAL; break; case _FPCLASS_NN: *is_negative = TRIO_TRUE; result = TRIO_FP_NORMAL; break; default: *is_negative = (number < 0.0); result = TRIO_FP_NORMAL; break; } # if defined(TRIO_COMPILER_BORLAND) /* Restore the old precision */ (void)_control87(mask, MCW_PC); # endif return result; } #endif /* TRIO_FUNC_MS_FPCLASSIFY_AND_SIGNBIT */ #if defined(TRIO_FUNC_HP_FPCLASSIFY_AND_SIGNBIT) TRIO_PRIVATE_NAN TRIO_INLINE int hp_fpclassify_and_signbit TRIO_ARGS2((number, is_negative), double number, int *is_negative) { /* * HP-UX 9.x and 10.x have an fpclassify() function, that is different * from the C99 fpclassify() macro supported on HP-UX 11.x. */ switch (fpclassify(number)) { case FP_QNAN: case FP_SNAN: *is_negative = TRIO_FALSE; /* NaN has no sign */ return TRIO_FP_NAN; case FP_PLUS_INF: *is_negative = TRIO_FALSE; return TRIO_FP_INFINITE; case FP_MINUS_INF: *is_negative = TRIO_TRUE; return TRIO_FP_INFINITE; case FP_PLUS_DENORM: *is_negative = TRIO_FALSE; return TRIO_FP_SUBNORMAL; case FP_MINUS_DENORM: *is_negative = TRIO_TRUE; return TRIO_FP_SUBNORMAL; case FP_PLUS_ZERO: *is_negative = TRIO_FALSE; return TRIO_FP_ZERO; case FP_MINUS_ZERO: *is_negative = TRIO_TRUE; return TRIO_FP_ZERO; case FP_PLUS_NORM: *is_negative = TRIO_FALSE; return TRIO_FP_NORMAL; case FP_MINUS_NORM: *is_negative = TRIO_TRUE; return TRIO_FP_NORMAL; default: *is_negative = (number < 0.0); return TRIO_FP_NORMAL; } } #endif /* TRIO_FUNC_HP_FPCLASSIFY_AND_SIGNBIT */ #if defined(TRIO_FUNC_XLC_FPCLASSIFY_AND_SIGNBIT) TRIO_PRIVATE_NAN TRIO_INLINE int xlc_fpclassify_and_signbit TRIO_ARGS2((number, is_negative), double number, int *is_negative) { /* * AIX has class() for C, and _class() for C++ */ # if defined(__cplusplus) # define AIX_CLASS(n) _class(n) # else # define AIX_CLASS(n) class(n) # endif switch (AIX_CLASS(number)) { case FP_QNAN: case FP_SNAN: *is_negative = TRIO_FALSE; /* NaN has no sign */ return TRIO_FP_NAN; case FP_PLUS_INF: *is_negative = TRIO_FALSE; return TRIO_FP_INFINITE; case FP_MINUS_INF: *is_negative = TRIO_TRUE; return TRIO_FP_INFINITE; case FP_PLUS_DENORM: *is_negative = TRIO_FALSE; return TRIO_FP_SUBNORMAL; case FP_MINUS_DENORM: *is_negative = TRIO_TRUE; return TRIO_FP_SUBNORMAL; case FP_PLUS_ZERO: *is_negative = TRIO_FALSE; return TRIO_FP_ZERO; case FP_MINUS_ZERO: *is_negative = TRIO_TRUE; return TRIO_FP_ZERO; case FP_PLUS_NORM: *is_negative = TRIO_FALSE; return TRIO_FP_NORMAL; case FP_MINUS_NORM: *is_negative = TRIO_TRUE; return TRIO_FP_NORMAL; default: *is_negative = (number < 0.0); return TRIO_FP_NORMAL; } } #endif /* TRIO_FUNC_XLC_FPCLASSIFY_AND_SIGNBIT */ #if defined(TRIO_FUNC_INTERNAL_ISNAN) TRIO_PRIVATE_NAN TRIO_INLINE int internal_isnan TRIO_ARGS1((number), double number) { # if defined(TRIO_INTERNAL_ISNAN_XPG3) || defined(TRIO_PLATFORM_SYMBIAN) /* * XPG3 defines isnan() as a function. */ return isnan(number); # endif # if defined(TRIO_INTERNAL_ISNAN_IEEE_754) /* * Examine IEEE 754 bit-pattern. A NaN must have a special exponent * pattern, and a non-empty mantissa. */ int has_mantissa; int is_special_quantity; is_special_quantity = internal_is_special_quantity(number, &has_mantissa); return (is_special_quantity && has_mantissa); # endif # if defined(TRIO_INTERNAL_ISNAN_FALLBACK) /* * Fallback solution */ int status; double integral, fraction; # if defined(TRIO_PLATFORM_UNIX) void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); # endif status = (/* * NaN is the only number which does not compare to itself */ ((TRIO_VOLATILE double)number != (TRIO_VOLATILE double)number) || /* * Fallback solution if NaN compares to NaN */ ((number != 0.0) && (fraction = modf(number, &integral), integral == fraction))); # if defined(TRIO_PLATFORM_UNIX) signal(SIGFPE, signal_handler); # endif return status; # endif } #endif /* TRIO_FUNC_INTERNAL_ISNAN */ #if defined(TRIO_FUNC_INTERNAL_ISINF) TRIO_PRIVATE_NAN TRIO_INLINE int internal_isinf TRIO_ARGS1((number), double number) { # if defined(TRIO_PLATFORM_SYMBIAN) return isinf(number); # endif # if defined(TRIO_INTERNAL_ISINF_IEEE_754) /* * Examine IEEE 754 bit-pattern. Infinity must have a special exponent * pattern, and an empty mantissa. */ int has_mantissa; int is_special_quantity; is_special_quantity = internal_is_special_quantity(number, &has_mantissa); return (is_special_quantity && !has_mantissa) ? ((number < 0.0) ? -1 : 1) : 0; # endif # if defined(TRIO_INTERNAL_ISINF_FALLBACK) /* * Fallback solution. */ int status; # if defined(TRIO_PLATFORM_UNIX) void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); # endif double infinity = trio_pinf(); status = ((number == infinity) ? 1 : ((number == -infinity) ? -1 : 0)); # if defined(TRIO_PLATFORM_UNIX) signal(SIGFPE, signal_handler); # endif return status; # endif } #endif /* TRIO_FUNC_INTERNAL_ISINF */ /************************************************************************* * Public functions */ #if defined(TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT) TRIO_PUBLIC_NAN int trio_fpclassify_and_signbit TRIO_ARGS2((number, is_negative), double number, int *is_negative) { /* The TRIO_FUNC_xxx_FPCLASSIFY_AND_SIGNBIT macros are mutually exclusive */ #if defined(TRIO_FUNC_C99_FPCLASSIFY_AND_SIGNBIT) return c99_fpclassify_and_signbit(number, is_negative); #endif #if defined(TRIO_FUNC_DECC_FPCLASSIFY_AND_SIGNBIT) return decc_fpclassify_and_signbit(number, is_negative); #endif #if defined(TRIO_FUNC_MS_FPCLASSIFY_AND_SIGNBIT) return ms_fpclassify_and_signbit(number, is_negative); #endif #if defined(TRIO_FUNC_HP_FPCLASSIFY_AND_SIGNBIT) return hp_fpclassify_and_signbit(number, is_negative); #endif #if defined(TRIO_FUNC_XLC_FPCLASSIFY_AND_SIGNBIT) return xlc_fpclassify_and_signbit(number, is_negative); #endif #if defined(TRIO_FUNC_INTERNAL_FPCLASSIFY_AND_SIGNBIT) /* * Fallback solution. */ int rc; if (number == 0.0) { /* * In IEEE 754 the sign of zero is ignored in comparisons, so we * have to handle this as a special case by examining the sign bit * directly. */ # if defined(TRIO_IEEE_754) *is_negative = internal_is_negative(number); # else *is_negative = TRIO_FALSE; /* FIXME */ # endif return TRIO_FP_ZERO; } if (internal_isnan(number)) { *is_negative = TRIO_FALSE; return TRIO_FP_NAN; } rc = internal_isinf(number); if (rc != 0) { *is_negative = (rc == -1); return TRIO_FP_INFINITE; } if ((number > 0.0) && (number < DBL_MIN)) { *is_negative = TRIO_FALSE; return TRIO_FP_SUBNORMAL; } if ((number < 0.0) && (number > -DBL_MIN)) { *is_negative = TRIO_TRUE; return TRIO_FP_SUBNORMAL; } *is_negative = (number < 0.0); return TRIO_FP_NORMAL; #endif } #endif /** Check for NaN. @param number An arbitrary floating-point number. @return Boolean value indicating whether or not the number is a NaN. */ #if defined(TRIO_FUNC_ISNAN) TRIO_PUBLIC_NAN int trio_isnan TRIO_ARGS1((number), double number) { int dummy; return (trio_fpclassify_and_signbit(number, &dummy) == TRIO_FP_NAN); } #endif /** Check for infinity. @param number An arbitrary floating-point number. @return 1 if positive infinity, -1 if negative infinity, 0 otherwise. */ #if defined(TRIO_FUNC_ISINF) TRIO_PUBLIC_NAN int trio_isinf TRIO_ARGS1((number), double number) { int is_negative; if (trio_fpclassify_and_signbit(number, &is_negative) == TRIO_FP_INFINITE) { return (is_negative) ? -1 : 1; } else { return 0; } } #endif /** Check for finity. @param number An arbitrary floating-point number. @return Boolean value indicating whether or not the number is a finite. */ #if defined(TRIO_FUNC_ISFINITE) TRIO_PUBLIC_NAN int trio_isfinite TRIO_ARGS1((number), double number) { int dummy; switch (trio_fpclassify_and_signbit(number, &dummy)) { case TRIO_FP_INFINITE: case TRIO_FP_NAN: return 0; default: return 1; } } #endif /** Examine the sign of a number. @param number An arbitrary floating-point number. @return Boolean value indicating whether or not the number has the sign bit set (i.e. is negative). */ #if defined(TRIO_FUNC_SIGNBIT) TRIO_PUBLIC_NAN int trio_signbit TRIO_ARGS1((number), double number) { int is_negative; (void)trio_fpclassify_and_signbit(number, &is_negative); return is_negative; } #endif /** Examine the class of a number. @param number An arbitrary floating-point number. @return Enumerable value indicating the class of @p number */ #if defined(TRIO_FUNC_FPCLASSIFY) TRIO_PUBLIC_NAN int trio_fpclassify TRIO_ARGS1((number), double number) { int dummy; return trio_fpclassify_and_signbit(number, &dummy); } #endif /** Generate negative zero. @return Floating-point representation of negative zero. */ #if defined(TRIO_FUNC_NZERO) TRIO_PUBLIC_NAN double trio_nzero(TRIO_NOARGS) { # if defined(TRIO_NZERO_IEEE_754) return internal_make_double(ieee_754_negzero_array); # endif # if defined(TRIO_NZERO_FALLBACK) TRIO_VOLATILE double zero = 0.0; return -zero; # endif } #endif /** Generate positive infinity. @return Floating-point representation of positive infinity. */ #if defined(TRIO_FUNC_PINF) TRIO_PUBLIC_NAN double trio_pinf(TRIO_NOARGS) { /* Cache the result */ static double pinf_value = 0.0; if (pinf_value == 0.0) { # if defined(TRIO_PINF_C99_MACRO) pinf_value = (double)INFINITY; # endif # if defined(TRIO_PINF_IEEE_754) pinf_value = internal_make_double(ieee_754_infinity_array); # endif # if defined(TRIO_PINF_FALLBACK) /* * If HUGE_VAL is different from DBL_MAX, then HUGE_VAL is used * as infinity. Otherwise we have to resort to an overflow * operation to generate infinity. */ # if defined(TRIO_PLATFORM_UNIX) void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); # endif pinf_value = HUGE_VAL; if (HUGE_VAL == DBL_MAX) { /* Force overflow */ pinf_value += HUGE_VAL; } # if defined(TRIO_PLATFORM_UNIX) signal(SIGFPE, signal_handler); # endif # endif } return pinf_value; } #endif /** Generate negative infinity. @return Floating-point value of negative infinity. */ #if defined(TRIO_FUNC_NINF) TRIO_PUBLIC_NAN double trio_ninf(TRIO_NOARGS) { static double ninf_value = 0.0; if (ninf_value == 0.0) { /* * Negative infinity is calculated by negating positive infinity, * which can be done because it is legal to do calculations on * infinity (for example, 1 / infinity == 0). */ ninf_value = -trio_pinf(); } return ninf_value; } #endif /** Generate NaN. @return Floating-point representation of NaN. */ #if defined(TRIO_FUNC_NAN) TRIO_PUBLIC_NAN double trio_nan(TRIO_NOARGS) { /* Cache the result */ static double nan_value = 0.0; if (nan_value == 0.0) { # if defined(TRIO_NAN_C99_FUNCTION) || defined(TRIO_PLATFORM_SYMBIAN) nan_value = nan(""); # endif # if defined(TRIO_NAN_C99_MACRO) nan_value = (double)NAN; # endif # if defined(TRIO_NAN_IEEE_754) nan_value = internal_make_double(ieee_754_qnan_array); # endif # if defined(TRIO_NAN_FALLBACK) /* * There are several ways to generate NaN. The one used here is * to divide infinity by infinity. I would have preferred to add * negative infinity to positive infinity, but that yields wrong * result (infinity) on FreeBSD. * * This may fail if the hardware does not support NaN, or if * the Invalid Operation floating-point exception is unmasked. */ # if defined(TRIO_PLATFORM_UNIX) void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); # endif nan_value = trio_pinf() / trio_pinf(); # if defined(TRIO_PLATFORM_UNIX) signal(SIGFPE, signal_handler); # endif # endif } return nan_value; } #endif /** @} SpecialQuantities */ /************************************************************************* * For test purposes. * * Add the following compiler option to include this test code. * * Unix : -DSTANDALONE * VMS : /DEFINE=(STANDALONE) */ #if defined(STANDALONE) # include static TRIO_CONST char * getClassification TRIO_ARGS1((type), int type) { switch (type) { case TRIO_FP_INFINITE: return "FP_INFINITE"; case TRIO_FP_NAN: return "FP_NAN"; case TRIO_FP_NORMAL: return "FP_NORMAL"; case TRIO_FP_SUBNORMAL: return "FP_SUBNORMAL"; case TRIO_FP_ZERO: return "FP_ZERO"; default: return "FP_UNKNOWN"; } } static void print_class TRIO_ARGS2((prefix, number), TRIO_CONST char *prefix, double number) { printf("%-6s: %s %-15s %g\n", prefix, trio_signbit(number) ? "-" : "+", getClassification(trio_fpclassify(number)), number); } int main(TRIO_NOARGS) { double my_nan; double my_pinf; double my_ninf; # if defined(TRIO_PLATFORM_UNIX) void (*signal_handler) TRIO_PROTO((int)); # endif my_nan = trio_nan(); my_pinf = trio_pinf(); my_ninf = trio_ninf(); print_class("Nan", my_nan); print_class("PInf", my_pinf); print_class("NInf", my_ninf); print_class("PZero", 0.0); print_class("NZero", -0.0); print_class("PNorm", 1.0); print_class("NNorm", -1.0); print_class("PSub", 1.01e-307 - 1.00e-307); print_class("NSub", 1.00e-307 - 1.01e-307); printf("NaN : %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d, %2d)\n", my_nan, ((unsigned char *)&my_nan)[0], ((unsigned char *)&my_nan)[1], ((unsigned char *)&my_nan)[2], ((unsigned char *)&my_nan)[3], ((unsigned char *)&my_nan)[4], ((unsigned char *)&my_nan)[5], ((unsigned char *)&my_nan)[6], ((unsigned char *)&my_nan)[7], trio_isnan(my_nan), trio_isinf(my_nan), trio_isfinite(my_nan)); printf("PInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d, %2d)\n", my_pinf, ((unsigned char *)&my_pinf)[0], ((unsigned char *)&my_pinf)[1], ((unsigned char *)&my_pinf)[2], ((unsigned char *)&my_pinf)[3], ((unsigned char *)&my_pinf)[4], ((unsigned char *)&my_pinf)[5], ((unsigned char *)&my_pinf)[6], ((unsigned char *)&my_pinf)[7], trio_isnan(my_pinf), trio_isinf(my_pinf), trio_isfinite(my_pinf)); printf("NInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d, %2d)\n", my_ninf, ((unsigned char *)&my_ninf)[0], ((unsigned char *)&my_ninf)[1], ((unsigned char *)&my_ninf)[2], ((unsigned char *)&my_ninf)[3], ((unsigned char *)&my_ninf)[4], ((unsigned char *)&my_ninf)[5], ((unsigned char *)&my_ninf)[6], ((unsigned char *)&my_ninf)[7], trio_isnan(my_ninf), trio_isinf(my_ninf), trio_isfinite(my_ninf)); # if defined(TRIO_PLATFORM_UNIX) signal_handler = signal(SIGFPE, SIG_IGN); # endif my_pinf = DBL_MAX + DBL_MAX; my_ninf = -my_pinf; my_nan = my_pinf / my_pinf; # if defined(TRIO_PLATFORM_UNIX) signal(SIGFPE, signal_handler); # endif printf("NaN : %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d, %2d)\n", my_nan, ((unsigned char *)&my_nan)[0], ((unsigned char *)&my_nan)[1], ((unsigned char *)&my_nan)[2], ((unsigned char *)&my_nan)[3], ((unsigned char *)&my_nan)[4], ((unsigned char *)&my_nan)[5], ((unsigned char *)&my_nan)[6], ((unsigned char *)&my_nan)[7], trio_isnan(my_nan), trio_isinf(my_nan), trio_isfinite(my_nan)); printf("PInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d, %2d)\n", my_pinf, ((unsigned char *)&my_pinf)[0], ((unsigned char *)&my_pinf)[1], ((unsigned char *)&my_pinf)[2], ((unsigned char *)&my_pinf)[3], ((unsigned char *)&my_pinf)[4], ((unsigned char *)&my_pinf)[5], ((unsigned char *)&my_pinf)[6], ((unsigned char *)&my_pinf)[7], trio_isnan(my_pinf), trio_isinf(my_pinf), trio_isfinite(my_pinf)); printf("NInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d, %2d)\n", my_ninf, ((unsigned char *)&my_ninf)[0], ((unsigned char *)&my_ninf)[1], ((unsigned char *)&my_ninf)[2], ((unsigned char *)&my_ninf)[3], ((unsigned char *)&my_ninf)[4], ((unsigned char *)&my_ninf)[5], ((unsigned char *)&my_ninf)[6], ((unsigned char *)&my_ninf)[7], trio_isnan(my_ninf), trio_isinf(my_ninf), trio_isfinite(my_ninf)); return 0; } #endif ================================================ FILE: src/sdk/src/libc/src/trio/trionan.h ================================================ #ifndef TRIO_TRIONAN_H #define TRIO_TRIONAN_H #include "triodef.h" #ifdef __cplusplus extern "C" { #endif #if !defined(TRIO_PUBLIC_NAN) # if !defined(TRIO_PUBLIC) # define TRIO_PUBLIC # endif # define TRIO_PUBLIC_NAN TRIO_PUBLIC #endif enum { TRIO_FP_INFINITE, TRIO_FP_NAN, TRIO_FP_NORMAL, TRIO_FP_SUBNORMAL, TRIO_FP_ZERO }; /************************************************************************* * Dependencies */ #if defined(TRIO_EMBED_NAN) /* * The application that trionan is embedded in must define which functions * it uses. * * The following resolves internal dependencies. */ # if defined(TRIO_FUNC_ISNAN) \ || defined(TRIO_FUNC_ISINF) # if !defined(TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT) # define TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT # endif # endif # if defined(TRIO_FUNC_NAN) # if !defined(TRIO_FUNC_PINF) # define TRIO_FUNC_PINF # endif # endif # if defined(TRIO_FUNC_NINF) # if !defined(TRIO_FUNC_PINF) # define TRIO_FUNC_PINF # endif # endif #else /* * When trionan is not embedded all all functions are defined. */ # define TRIO_FUNC_NAN # define TRIO_FUNC_PINF # define TRIO_FUNC_NINF # define TRIO_FUNC_NZERO # define TRIO_FUNC_ISNAN # define TRIO_FUNC_ISINF # define TRIO_FUNC_ISFINITE # define TRIO_FUNC_SIGNBIT # define TRIO_FUNC_FPCLASSIFY # define TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT #endif /************************************************************************* * Functions */ /* * Return NaN (Not-a-Number). */ #if defined(TRIO_FUNC_NAN) TRIO_PUBLIC_NAN double trio_nan TRIO_PROTO((void)); #endif /* * Return positive infinity. */ #if defined(TRIO_FUNC_PINF) TRIO_PUBLIC_NAN double trio_pinf TRIO_PROTO((void)); #endif /* * Return negative infinity. */ #if defined(TRIO_FUNC_NINF) TRIO_PUBLIC_NAN double trio_ninf TRIO_PROTO((void)); #endif /* * Return negative zero. */ #if defined(TRIO_FUNC_NZERO) TRIO_PUBLIC_NAN double trio_nzero TRIO_PROTO((TRIO_NOARGS)); #endif /* * If number is a NaN return non-zero, otherwise return zero. */ #if defined(TRIO_FUNC_ISNAN) TRIO_PUBLIC_NAN int trio_isnan TRIO_PROTO((double number)); #endif /* * If number is positive infinity return 1, if number is negative * infinity return -1, otherwise return 0. */ #if defined(TRIO_FUNC_ISINF) TRIO_PUBLIC_NAN int trio_isinf TRIO_PROTO((double number)); #endif /* * If number is finite return non-zero, otherwise return zero. */ #if defined(TRIO_FUNC_ISFINITE) TRIO_PUBLIC_NAN int trio_isfinite TRIO_PROTO((double number)); #endif #if defined(TRIO_FUNC_SIGNBIT) TRIO_PUBLIC_NAN int trio_signbit TRIO_PROTO((double number)); #endif #if defined(TRIO_FUNC_FPCLASSIFY) TRIO_PUBLIC_NAN int trio_fpclassify TRIO_PROTO((double number)); #endif #if defined(TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT) TRIO_PUBLIC_NAN int trio_fpclassify_and_signbit TRIO_PROTO((double number, int *is_negative)); #endif #ifdef __cplusplus } #endif #endif /* TRIO_TRIONAN_H */ ================================================ FILE: src/sdk/src/libc/src/trio/triop.h ================================================ #ifndef TRIO_TRIOP_H #define TRIO_TRIOP_H #include "triodef.h" #include #if defined(TRIO_COMPILER_ANCIENT) # include #else # include #endif #ifdef __cplusplus extern "C" { #endif /************************************************************************* * Supported standards */ /* * TRIO_C99 (=0 or =1) * * Define this to 0 to disable C99 format specifier extensions, or * define to 1 to enable them. The format specifiers that are * disabled by this switch are labelled with [C99] in the format * specifier documentation. */ #if !defined(TRIO_C99) # define TRIO_C99 1 #endif /* * TRIO_BSD (=0 or =1) * * Define this to 0 to disable BSD format specifier extensions, or * define to 1 to enable them. The format specifiers that are * disabled by this switch are labelled with [BSD] in the format * specifier documentation. */ #if !defined(TRIO_BSD) # define TRIO_BSD 1 #endif /* * TRIO_GNU (=0 or =1) * * Define this to 0 to disable GNU format specifier extensions, or * define to 1 to enable them. The format specifiers that are * disabled by this switch are labelled with [GNU] in the format * specifier documentation. */ #if !defined(TRIO_GNU) # define TRIO_GNU 1 #endif /* * TRIO_MISC (=0 or =1) * * Define this to 0 to disable miscellaneous format specifier * extensions, or define to 1 to enable them. The format specifiers * that are disabled by this switch are labelled with [MISC] in the * format specifier documentation. */ #if !defined(TRIO_MISC) # define TRIO_MISC 1 #endif /* * TRIO_UNIX98 (=0 or =1) * * Define this to 0 to disable UNIX98 format specifier extensions, * or define to 1 to enable them. The format specifiers that are * disabled by this switch are labelled with [UNIX98] in the format * specifier documentation. */ #if !defined(TRIO_UNIX98) # define TRIO_UNIX98 1 #endif /* * TRIO_MICROSOFT (=0 or =1) * * Define this to 0 to disable Microsoft Visual C format specifier * extensions, or define to 1 to enable them. The format specifiers * that are disabled by this switch are labelled with [MSVC] in the * format specifier documentation. */ #if !defined(TRIO_MICROSOFT) # define TRIO_MICROSOFT 1 #endif /* * TRIO_EXTENSION (=0 or =1) * * Define this to 0 to disable Trio-specific extensions, or define * to 1 to enable them. This has two effects: it controls whether * or not the Trio user-defined formating mechanism * (trio_register() etc) is supported, and it enables or disables * Trio's own format specifier extensions. The format specifiers * that are disabled by this switch are labelled with [TRIO] in * the format specifier documentation. */ #if !defined(TRIO_EXTENSION) # define TRIO_EXTENSION 1 #endif /* * TRIO_DEPRECATED (=0 or =1) * * Define this to 0 to disable deprecated functionality, or define * to 1 to enable them. */ #if !defined(TRIO_DEPRECATED) # define TRIO_DEPRECATED 1 #endif /************************************************************************* * Features */ #if defined(TRIO_SNPRINTF_ONLY) # define TRIO_FEATURE_SCANF 0 # define TRIO_FEATURE_FILE 0 # define TRIO_FEATURE_STDIO 0 # define TRIO_FEATURE_FD 0 # define TRIO_FEATURE_DYNAMICSTRING 0 # define TRIO_FEATURE_CLOSURE 0 # define TRIO_FEATURE_STRERR 0 # define TRIO_FEATURE_LOCALE 0 # define TRIO_EMBED_NAN 1 # define TRIO_EMBED_STRING 1 #endif /* * TRIO_FEATURE_SCANF (=0 or =1) * * Define this to 0 to disable all the scanf() variants, or define to 1 * to enable them. */ #if !defined(TRIO_FEATURE_SCANF) # define TRIO_FEATURE_SCANF 1 #endif /* * TRIO_FEATURE_FILE (=0 or =1) * * Define this to 0 to disable compilation of the trio_fprintf() and * trio_fscanf() family of functions, or define to 1 to enable them. * * This may be useful on an embedded platform with no filesystem. * Note that trio_printf() uses fwrite to write to stdout, so if you * do not have an implementation of fwrite() at all then you must also * define TRIO_FEATURE_STDIO to 0. */ #if !defined(TRIO_FEATURE_FILE) # define TRIO_FEATURE_FILE 1 #endif /* * TRIO_FEATURE_STDIO (=0 or =1) * * Define this to 0 to disable compilation of the trio_printf() and * trio_scanf() family of functions, or define to 1 to enable them. * * This may be useful on an embedded platform with no standard I/O. */ #if !defined(TRIO_FEATURE_STDIO) # define TRIO_FEATURE_STDIO 1 #endif /* * TRIO_FEATURE_FD (=0 or =1) * * Define this to 0 to disable compilation of the trio_dprintf() and * trio_dscanf() family of functions, or define to 1 to enable them. * * This may be useful on an embedded platform with no filesystem, or on * a platform that supports file I/O using FILE* but not using raw file * descriptors. */ #if !defined(TRIO_FEATURE_FD) # define TRIO_FEATURE_FD 1 #endif /* * TRIO_FEATURE_DYNAMICSTRING (=0 or =1) * * Define this to 0 to disable compilation of the trio_aprintf() * family of functions, or define to 1 to enable them. * * If you define both this and TRIO_MINIMAL to 0, then Trio will never * call malloc or free. */ #if !defined(TRIO_FEATURE_DYNAMICSTRING) # define TRIO_FEATURE_DYNAMICSTRING 1 #endif /* * TRIO_FEATURE_CLOSURE (=0 or =1) * * Define this to 0 to disable compilation of the trio_cprintf() and * trio_cscanf() family of functions, or define to 1 to enable them. * * These functions are rarely needed. This saves a (small) amount of code. */ #if !defined(TRIO_FEATURE_CLOSURE) # define TRIO_FEATURE_CLOSURE 1 #endif /* * TRIO_FEATURE_ERRORCODE (=0 or =1) * * Define this to 0 to return -1 from the print and scan function on * error, or define to 1 to return a negative number with debugging * information as part of the return code. * * If enabled, the return code will be a negative number, which encodes * an error code and an error location. These can be decoded with the * TRIO_ERROR_CODE and TRIO_ERROR_POSITION macros. */ #if defined(TRIO_ERRORS) # define TRIO_FEATURE_ERRORCODE TRIO_ERRORS #endif #if !defined(TRIO_FEATURE_ERRORCODE) # define TRIO_FEATURE_ERRORCODE 1 #endif /* * TRIO_FEATURE_STRERR (=0 or =1) * * Define this to 0 if you do not use trio_strerror(), or define to 1 if * you do use it. * * This saves a (small) amount of code. */ #if !defined(TRIO_FEATURE_STRERR) # define TRIO_FEATURE_STRERR 1 #endif /* * TRIO_FEATURE_FLOAT (=0 or =1) * * Define this to 0 to disable all floating-point support, or define * to 1 to enable it. * * This is useful in restricted embedded platforms that do not support * floating-point. Obviously you cannot use floating-point format * specifiers if you define this. * * Do not compile trionan.c if you disable this. */ #if !defined(TRIO_FEATURE_FLOAT) # define TRIO_FEATURE_FLOAT 1 #endif /* * TRIO_FEATURE_LOCALE (=0 or =1) * * Define this to 0 to disable customized locale support, or define * to 1 to enable it. * * This saves a (small) amount of code. */ #if !defined(TRIO_FEATURE_LOCALE) # define TRIO_FEATURE_LOCALE 1 #endif /* * TRIO_MINIMAL * * Define this to disable building the public trionan.h and triostr.h. * If you define this, then you must not compile trionan.c and triostr.c * separately. */ #if defined(TRIO_MINIMAL) # if !defined(TRIO_EMBED_NAN) # define TRIO_EMBED_NAN # endif # if !defined(TRIO_EMBED_STRING) # define TRIO_EMBED_STRING # endif #endif /* Does not work yet. Do not enable */ #ifndef TRIO_FEATURE_WIDECHAR # define TRIO_FEATURE_WIDECHAR 0 #endif /************************************************************************* * Mapping standards to internal features */ #if !defined(TRIO_FEATURE_HEXFLOAT) # define TRIO_FEATURE_HEXFLOAT (TRIO_C99 && TRIO_FEATURE_FLOAT) #endif #if !defined(TRIO_FEATURE_LONGDOUBLE) # define TRIO_FEATURE_LONGDOUBLE TRIO_FEATURE_FLOAT #endif #if !defined(TRIO_FEATURE_ERRNO) # define TRIO_FEATURE_ERRNO TRIO_GNU #endif #if !defined(TRIO_FEATURE_QUAD) # define TRIO_FEATURE_QUAD (TRIO_BSD || TRIO_GNU) #endif #if !defined(TRIO_FEATURE_SIZE_T) # define TRIO_FEATURE_SIZE_T TRIO_C99 #endif #if !defined(TRIO_FEATURE_SIZE_T_UPPER) # define TRIO_FEATURE_SIZE_T_UPPER TRIO_GNU #endif #if !defined(TRIO_FEATURE_PTRDIFF_T) # define TRIO_FEATURE_PTRDIFF_T TRIO_C99 #endif #if !defined(TRIO_FEATURE_INTMAX_T) # define TRIO_FEATURE_INTMAX_T TRIO_C99 #endif #if !defined(TRIO_FEATURE_FIXED_SIZE) # define TRIO_FEATURE_FIXED_SIZE TRIO_MICROSOFT #endif #if !defined(TRIO_FEATURE_POSITIONAL) # define TRIO_FEATURE_POSITIONAL TRIO_UNIX98 #endif #if !defined(TRIO_FEATURE_USER_DEFINED) # define TRIO_FEATURE_USER_DEFINED TRIO_EXTENSION #endif #if !defined(TRIO_FEATURE_BINARY) # define TRIO_FEATURE_BINARY TRIO_EXTENSION #endif #if !defined(TRIO_FEATURE_QUOTE) # define TRIO_FEATURE_QUOTE TRIO_EXTENSION #endif #if !defined(TRIO_FEATURE_STICKY) # define TRIO_FEATURE_STICKY TRIO_EXTENSION #endif #if !defined(TRIO_FEATURE_VARSIZE) # define TRIO_FEATURE_VARSIZE TRIO_EXTENSION #endif #if !defined(TRIO_FEATURE_ROUNDING) # define TRIO_FEATURE_ROUNDING TRIO_EXTENSION #endif /************************************************************************* * Memory handling */ #ifndef TRIO_MALLOC # define TRIO_MALLOC(n) malloc(n) #endif #ifndef TRIO_REALLOC # define TRIO_REALLOC(x,n) realloc((x),(n)) #endif #ifndef TRIO_FREE # define TRIO_FREE(x) free(x) #endif /************************************************************************* * User-defined specifiers */ typedef int (*trio_callback_t) TRIO_PROTO((trio_pointer_t)); trio_pointer_t trio_register TRIO_PROTO((trio_callback_t callback, const char *name)); void trio_unregister TRIO_PROTO((trio_pointer_t handle)); TRIO_CONST char *trio_get_format TRIO_PROTO((trio_pointer_t ref)); trio_pointer_t trio_get_argument TRIO_PROTO((trio_pointer_t ref)); /* Modifiers */ int trio_get_width TRIO_PROTO((trio_pointer_t ref)); void trio_set_width TRIO_PROTO((trio_pointer_t ref, int width)); int trio_get_precision TRIO_PROTO((trio_pointer_t ref)); void trio_set_precision TRIO_PROTO((trio_pointer_t ref, int precision)); int trio_get_base TRIO_PROTO((trio_pointer_t ref)); void trio_set_base TRIO_PROTO((trio_pointer_t ref, int base)); int trio_get_padding TRIO_PROTO((trio_pointer_t ref)); void trio_set_padding TRIO_PROTO((trio_pointer_t ref, int is_padding)); int trio_get_short TRIO_PROTO((trio_pointer_t ref)); /* h */ void trio_set_shortshort TRIO_PROTO((trio_pointer_t ref, int is_shortshort)); int trio_get_shortshort TRIO_PROTO((trio_pointer_t ref)); /* hh */ void trio_set_short TRIO_PROTO((trio_pointer_t ref, int is_short)); int trio_get_long TRIO_PROTO((trio_pointer_t ref)); /* l */ void trio_set_long TRIO_PROTO((trio_pointer_t ref, int is_long)); int trio_get_longlong TRIO_PROTO((trio_pointer_t ref)); /* ll */ void trio_set_longlong TRIO_PROTO((trio_pointer_t ref, int is_longlong)); int trio_get_longdouble TRIO_PROTO((trio_pointer_t ref)); /* L */ void trio_set_longdouble TRIO_PROTO((trio_pointer_t ref, int is_longdouble)); int trio_get_alternative TRIO_PROTO((trio_pointer_t ref)); /* # */ void trio_set_alternative TRIO_PROTO((trio_pointer_t ref, int is_alternative)); int trio_get_alignment TRIO_PROTO((trio_pointer_t ref)); /* - */ void trio_set_alignment TRIO_PROTO((trio_pointer_t ref, int is_leftaligned)); int trio_get_spacing TRIO_PROTO((trio_pointer_t ref)); /* TRIO_PROTO((space) */ void trio_set_spacing TRIO_PROTO((trio_pointer_t ref, int is_space)); int trio_get_sign TRIO_PROTO((trio_pointer_t ref)); /* + */ void trio_set_sign TRIO_PROTO((trio_pointer_t ref, int is_showsign)); #if TRIO_FEATURE_QUOTE int trio_get_quote TRIO_PROTO((trio_pointer_t ref)); /* ' */ void trio_set_quote TRIO_PROTO((trio_pointer_t ref, int is_quote)); #endif int trio_get_upper TRIO_PROTO((trio_pointer_t ref)); void trio_set_upper TRIO_PROTO((trio_pointer_t ref, int is_upper)); #if TRIO_FEATURE_INTMAX_T int trio_get_largest TRIO_PROTO((trio_pointer_t ref)); /* j */ void trio_set_largest TRIO_PROTO((trio_pointer_t ref, int is_largest)); #endif #if TRIO_FEATURE_PTRDIFF_T int trio_get_ptrdiff TRIO_PROTO((trio_pointer_t ref)); /* t */ void trio_set_ptrdiff TRIO_PROTO((trio_pointer_t ref, int is_ptrdiff)); #endif #if TRIO_FEATURE_SIZE_T int trio_get_size TRIO_PROTO((trio_pointer_t ref)); /* z / Z */ void trio_set_size TRIO_PROTO((trio_pointer_t ref, int is_size)); #endif /* Printing */ int trio_print_ref TRIO_PROTO((trio_pointer_t ref, const char *format, ...)); int trio_vprint_ref TRIO_PROTO((trio_pointer_t ref, const char *format, va_list args)); int trio_printv_ref TRIO_PROTO((trio_pointer_t ref, const char *format, trio_pointer_t *args)); void trio_print_int TRIO_PROTO((trio_pointer_t ref, int number)); void trio_print_uint TRIO_PROTO((trio_pointer_t ref, unsigned int number)); /* void trio_print_long TRIO_PROTO((trio_pointer_t ref, long number)); */ /* void trio_print_ulong TRIO_PROTO((trio_pointer_t ref, unsigned long number)); */ void trio_print_double TRIO_PROTO((trio_pointer_t ref, double number)); void trio_print_string TRIO_PROTO((trio_pointer_t ref, char *string)); void trio_print_pointer TRIO_PROTO((trio_pointer_t ref, trio_pointer_t pointer)); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* TRIO_TRIOP_H */ ================================================ FILE: src/sdk/src/libc/src/trio/triostr.c ================================================ #if defined(HAVE_CONFIG_H) # include #endif #include #include #include #include #include "triodef.h" #include "triostr.h" #if defined(TRIO_FUNC_TO_LONG_DOUBLE) # define USE_MATH #endif #if defined(USE_MATH) # include #endif /************************************************************************* * Definitions */ #if !defined(TRIO_PUBLIC_STRING) # define TRIO_PUBLIC_STRING TRIO_PUBLIC #endif #if !defined(TRIO_PRIVATE_STRING) # define TRIO_PRIVATE_STRING TRIO_PRIVATE #endif #if !defined(NULL) # define NULL 0 #endif #if !defined(NIL) # define NIL ((char)0) #endif #if !defined(FALSE) # define FALSE (1 == 0) # define TRUE (! FALSE) #endif #if !defined(BOOLEAN_T) # define BOOLEAN_T int #endif #if defined(USE_MATH) # if defined(PREDEF_STANDARD_C99) # if defined(TRIO_COMPILER_DECC) # if (TRIO_COMPILER_DECC - 0 > 80000000) /* * The OSF/1 runtime that comes with the DECC compiler does not support * hexfloats conversion. */ # define USE_STRTOD # define USE_STRTOF # endif # else # define USE_STRTOD # define USE_STRTOF # endif # else # if defined(TRIO_COMPILER_VISUALC) # define USE_STRTOD # endif #endif #endif #if defined(TRIO_PLATFORM_UNIX) # if defined(PREDEF_STANDARD_UNIX95) # define USE_STRCASECMP # define USE_STRNCASECMP # endif # if defined(TRIO_PLATFORM_SUNOS) # define USE_SYS_ERRLIST # else # define USE_STRERROR # endif # if defined(TRIO_PLATFORM_QNX) # define strcasecmp(x,y) stricmp(x,y) # define strncasecmp(x,y,n) strnicmp(x,y,n) # endif #endif #if defined(TRIO_PLATFORM_WIN32) # define USE_STRCASECMP # if defined(TRIO_PLATFORM_WINCE) # define strcasecmp(x,y) _stricmp(x,y) # else # define strcasecmp(x,y) strcmpi(x,y) # endif #endif #if !defined(HAVE_CONFIG_H) # if !(defined(TRIO_PLATFORM_SUNOS)) # define HAVE_TOLOWER # define HAVE_TOUPPER # endif #endif #if defined(USE_MATH) # if !defined(HAVE_POWL) # if defined(PREDEF_STANDARD_C99) \ || defined(PREDEF_STANDARD_UNIX03) # define HAVE_POWL # else # if defined(TRIO_COMPILER_VISUALC) # if defined(powl) # define HAVE_POWL # endif # endif # endif # endif #endif #if defined(HAVE_POWL) # define trio_powl(x,y) powl((x),(y)) #else # define trio_powl(x,y) pow((double)(x),(double)(y)) #endif #if defined(TRIO_FUNC_TO_UPPER) \ || (defined(TRIO_FUNC_EQUAL) && !defined(USE_STRCASECMP)) \ || (defined(TRIO_FUNC_EQUAL_MAX) && !defined(USE_STRNCASECMP)) \ || defined(TRIO_FUNC_MATCH) \ || defined(TRIO_FUNC_TO_LONG_DOUBLE) \ || defined(TRIO_FUNC_UPPER) # define TRIO_FUNC_INTERNAL_TO_UPPER #endif /************************************************************************* * Structures */ struct _trio_string_t { char *content; size_t length; size_t allocated; }; /************************************************************************* * Constants */ #if !defined(TRIO_EMBED_STRING) static TRIO_CONST char rcsid[] = "@(#)$Id: triostr.c,v 1.34 2008/11/09 12:17:39 breese Exp $"; #endif /************************************************************************* * Static String Functions */ #if defined(TRIO_DOCUMENTATION) # include "doc/doc_static.h" #endif /** @addtogroup StaticStrings @{ */ /* * internal_duplicate_max */ #if defined(TRIO_FUNC_DUPLICATE) \ || defined(TRIO_FUNC_DUPLICATE_MAX) \ || defined(TRIO_FUNC_STRING_DUPLICATE) \ || defined(TRIO_FUNC_XSTRING_DUPLICATE) TRIO_PRIVATE_STRING char * internal_duplicate_max TRIO_ARGS2((source, size), TRIO_CONST char *source, size_t size) { char *target; assert(source); /* Make room for string plus a terminating zero */ size++; target = trio_create(size); if (target) { trio_copy_max(target, size, source); } return target; } #endif /* * internal_string_alloc */ #if defined(TRIO_FUNC_STRING_CREATE) \ || defined(TRIO_FUNC_STRING_DUPLICATE) \ || defined(TRIO_FUNC_XSTRING_DUPLICATE) TRIO_PRIVATE_STRING trio_string_t * internal_string_alloc(TRIO_NOARGS) { trio_string_t *self; self = (trio_string_t *)TRIO_MALLOC(sizeof(trio_string_t)); if (self) { self->content = NULL; self->length = 0; self->allocated = 0; } return self; } #endif /* * internal_string_grow * * The size of the string will be increased by 'delta' characters. If * 'delta' is zero, the size will be doubled. */ #if defined(TRIO_FUNC_STRING_CREATE) \ || defined(TRIO_FUNC_STRING_APPEND) \ || defined(TRIO_FUNC_XSTRING_APPEND) \ || defined(TRIO_FUNC_XSTRING_APPEND_CHAR) TRIO_PRIVATE_STRING BOOLEAN_T internal_string_grow TRIO_ARGS2((self, delta), trio_string_t *self, size_t delta) { BOOLEAN_T status = FALSE; char *new_content; size_t new_size; new_size = (delta == 0) ? ( (self->allocated == 0) ? 1 : self->allocated * 2 ) : self->allocated + delta; new_content = (char *)TRIO_REALLOC(self->content, new_size); if (new_content) { self->content = new_content; self->allocated = new_size; status = TRUE; } return status; } #endif /* * internal_string_grow_to * * The size of the string will be increased to 'length' plus one characters. * If 'length' is less than the original size, the original size will be * used (that is, the size of the string is never decreased). */ #if defined(TRIO_FUNC_STRING_APPEND) \ || defined(TRIO_FUNC_XSTRING_APPEND) TRIO_PRIVATE_STRING BOOLEAN_T internal_string_grow_to TRIO_ARGS2((self, length), trio_string_t *self, size_t length) { length++; /* Room for terminating zero */ return (self->allocated < length) ? internal_string_grow(self, length - self->allocated) : TRUE; } #endif #if defined(TRIO_FUNC_INTERNAL_TO_UPPER) TRIO_PRIVATE_STRING TRIO_INLINE int internal_to_upper TRIO_ARGS1((source), int source) { # if defined(HAVE_TOUPPER) return toupper(source); # else /* Does not handle locales or non-contiguous alphabetic characters */ return ((source >= (int)'a') && (source <= (int)'z')) ? source - 'a' + 'A' : source; # endif } #endif /** Create new string. @param size Size of new string. @return Pointer to string, or NULL if allocation failed. */ #if defined(TRIO_FUNC_CREATE) TRIO_PUBLIC_STRING char * trio_create TRIO_ARGS1((size), size_t size) { return (char *)TRIO_MALLOC(size); } #endif /** Destroy string. @param string String to be freed. */ #if defined(TRIO_FUNC_DESTROY) TRIO_PUBLIC_STRING void trio_destroy TRIO_ARGS1((string), char *string) { if (string) { TRIO_FREE(string); } } #endif /** Count the number of characters in a string. @param string String to measure. @return Number of characters in @p string. */ #if defined(TRIO_FUNC_LENGTH) TRIO_PUBLIC_STRING size_t trio_length TRIO_ARGS1((string), TRIO_CONST char *string) { return strlen(string); } #endif /** Count at most @p max characters in a string. @param string String to measure. @param max Maximum number of characters to count. @return The maximum value of @p max and number of characters in @p string. */ #if defined(TRIO_FUNC_LENGTH) TRIO_PUBLIC_STRING size_t trio_length_max TRIO_ARGS2((string, max), TRIO_CONST char *string, size_t max) { size_t i; for (i = 0; i < max; ++i) { if (string[i] == 0) break; } return i; } #endif /** Append @p source at the end of @p target. @param target Target string. @param source Source string. @return Boolean value indicating success or failure. @pre @p target must point to a memory chunk with sufficient room to contain the @p target string and @p source string. @pre No boundary checking is performed, so insufficient memory will result in a buffer overrun. @post @p target will be zero terminated. */ #if defined(TRIO_FUNC_APPEND) TRIO_PUBLIC_STRING int trio_append TRIO_ARGS2((target, source), char *target, TRIO_CONST char *source) { assert(target); assert(source); return (strcat(target, source) != NULL); } #endif /** Append at most @p max characters from @p source to @p target. @param target Target string. @param max Maximum number of characters to append. @param source Source string. @return Boolean value indicating success or failure. @pre @p target must point to a memory chuck with sufficient room to contain the @p target string and the @p source string (at most @p max characters). @pre No boundary checking is performed, so insufficient memory will result in a buffer overrun. @post @p target will be zero terminated. */ #if defined(TRIO_FUNC_APPEND_MAX) TRIO_PUBLIC_STRING int trio_append_max TRIO_ARGS3((target, max, source), char *target, size_t max, TRIO_CONST char *source) { size_t length; assert(target); assert(source); length = trio_length(target); if (max > length) { strncat(target, source, max - length - 1); } return TRUE; } #endif /** Determine if a string contains a substring. @param string String to be searched. @param substring String to be found. @return Boolean value indicating success or failure. */ #if defined(TRIO_FUNC_CONTAINS) TRIO_PUBLIC_STRING int trio_contains TRIO_ARGS2((string, substring), TRIO_CONST char *string, TRIO_CONST char *substring) { assert(string); assert(substring); return (0 != strstr(string, substring)); } #endif /** Copy @p source to @p target. @param target Target string. @param source Source string. @return Boolean value indicating success or failure. @pre @p target must point to a memory chunk with sufficient room to contain the @p source string. @pre No boundary checking is performed, so insufficient memory will result in a buffer overrun. @post @p target will be zero terminated. */ #if defined(TRIO_FUNC_COPY) TRIO_PUBLIC_STRING int trio_copy TRIO_ARGS2((target, source), char *target, TRIO_CONST char *source) { assert(target); assert(source); (void)strcpy(target, source); return TRUE; } #endif /** Copy at most @p max characters from @p source to @p target. @param target Target string. @param max Maximum number of characters to append. @param source Source string. @return Boolean value indicating success or failure. @pre @p target must point to a memory chunk with sufficient room to contain the @p source string (at most @p max characters). @pre No boundary checking is performed, so insufficient memory will result in a buffer overrun. @post @p target will be zero terminated. */ #if defined(TRIO_FUNC_COPY_MAX) TRIO_PUBLIC_STRING int trio_copy_max TRIO_ARGS3((target, max, source), char *target, size_t max, TRIO_CONST char *source) { assert(target); assert(source); assert(max > 0); /* Includes != 0 */ (void)strncpy(target, source, max - 1); target[max - 1] = (char)0; return TRUE; } #endif /** Duplicate @p source. @param source Source string. @return A copy of the @p source string. @post @p target will be zero terminated. */ #if defined(TRIO_FUNC_DUPLICATE) TRIO_PUBLIC_STRING char * trio_duplicate TRIO_ARGS1((source), TRIO_CONST char *source) { return internal_duplicate_max(source, trio_length(source)); } #endif /** Duplicate at most @p max characters of @p source. @param source Source string. @param max Maximum number of characters to duplicate. @return A copy of the @p source string. @post @p target will be zero terminated. */ #if defined(TRIO_FUNC_DUPLICATE_MAX) TRIO_PUBLIC_STRING char * trio_duplicate_max TRIO_ARGS2((source, max), TRIO_CONST char *source, size_t max) { size_t length; assert(source); assert(max > 0); length = trio_length(source); if (length > max) { length = max; } return internal_duplicate_max(source, length); } #endif /** Compare if two strings are equal. @param first First string. @param second Second string. @return Boolean indicating whether the two strings are equal or not. Case-insensitive comparison. */ #if defined(TRIO_FUNC_EQUAL) TRIO_PUBLIC_STRING int trio_equal TRIO_ARGS2((first, second), TRIO_CONST char *first, TRIO_CONST char *second) { assert(first); assert(second); if ((first != NULL) && (second != NULL)) { # if defined(USE_STRCASECMP) return (0 == strcasecmp(first, second)); # else while ((*first != NIL) && (*second != NIL)) { if (internal_to_upper(*first) != internal_to_upper(*second)) { break; } first++; second++; } return ((*first == NIL) && (*second == NIL)); # endif } return FALSE; } #endif /** Compare if two strings are equal. @param first First string. @param second Second string. @return Boolean indicating whether the two strings are equal or not. Case-sensitive comparison. */ #if defined(TRIO_FUNC_EQUAL_CASE) TRIO_PUBLIC_STRING int trio_equal_case TRIO_ARGS2((first, second), TRIO_CONST char *first, TRIO_CONST char *second) { assert(first); assert(second); if ((first != NULL) && (second != NULL)) { return (0 == strcmp(first, second)); } return FALSE; } #endif /** Compare if two strings up until the first @p max characters are equal. @param first First string. @param max Maximum number of characters to compare. @param second Second string. @return Boolean indicating whether the two strings are equal or not. Case-sensitive comparison. */ #if defined(TRIO_FUNC_EQUAL_CASE_MAX) TRIO_PUBLIC_STRING int trio_equal_case_max TRIO_ARGS3((first, max, second), TRIO_CONST char *first, size_t max, TRIO_CONST char *second) { assert(first); assert(second); if ((first != NULL) && (second != NULL)) { return (0 == strncmp(first, second, max)); } return FALSE; } #endif /** Compare if two strings are equal. @param first First string. @param second Second string. @return Boolean indicating whether the two strings are equal or not. Collating characters are considered equal. */ #if defined(TRIO_FUNC_EQUAL_LOCALE) TRIO_PUBLIC_STRING int trio_equal_locale TRIO_ARGS2((first, second), TRIO_CONST char *first, TRIO_CONST char *second) { assert(first); assert(second); # if defined(LC_COLLATE) return (strcoll(first, second) == 0); # else return trio_equal(first, second); # endif } #endif /** Compare if two strings up until the first @p max characters are equal. @param first First string. @param max Maximum number of characters to compare. @param second Second string. @return Boolean indicating whether the two strings are equal or not. Case-insensitive comparison. */ #if defined(TRIO_FUNC_EQUAL_MAX) TRIO_PUBLIC_STRING int trio_equal_max TRIO_ARGS3((first, max, second), TRIO_CONST char *first, size_t max, TRIO_CONST char *second) { assert(first); assert(second); if ((first != NULL) && (second != NULL)) { # if defined(USE_STRNCASECMP) return (0 == strncasecmp(first, second, max)); # else /* Not adequately tested yet */ size_t cnt = 0; while ((*first != NIL) && (*second != NIL) && (cnt <= max)) { if (internal_to_upper(*first) != internal_to_upper(*second)) { break; } first++; second++; cnt++; } return ((cnt == max) || ((*first == NIL) && (*second == NIL))); # endif } return FALSE; } #endif /** Provide a textual description of an error code (errno). @param error_number Error number. @return Textual description of @p error_number. */ #if defined(TRIO_FUNC_ERROR) TRIO_PUBLIC_STRING TRIO_CONST char * trio_error TRIO_ARGS1((error_number), int error_number) { # if defined(USE_STRERROR) return strerror(error_number); # else # if defined(USE_SYS_ERRLIST) extern char *sys_errlist[]; extern int sys_nerr; return ((error_number < 0) || (error_number >= sys_nerr)) ? "unknown" : sys_errlist[error_number]; # else return "unknown"; # endif # endif } #endif /** Format the date/time according to @p format. @param target Target string. @param max Maximum number of characters to format. @param format Formatting string. @param datetime Date/time structure. @return Number of formatted characters. The formatting string accepts the same specifiers as the standard C function strftime. */ #if defined(TRIO_FUNC_FORMAT_DATE_MAX) TRIO_PUBLIC_STRING size_t trio_format_date_max TRIO_ARGS4((target, max, format, datetime), char *target, size_t max, TRIO_CONST char *format, TRIO_CONST struct tm *datetime) { assert(target); assert(format); assert(datetime); assert(max > 0); return strftime(target, max, format, datetime); } #endif /** Calculate a hash value for a string. @param string String to be calculated on. @param type Hash function. @return Calculated hash value. @p type can be one of the following @li @c TRIO_HASH_PLAIN Plain hash function. */ #if defined(TRIO_FUNC_HASH) TRIO_PUBLIC_STRING unsigned long trio_hash TRIO_ARGS2((string, type), TRIO_CONST char *string, int type) { unsigned long value = 0L; char ch; assert(string); switch (type) { case TRIO_HASH_PLAIN: while ( (ch = *string++) != NIL ) { value *= 31; value += (unsigned long)ch; } break; default: assert(FALSE); break; } return value; } #endif /** Find first occurrence of a character in a string. @param string String to be searched. @param character Character to be found. @return A pointer to the found character, or NULL if character was not found. */ #if defined(TRIO_FUNC_INDEX) TRIO_PUBLIC_STRING char * trio_index TRIO_ARGS2((string, character), TRIO_CONST char *string, int character) { assert(string); return strchr(string, character); } #endif /** Find last occurrence of a character in a string. @param string String to be searched. @param character Character to be found. @return A pointer to the found character, or NULL if character was not found. */ #if defined(TRIO_FUNC_INDEX_LAST) TRIO_PUBLIC_STRING char * trio_index_last TRIO_ARGS2((string, character), TRIO_CONST char *string, int character) { assert(string); return strchr(string, character); } #endif /** Convert the alphabetic letters in the string to lower-case. @param target String to be converted. @return Number of processed characters (converted or not). */ #if defined(TRIO_FUNC_LOWER) TRIO_PUBLIC_STRING int trio_lower TRIO_ARGS1((target), char *target) { assert(target); return trio_span_function(target, target, trio_to_lower); } #endif /** Compare two strings using wildcards. @param string String to be searched. @param pattern Pattern, including wildcards, to search for. @return Boolean value indicating success or failure. Case-insensitive comparison. The following wildcards can be used @li @c * Match any number of characters. @li @c ? Match a single character. */ #if defined(TRIO_FUNC_MATCH) TRIO_PUBLIC_STRING int trio_match TRIO_ARGS2((string, pattern), TRIO_CONST char *string, TRIO_CONST char *pattern) { assert(string); assert(pattern); for (; ('*' != *pattern); ++pattern, ++string) { if (NIL == *string) { return (NIL == *pattern); } if ((internal_to_upper((int)*string) != internal_to_upper((int)*pattern)) && ('?' != *pattern)) { return FALSE; } } /* two-line patch to prevent *too* much recursiveness: */ while ('*' == pattern[1]) pattern++; do { if ( trio_match(string, &pattern[1]) ) { return TRUE; } } while (*string++); return FALSE; } #endif /** Compare two strings using wildcards. @param string String to be searched. @param pattern Pattern, including wildcards, to search for. @return Boolean value indicating success or failure. Case-sensitive comparison. The following wildcards can be used @li @c * Match any number of characters. @li @c ? Match a single character. */ #if defined(TRIO_FUNC_MATCH_CASE) TRIO_PUBLIC_STRING int trio_match_case TRIO_ARGS2((string, pattern), TRIO_CONST char *string, TRIO_CONST char *pattern) { assert(string); assert(pattern); for (; ('*' != *pattern); ++pattern, ++string) { if (NIL == *string) { return (NIL == *pattern); } if ((*string != *pattern) && ('?' != *pattern)) { return FALSE; } } /* two-line patch to prevent *too* much recursiveness: */ while ('*' == pattern[1]) pattern++; do { if ( trio_match_case(string, &pattern[1]) ) { return TRUE; } } while (*string++); return FALSE; } #endif /** Execute a function on each character in string. @param target Target string. @param source Source string. @param Function Function to be executed. @return Number of processed characters. */ #if defined(TRIO_FUNC_SPAN_FUNCTION) TRIO_PUBLIC_STRING size_t trio_span_function TRIO_ARGS3((target, source, Function), char *target, TRIO_CONST char *source, int (*Function) TRIO_PROTO((int))) { size_t count = 0; assert(target); assert(source); assert(Function); while (*source != NIL) { *target++ = Function(*source++); count++; } return count; } #endif /** Search for a substring in a string. @param string String to be searched. @param substring String to be found. @return Pointer to first occurrence of @p substring in @p string, or NULL if no match was found. */ #if defined(TRIO_FUNC_SUBSTRING) TRIO_PUBLIC_STRING char * trio_substring TRIO_ARGS2((string, substring), TRIO_CONST char *string, TRIO_CONST char *substring) { assert(string); assert(substring); return strstr(string, substring); } #endif /** Search for a substring in the first @p max characters of a string. @param string String to be searched. @param max Maximum characters to be searched. @param substring String to be found. @return Pointer to first occurrence of @p substring in @p string, or NULL if no match was found. */ #if defined(TRIO_FUNC_SUBSTRING_MAX) TRIO_PUBLIC_STRING char * trio_substring_max TRIO_ARGS3((string, max, substring), TRIO_CONST char *string, size_t max, TRIO_CONST char *substring) { size_t count; size_t size; char *result = NULL; assert(string); assert(substring); size = trio_length(substring); if (size <= max) { for (count = 0; count <= max - size; count++) { if (trio_equal_max(substring, size, &string[count])) { result = (char *)&string[count]; break; } } } return result; } #endif /** Tokenize string. @param string String to be tokenized. @param delimiters String containing list of delimiting characters. @return Start of new token. @warning @p string will be destroyed. */ #if defined(TRIO_FUNC_TOKENIZE) TRIO_PUBLIC_STRING char * trio_tokenize TRIO_ARGS2((string, delimiters), char *string, TRIO_CONST char *delimiters) { assert(delimiters); return strtok(string, delimiters); } #endif /** Convert string to floating-point number. @param source String to be converted. @param endp Pointer to end of the converted string. @return A floating-point number. The following Extended Backus-Naur form is used @verbatim double ::= [ ] ( | | ) [ [ ] ] number ::= 1*( ) digit ::= ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ) exponential ::= ( 'e' | 'E' ) sign ::= ( '-' | '+' ) decimal_point ::= '.' @endverbatim */ #if defined(TRIO_FUNC_TO_LONG_DOUBLE) /* FIXME: Add EBNF for hex-floats */ TRIO_PUBLIC_STRING trio_long_double_t trio_to_long_double TRIO_ARGS2((source, endp), TRIO_CONST char *source, char **endp) { # if defined(USE_STRTOLD) return strtold(source, endp); # else int isNegative = FALSE; int isExponentNegative = FALSE; trio_long_double_t integer = 0.0; trio_long_double_t fraction = 0.0; unsigned long exponent = 0; trio_long_double_t base; trio_long_double_t fracdiv = 1.0; trio_long_double_t value = 0.0; /* First try hex-floats */ if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X'))) { base = 16.0; source += 2; while (isxdigit((int)*source)) { integer *= base; integer += (isdigit((int)*source) ? (*source - '0') : 10 + (internal_to_upper((int)*source) - 'A')); source++; } if (*source == '.') { source++; while (isxdigit((int)*source)) { fracdiv /= base; fraction += fracdiv * (isdigit((int)*source) ? (*source - '0') : 10 + (internal_to_upper((int)*source) - 'A')); source++; } if ((*source == 'p') || (*source == 'P')) { source++; if ((*source == '+') || (*source == '-')) { isExponentNegative = (*source == '-'); source++; } while (isdigit((int)*source)) { exponent *= 10; exponent += (*source - '0'); source++; } } } /* For later use with exponent */ base = 2.0; } else /* Then try normal decimal floats */ { base = 10.0; isNegative = (*source == '-'); /* Skip sign */ if ((*source == '+') || (*source == '-')) source++; /* Integer part */ while (isdigit((int)*source)) { integer *= base; integer += (*source - '0'); source++; } if (*source == '.') { source++; /* skip decimal point */ while (isdigit((int)*source)) { fracdiv /= base; fraction += (*source - '0') * fracdiv; source++; } } if ((*source == 'e') || (*source == 'E') # if TRIO_MICROSOFT || (*source == 'd') || (*source == 'D') # endif ) { source++; /* Skip exponential indicator */ isExponentNegative = (*source == '-'); if ((*source == '+') || (*source == '-')) source++; while (isdigit((int)*source)) { exponent *= (int)base; exponent += (*source - '0'); source++; } } } value = integer + fraction; if (exponent != 0) { if (isExponentNegative) value /= trio_powl(base, (trio_long_double_t)exponent); else value *= trio_powl(base, (trio_long_double_t)exponent); } if (isNegative) value = -value; if (endp) *endp = (char *)source; return value; # endif } #endif /** Convert string to floating-point number. @param source String to be converted. @param endp Pointer to end of the converted string. @return A floating-point number. See @ref trio_to_long_double. */ #if defined(TRIO_FUNC_TO_DOUBLE) TRIO_PUBLIC_STRING double trio_to_double TRIO_ARGS2((source, endp), TRIO_CONST char *source, char **endp) { #if defined(USE_STRTOD) return strtod(source, endp); #else return (double)trio_to_long_double(source, endp); #endif } #endif /** Convert string to floating-point number. @param source String to be converted. @param endp Pointer to end of the converted string. @return A floating-point number. See @ref trio_to_long_double. */ #if defined(TRIO_FUNC_TO_FLOAT) TRIO_PUBLIC_STRING float trio_to_float TRIO_ARGS2((source, endp), TRIO_CONST char *source, char **endp) { # if defined(USE_STRTOF) return strtof(source, endp); # else return (float)trio_to_long_double(source, endp); # endif } #endif /** Convert string to signed integer. @param string String to be converted. @param endp Pointer to end of converted string. @param base Radix number of number. */ #if defined(TRIO_FUNC_TO_LONG) TRIO_PUBLIC_STRING long trio_to_long TRIO_ARGS3((string, endp, base), TRIO_CONST char *string, char **endp, int base) { assert(string); assert((base >= 2) && (base <= 36)); return strtol(string, endp, base); } #endif /** Convert one alphabetic letter to lower-case. @param source The letter to be converted. @return The converted letter. */ #if defined(TRIO_FUNC_TO_LOWER) TRIO_PUBLIC_STRING int trio_to_lower TRIO_ARGS1((source), int source) { # if defined(HAVE_TOLOWER) return tolower(source); # else /* Does not handle locales or non-contiguous alphabetic characters */ return ((source >= (int)'A') && (source <= (int)'Z')) ? source - 'A' + 'a' : source; # endif } #endif /** Convert string to unsigned integer. @param string String to be converted. @param endp Pointer to end of converted string. @param base Radix number of number. */ #if defined(TRIO_FUNC_TO_UNSIGNED_LONG) TRIO_PUBLIC_STRING unsigned long trio_to_unsigned_long TRIO_ARGS3((string, endp, base), TRIO_CONST char *string, char **endp, int base) { assert(string); assert((base >= 2) && (base <= 36)); return strtoul(string, endp, base); } #endif /** Convert one alphabetic letter to upper-case. @param source The letter to be converted. @return The converted letter. */ #if defined(TRIO_FUNC_TO_UPPER) TRIO_PUBLIC_STRING int trio_to_upper TRIO_ARGS1((source), int source) { return internal_to_upper(source); } #endif /** Convert the alphabetic letters in the string to upper-case. @param target The string to be converted. @return The number of processed characters (converted or not). */ #if defined(TRIO_FUNC_UPPER) TRIO_PUBLIC_STRING int trio_upper TRIO_ARGS1((target), char *target) { assert(target); return trio_span_function(target, target, internal_to_upper); } #endif /** @} End of StaticStrings */ /************************************************************************* * Dynamic String Functions */ #if defined(TRIO_DOCUMENTATION) # include "doc/doc_dynamic.h" #endif /** @addtogroup DynamicStrings @{ */ /** Create a new dynamic string. @param initial_size Initial size of the buffer. @return Newly allocated dynamic string, or NULL if memory allocation failed. */ #if defined(TRIO_FUNC_STRING_CREATE) TRIO_PUBLIC_STRING trio_string_t * trio_string_create TRIO_ARGS1((initial_size), int initial_size) { trio_string_t *self; self = internal_string_alloc(); if (self) { if (internal_string_grow(self, (size_t)((initial_size > 0) ? initial_size : 1))) { self->content[0] = (char)0; self->allocated = initial_size; } else { trio_string_destroy(self); self = NULL; } } return self; } #endif /** Deallocate the dynamic string and its contents. @param self Dynamic string */ #if defined(TRIO_FUNC_STRING_DESTROY) TRIO_PUBLIC_STRING void trio_string_destroy TRIO_ARGS1((self), trio_string_t *self) { assert(self); if (self) { trio_destroy(self->content); TRIO_FREE(self); } } #endif /** Get a pointer to the content. @param self Dynamic string. @param offset Offset into content. @return Pointer to the content. @p Offset can be zero, positive, or negative. If @p offset is zero, then the start of the content will be returned. If @p offset is positive, then a pointer to @p offset number of characters from the beginning of the content is returned. If @p offset is negative, then a pointer to @p offset number of characters from the ending of the string, starting at the terminating zero, is returned. */ #if defined(TRIO_FUNCT_STRING_GET) TRIO_PUBLIC_STRING char * trio_string_get TRIO_ARGS2((self, offset), trio_string_t *self, int offset) { char *result = NULL; assert(self); if (self->content != NULL) { if (self->length == 0) { (void)trio_string_length(self); } if (offset >= 0) { if (offset > (int)self->length) { offset = self->length; } } else { offset += self->length + 1; if (offset < 0) { offset = 0; } } result = &(self->content[offset]); } return result; } #endif /** Extract the content. @param self Dynamic String @return Content of dynamic string. The content is removed from the dynamic string. This enables destruction of the dynamic string without deallocation of the content. */ #if defined(TRIO_FUNC_STRING_EXTRACT) TRIO_PUBLIC_STRING char * trio_string_extract TRIO_ARGS1((self), trio_string_t *self) { char *result; assert(self); result = self->content; /* FIXME: Allocate new empty buffer? */ self->content = NULL; self->length = self->allocated = 0; return result; } #endif /** Set the content of the dynamic string. @param self Dynamic String @param buffer The new content. Sets the content of the dynamic string to a copy @p buffer. An existing content will be deallocated first, if necessary. @remark This function will make a copy of @p buffer. You are responsible for deallocating @p buffer yourself. */ #if defined(TRIO_FUNC_XSTRING_SET) TRIO_PUBLIC_STRING void trio_xstring_set TRIO_ARGS2((self, buffer), trio_string_t *self, char *buffer) { assert(self); trio_destroy(self->content); self->content = trio_duplicate(buffer); } #endif /* * trio_string_size */ #if defined(TRIO_FUNC_STRING_SIZE) TRIO_PUBLIC_STRING int trio_string_size TRIO_ARGS1((self), trio_string_t *self) { assert(self); return self->allocated; } #endif /* * trio_string_terminate */ #if defined(TRIO_FUNC_STRING_TERMINATE) TRIO_PUBLIC_STRING void trio_string_terminate TRIO_ARGS1((self), trio_string_t *self) { trio_xstring_append_char(self, 0); } #endif /** Append the second string to the first. @param self Dynamic string to be modified. @param other Dynamic string to copy from. @return Boolean value indicating success or failure. */ #if defined(TRIO_FUNC_STRING_APPEND) TRIO_PUBLIC_STRING int trio_string_append TRIO_ARGS2((self, other), trio_string_t *self, trio_string_t *other) { size_t length; assert(self); assert(other); length = self->length + other->length; if (!internal_string_grow_to(self, length)) goto error; trio_copy(&self->content[self->length], other->content); self->length = length; return TRUE; error: return FALSE; } #endif /* * trio_xstring_append */ #if defined(TRIO_FUNC_XSTRING_APPEND) TRIO_PUBLIC_STRING int trio_xstring_append TRIO_ARGS2((self, other), trio_string_t *self, TRIO_CONST char *other) { size_t length; assert(self); assert(other); length = self->length + trio_length(other); if (!internal_string_grow_to(self, length)) goto error; trio_copy(&self->content[self->length], other); self->length = length; return TRUE; error: return FALSE; } #endif /* * trio_xstring_append_char */ #if defined(TRIO_FUNC_XSTRING_APPEND_CHAR) TRIO_PUBLIC_STRING int trio_xstring_append_char TRIO_ARGS2((self, character), trio_string_t *self, char character) { assert(self); if ((int)self->length >= trio_string_size(self)) { if (!internal_string_grow(self, 0)) goto error; } self->content[self->length] = character; self->length++; return TRUE; error: return FALSE; } #endif /** Search for the first occurrence of second parameter in the first. @param self Dynamic string to be modified. @param other Dynamic string to copy from. @return Boolean value indicating success or failure. */ #if defined(TRIO_FUNC_STRING_CONTAINS) TRIO_PUBLIC_STRING int trio_string_contains TRIO_ARGS2((self, other), trio_string_t *self, trio_string_t *other) { assert(self); assert(other); return trio_contains(self->content, other->content); } #endif /* * trio_xstring_contains */ #if defined(TRIO_FUNC_XSTRING_CONTAINS) TRIO_PUBLIC_STRING int trio_xstring_contains TRIO_ARGS2((self, other), trio_string_t *self, TRIO_CONST char *other) { assert(self); assert(other); return trio_contains(self->content, other); } #endif /* * trio_string_copy */ #if defined(TRIO_FUNC_STRING_COPY) TRIO_PUBLIC_STRING int trio_string_copy TRIO_ARGS2((self, other), trio_string_t *self, trio_string_t *other) { assert(self); assert(other); self->length = 0; return trio_string_append(self, other); } #endif /* * trio_xstring_copy */ #if defined(TRIO_FUNC_XSTRING_COPY) TRIO_PUBLIC_STRING int trio_xstring_copy TRIO_ARGS2((self, other), trio_string_t *self, TRIO_CONST char *other) { assert(self); assert(other); self->length = 0; return trio_xstring_append(self, other); } #endif /* * trio_string_duplicate */ #if defined(TRIO_FUNC_STRING_DUPLICATE) TRIO_PUBLIC_STRING trio_string_t * trio_string_duplicate TRIO_ARGS1((other), trio_string_t *other) { trio_string_t *self; assert(other); self = internal_string_alloc(); if (self) { self->content = internal_duplicate_max(other->content, other->length); if (self->content) { self->length = other->length; self->allocated = self->length + 1; } else { self->length = self->allocated = 0; } } return self; } #endif /* * trio_xstring_duplicate */ #if defined(TRIO_FUNC_XSTRING_DUPLICATE) TRIO_PUBLIC_STRING trio_string_t * trio_xstring_duplicate TRIO_ARGS1((other), TRIO_CONST char *other) { trio_string_t *self; assert(other); self = internal_string_alloc(); if (self) { self->content = internal_duplicate_max(other, trio_length(other)); if (self->content) { self->length = trio_length(self->content); self->allocated = self->length + 1; } else { self->length = self->allocated = 0; } } return self; } #endif /* * trio_string_equal */ #if defined(TRIO_FUNC_STRING_EQUAL) TRIO_PUBLIC_STRING int trio_string_equal TRIO_ARGS2((self, other), trio_string_t *self, trio_string_t *other) { assert(self); assert(other); return trio_equal(self->content, other->content); } #endif /* * trio_xstring_equal */ #if defined(TRIO_FUNC_XSTRING_EQUAL) TRIO_PUBLIC_STRING int trio_xstring_equal TRIO_ARGS2((self, other), trio_string_t *self, TRIO_CONST char *other) { assert(self); assert(other); return trio_equal(self->content, other); } #endif /* * trio_string_equal_max */ #if defined(TRIO_FUNC_STRING_EQUAL_MAX) TRIO_PUBLIC_STRING int trio_string_equal_max TRIO_ARGS3((self, max, other), trio_string_t *self, size_t max, trio_string_t *other) { assert(self); assert(other); return trio_equal_max(self->content, max, other->content); } #endif /* * trio_xstring_equal_max */ #if defined(TRIO_FUNC_XSTRING_EQUAL_MAX) TRIO_PUBLIC_STRING int trio_xstring_equal_max TRIO_ARGS3((self, max, other), trio_string_t *self, size_t max, TRIO_CONST char *other) { assert(self); assert(other); return trio_equal_max(self->content, max, other); } #endif /* * trio_string_equal_case */ #if defined(TRIO_FUNC_STRING_EQUAL_CASE) TRIO_PUBLIC_STRING int trio_string_equal_case TRIO_ARGS2((self, other), trio_string_t *self, trio_string_t *other) { assert(self); assert(other); return trio_equal_case(self->content, other->content); } #endif /* * trio_xstring_equal_case */ #if defined(TRIO_FUNC_XSTRING_EQUAL_CASE) TRIO_PUBLIC_STRING int trio_xstring_equal_case TRIO_ARGS2((self, other), trio_string_t *self, TRIO_CONST char *other) { assert(self); assert(other); return trio_equal_case(self->content, other); } #endif /* * trio_string_equal_case_max */ #if defined(TRIO_FUNC_STRING_EQUAL_CASE_MAX) TRIO_PUBLIC_STRING int trio_string_equal_case_max TRIO_ARGS3((self, max, other), trio_string_t *self, size_t max, trio_string_t *other) { assert(self); assert(other); return trio_equal_case_max(self->content, max, other->content); } #endif /* * trio_xstring_equal_case_max */ #if defined(TRIO_FUNC_XSTRING_EQUAL_CASE_MAX) TRIO_PUBLIC_STRING int trio_xstring_equal_case_max TRIO_ARGS3((self, max, other), trio_string_t *self, size_t max, TRIO_CONST char *other) { assert(self); assert(other); return trio_equal_case_max(self->content, max, other); } #endif /* * trio_string_format_data_max */ #if defined(TRIO_FUNC_STRING_FORMAT_DATE_MAX) TRIO_PUBLIC_STRING size_t trio_string_format_date_max TRIO_ARGS4((self, max, format, datetime), trio_string_t *self, size_t max, TRIO_CONST char *format, TRIO_CONST struct tm *datetime) { assert(self); return trio_format_date_max(self->content, max, format, datetime); } #endif /* * trio_string_index */ #if defined(TRIO_FUNC_STRING_INDEX) TRIO_PUBLIC_STRING char * trio_string_index TRIO_ARGS2((self, character), trio_string_t *self, int character) { assert(self); return trio_index(self->content, character); } #endif /* * trio_string_index_last */ #if defined(TRIO_FUNC_STRING_INDEX_LAST) TRIO_PUBLIC_STRING char * trio_string_index_last TRIO_ARGS2((self, character), trio_string_t *self, int character) { assert(self); return trio_index_last(self->content, character); } #endif /* * trio_string_length */ #if defined(TRIO_FUNC_STRING_LENGTH) TRIO_PUBLIC_STRING int trio_string_length TRIO_ARGS1((self), trio_string_t *self) { assert(self); if (self->length == 0) { self->length = trio_length(self->content); } return self->length; } #endif /* * trio_string_lower */ #if defined(TRIO_FUNC_STRING_LOWER) TRIO_PUBLIC_STRING int trio_string_lower TRIO_ARGS1((self), trio_string_t *self) { assert(self); return trio_lower(self->content); } #endif /* * trio_string_match */ #if defined(TRIO_FUNC_STRING_MATCH) TRIO_PUBLIC_STRING int trio_string_match TRIO_ARGS2((self, other), trio_string_t *self, trio_string_t *other) { assert(self); assert(other); return trio_match(self->content, other->content); } #endif /* * trio_xstring_match */ #if defined(TRIO_FUNC_XSTRING_MATCH) TRIO_PUBLIC_STRING int trio_xstring_match TRIO_ARGS2((self, other), trio_string_t *self, TRIO_CONST char *other) { assert(self); assert(other); return trio_match(self->content, other); } #endif /* * trio_string_match_case */ #if defined(TRIO_FUNC_STRING_MATCH_CASE) TRIO_PUBLIC_STRING int trio_string_match_case TRIO_ARGS2((self, other), trio_string_t *self, trio_string_t *other) { assert(self); assert(other); return trio_match_case(self->content, other->content); } #endif /* * trio_xstring_match_case */ #if defined(TRIO_FUNC_XSTRING_MATCH_CASE) TRIO_PUBLIC_STRING int trio_xstring_match_case TRIO_ARGS2((self, other), trio_string_t *self, TRIO_CONST char *other) { assert(self); assert(other); return trio_match_case(self->content, other); } #endif /* * trio_string_substring */ #if defined(TRIO_FUNC_STRING_SUBSTRING) TRIO_PUBLIC_STRING char * trio_string_substring TRIO_ARGS2((self, other), trio_string_t *self, trio_string_t *other) { assert(self); assert(other); return trio_substring(self->content, other->content); } #endif /* * trio_xstring_substring */ #if defined(TRIO_FUNC_XSTRING_SUBSTRING) TRIO_PUBLIC_STRING char * trio_xstring_substring TRIO_ARGS2((self, other), trio_string_t *self, TRIO_CONST char *other) { assert(self); assert(other); return trio_substring(self->content, other); } #endif /* * trio_string_upper */ #if defined(TRIO_FUNC_STRING_UPPER) TRIO_PUBLIC_STRING int trio_string_upper TRIO_ARGS1((self), trio_string_t *self) { assert(self); return trio_upper(self->content); } #endif /** @} End of DynamicStrings */ ================================================ FILE: src/sdk/src/libc/src/trio/triostr.h ================================================ #ifndef TRIO_TRIOSTR_H #define TRIO_TRIOSTR_H /* * Documentation is located in triostr.c */ #include #include #include #include #include "triodef.h" #include "triop.h" #ifdef __cplusplus extern "C" { #endif enum { TRIO_HASH_NONE = 0, TRIO_HASH_PLAIN, TRIO_HASH_TWOSIGNED }; #if !defined(TRIO_PUBLIC_STRING) # if !defined(TRIO_PUBLIC) # define TRIO_PUBLIC # endif # define TRIO_PUBLIC_STRING TRIO_PUBLIC #endif /************************************************************************* * Dependencies */ #if defined(TRIO_EMBED_STRING) /* * The application that triostr is embedded in must define which functions * it uses. * * The following resolves internal dependencies. */ # if defined(TRIO_FUNC_XSTRING_SET) # if !defined(TRIO_FUNC_DUPLICATE) # define TRIO_FUNC_DUPLICATE # endif # endif # if defined(TRIO_FUNC_DUPLICATE) \ || defined(TRIO_FUNC_DUPLICATE_MAX) \ || defined(TRIO_FUNC_STRING_DUPLICATE) \ || defined(TRIO_FUNC_XSTRING_DUPLICATE) # if !defined(TRIO_FUNC_CREATE) # define TRIO_FUNC_CREATE # endif # if !defined(TRIO_FUNC_COPY_MAX) # define TRIO_FUNC_COPY_MAX # endif # endif # if defined(TRIO_FUNC_STRING_CREATE) # if !defined(TRIO_FUNC_STRING_DESTROY) # define TRIO_FUNC_STRING_DESTROY # endif # endif # if defined(TRIO_FUNC_STRING_DESTROY) \ || defined(TRIO_FUNC_XSTRING_SET) # if !defined(TRIO_FUNC_DESTROY) # define TRIO_FUNC_DESTROY # endif # endif # if defined(TRIO_FUNC_EQUAL_LOCALE) \ || defined(TRIO_FUNC_STRING_EQUAL) \ || defined(TRIO_FUNC_XSTRING_EQUAL) # if !defined(TRIO_FUNC_EQUAL) # define TRIO_FUNC_EQUAL # endif # endif # if defined(TRIO_FUNC_EQUAL_CASE) \ || defined(TRIO_FUNC_STRING_EQUAL_CASE) \ || defined(TRIO_FUNC_XSTRING_EQUAL_CASE) # if !defined(TRIO_FUNC_EQUAL_CASE) # define TRIO_FUNC_EQUAL_CASE # endif # endif # if defined(TRIO_FUNC_SUBSTRING_MAX) \ || defined(TRIO_FUNC_STRING_EQUAL_MAX) \ || defined(TRIO_FUNC_XSTRING_EQUAL_MAX) # if !defined(TRIO_FUNC_EQUAL_MAX) # define TRIO_FUNC_EQUAL_MAX # endif # endif # if defined(TRIO_FUNC_TO_DOUBLE) \ || defined(TRIO_FUNC_TO_FLOAT) # if !defined(TRIO_FUNC_TO_LONG_DOUBLE) # define TRIO_FUNC_TO_LONG_DOUBLE # endif # endif # if defined(TRIO_FUNC_STRING_TERMINATE) # if !defined(TRIO_FUNC_XSTRING_APPEND_CHAR) # define TRIO_FUNC_XSTRING_APPEND_CHAR # endif # endif # if defined(TRIO_FUNC_XSTRING_APPEND_CHAR) # if !defined(TRIO_FUNC_STRING_SIZE) # define TRIO_FUNC_STRING_SIZE # endif # endif #else /* * When triostr is not embedded all functions are defined. */ # define TRIO_FUNC_APPEND # define TRIO_FUNC_APPEND_MAX # define TRIO_FUNC_CONTAINS # define TRIO_FUNC_COPY # define TRIO_FUNC_COPY_MAX # define TRIO_FUNC_CREATE # define TRIO_FUNC_DESTROY # define TRIO_FUNC_DUPLICATE # define TRIO_FUNC_DUPLICATE_MAX # define TRIO_FUNC_EQUAL # define TRIO_FUNC_EQUAL_CASE # define TRIO_FUNC_EQUAL_CASE_MAX # define TRIO_FUNC_EQUAL_LOCALE # define TRIO_FUNC_EQUAL_MAX # define TRIO_FUNC_ERROR # if !defined(TRIO_PLATFORM_WINCE) # define TRIO_FUNC_FORMAT_DATE_MAX # endif # define TRIO_FUNC_HASH # define TRIO_FUNC_INDEX # define TRIO_FUNC_INDEX_LAST # define TRIO_FUNC_LENGTH # define TRIO_FUNC_LENGTH_MAX # define TRIO_FUNC_LOWER # define TRIO_FUNC_MATCH # define TRIO_FUNC_MATCH_CASE # define TRIO_FUNC_SPAN_FUNCTION # define TRIO_FUNC_SUBSTRING # define TRIO_FUNC_SUBSTRING_MAX # define TRIO_FUNC_TO_DOUBLE # define TRIO_FUNC_TO_FLOAT # define TRIO_FUNC_TO_LONG # define TRIO_FUNC_TO_LONG_DOUBLE # define TRIO_FUNC_TO_LOWER # define TRIO_FUNC_TO_UNSIGNED_LONG # define TRIO_FUNC_TO_UPPER # define TRIO_FUNC_TOKENIZE # define TRIO_FUNC_UPPER # define TRIO_FUNC_STRING_APPEND # define TRIO_FUNC_STRING_CONTAINS # define TRIO_FUNC_STRING_COPY # define TRIO_FUNC_STRING_CREATE # define TRIO_FUNC_STRING_DESTROY # define TRIO_FUNC_STRING_DUPLICATE # define TRIO_FUNC_STRING_EQUAL # define TRIO_FUNC_STRING_EQUAL_CASE # define TRIO_FUNC_STRING_EQUAL_CASE_MAX # define TRIO_FUNC_STRING_EQUAL_MAX # define TRIO_FUNC_STRING_EXTRACT # if !defined(TRIO_PLATFORM_WINCE) # define TRIO_FUNC_STRING_FORMAT_DATE_MAX # endif # define TRIO_FUNC_STRING_GET # define TRIO_FUNC_STRING_INDEX # define TRIO_FUNC_STRING_INDEX_LAST # define TRIO_FUNC_STRING_LENGTH # define TRIO_FUNC_STRING_LOWER # define TRIO_FUNC_STRING_MATCH # define TRIO_FUNC_STRING_MATCH_CASE # define TRIO_FUNC_STRING_SIZE # define TRIO_FUNC_STRING_SUBSTRING # define TRIO_FUNC_STRING_TERMINATE # define TRIO_FUNC_STRING_UPPER # define TRIO_FUNC_XSTRING_APPEND # define TRIO_FUNC_XSTRING_APPEND_CHAR # define TRIO_FUNC_XSTRING_CONTAINS # define TRIO_FUNC_XSTRING_COPY # define TRIO_FUNC_XSTRING_DUPLICATE # define TRIO_FUNC_XSTRING_EQUAL # define TRIO_FUNC_XSTRING_EQUAL_CASE # define TRIO_FUNC_XSTRING_EQUAL_CASE_MAX # define TRIO_FUNC_XSTRING_EQUAL_MAX # define TRIO_FUNC_XSTRING_MATCH # define TRIO_FUNC_XSTRING_MATCH_CASE # define TRIO_FUNC_XSTRING_SET # define TRIO_FUNC_XSTRING_SUBSTRING #endif /************************************************************************* * String functions */ #if defined(TRIO_FUNC_APPEND) TRIO_PUBLIC_STRING int trio_append TRIO_PROTO((char *target, TRIO_CONST char *source)); #endif #if defined(TRIO_FUNC_APPEND_MAX) TRIO_PUBLIC_STRING int trio_append_max TRIO_PROTO((char *target, size_t max, TRIO_CONST char *source)); #endif #if defined(TRIO_FUNC_CONTAINS) TRIO_PUBLIC_STRING int trio_contains TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *substring)); #endif #if defined(TRIO_FUNC_COPY) TRIO_PUBLIC_STRING int trio_copy TRIO_PROTO((char *target, TRIO_CONST char *source)); #endif #if defined(TRIO_FUNC_COPY_MAX) TRIO_PUBLIC_STRING int trio_copy_max TRIO_PROTO((char *target, size_t max, TRIO_CONST char *source)); #endif #if defined(TRIO_FUNC_CREATE) TRIO_PUBLIC_STRING char * trio_create TRIO_PROTO((size_t size)); #endif #if defined(TRIO_FUNC_DESTROY) TRIO_PUBLIC_STRING void trio_destroy TRIO_PROTO((char *string)); #endif #if defined(TRIO_FUNC_DUPLICATE) TRIO_PUBLIC_STRING char * trio_duplicate TRIO_PROTO((TRIO_CONST char *source)); #endif #if defined(TRIO_FUNC_DUPLICATE_MAX) TRIO_PUBLIC_STRING char * trio_duplicate_max TRIO_PROTO((TRIO_CONST char *source, size_t max)); #endif #if defined(TRIO_FUNC_EQUAL) TRIO_PUBLIC_STRING int trio_equal TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second)); #endif #if defined(TRIO_FUNC_EQUAL_CASE) TRIO_PUBLIC_STRING int trio_equal_case TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second)); #endif #if defined(TRIO_FUNC_EQUAL_CASE_MAX) TRIO_PUBLIC_STRING int trio_equal_case_max TRIO_PROTO((TRIO_CONST char *first, size_t max, TRIO_CONST char *second)); #endif #if defined(TRIO_FUNC_EQUAL_LOCALE) TRIO_PUBLIC_STRING int trio_equal_locale TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second)); #endif #if defined(TRIO_FUNC_EQUAL_MAX) TRIO_PUBLIC_STRING int trio_equal_max TRIO_PROTO((TRIO_CONST char *first, size_t max, TRIO_CONST char *second)); #endif #if defined(TRIO_FUNC_ERROR) TRIO_PUBLIC_STRING TRIO_CONST char * trio_error TRIO_PROTO((int)); #endif #if defined(TRIO_FUNC_FORMAT_DATE_MAX) TRIO_PUBLIC_STRING size_t trio_format_date_max TRIO_PROTO((char *target, size_t max, TRIO_CONST char *format, TRIO_CONST struct tm *datetime)); #endif #if defined(TRIO_FUNC_HASH) TRIO_PUBLIC_STRING unsigned long trio_hash TRIO_PROTO((TRIO_CONST char *string, int type)); #endif #if defined(TRIO_FUNC_INDEX) TRIO_PUBLIC_STRING char * trio_index TRIO_PROTO((TRIO_CONST char *string, int character)); #endif #if defined(TRIO_FUNC_INDEX_LAST) TRIO_PUBLIC_STRING char * trio_index_last TRIO_PROTO((TRIO_CONST char *string, int character)); #endif #if defined(TRIO_FUNC_LENGTH) TRIO_PUBLIC_STRING size_t trio_length TRIO_PROTO((TRIO_CONST char *string)); #endif #if defined(TRIO_FUNC_LENGTH_MAX) TRIO_PUBLIC_STRING size_t trio_length_max TRIO_PROTO((TRIO_CONST char *string, size_t max)); #endif #if defined(TRIO_FUNC_LOWER) TRIO_PUBLIC_STRING int trio_lower TRIO_PROTO((char *target)); #endif #if defined(TRIO_FUNC_MATCH) TRIO_PUBLIC_STRING int trio_match TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *pattern)); #endif #if defined(TRIO_FUNC_MATCH_CASE) TRIO_PUBLIC_STRING int trio_match_case TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *pattern)); #endif #if defined(TRIO_FUNC_SPAN_FUNCTION) TRIO_PUBLIC_STRING size_t trio_span_function TRIO_PROTO((char *target, TRIO_CONST char *source, int (*Function) TRIO_PROTO((int)))); #endif #if defined(TRIO_FUNC_SUBSTRING) TRIO_PUBLIC_STRING char * trio_substring TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *substring)); #endif #if defined(TRIO_FUNC_SUBSTRING_MAX) TRIO_PUBLIC_STRING char * trio_substring_max TRIO_PROTO((TRIO_CONST char *string, size_t max, TRIO_CONST char *substring)); #endif #if defined(TRIO_FUNC_TO_DOUBLE) TRIO_PUBLIC_STRING double trio_to_double TRIO_PROTO((TRIO_CONST char *source, char **endp)); #endif #if defined(TRIO_FUNC_TO_FLOAT) TRIO_PUBLIC_STRING float trio_to_float TRIO_PROTO((TRIO_CONST char *source, char **endp)); #endif #if defined(TRIO_FUNC_TO_LONG) TRIO_PUBLIC_STRING long trio_to_long TRIO_PROTO((TRIO_CONST char *source, char **endp, int base)); #endif #if defined(TRIO_FUNC_TO_LOWER) TRIO_PUBLIC_STRING int trio_to_lower TRIO_PROTO((int source)); #endif #if defined(TRIO_FUNC_TO_LONG_DOUBLE) TRIO_PUBLIC_STRING trio_long_double_t trio_to_long_double TRIO_PROTO((TRIO_CONST char *source, char **endp)); #endif #if defined(TRIO_FUNC_TO_UNSIGNED_LONG) TRIO_PUBLIC_STRING unsigned long trio_to_unsigned_long TRIO_PROTO((TRIO_CONST char *source, char **endp, int base)); #endif #if defined(TRIO_FUNC_TO_UPPER) TRIO_PUBLIC_STRING int trio_to_upper TRIO_PROTO((int source)); #endif #if defined(TRIO_FUNC_TOKENIZE) TRIO_PUBLIC_STRING char * trio_tokenize TRIO_PROTO((char *string, TRIO_CONST char *delimiters)); #endif #if defined(TRIO_FUNC_UPPER) TRIO_PUBLIC_STRING int trio_upper TRIO_PROTO((char *target)); #endif /************************************************************************* * Dynamic string functions */ /* * Opaque type for dynamic strings */ typedef struct _trio_string_t trio_string_t; #if defined(TRIO_FUNC_STRING_APPEND) TRIO_PUBLIC_STRING int trio_string_append TRIO_PROTO((trio_string_t *self, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_CONTAINS) TRIO_PUBLIC_STRING int trio_string_contains TRIO_PROTO((trio_string_t *self, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_COPY) TRIO_PUBLIC_STRING int trio_string_copy TRIO_PROTO((trio_string_t *self, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_CREATE) TRIO_PUBLIC_STRING trio_string_t * trio_string_create TRIO_PROTO((int initial_size)); #endif #if defined(TRIO_FUNC_STRING_DESTROY) TRIO_PUBLIC_STRING void trio_string_destroy TRIO_PROTO((trio_string_t *self)); #endif #if defined(TRIO_FUNC_STRING_DUPLICATE) TRIO_PUBLIC_STRING trio_string_t * trio_string_duplicate TRIO_PROTO((trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_EQUAL) TRIO_PUBLIC_STRING int trio_string_equal TRIO_PROTO((trio_string_t *self, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_EQUAL_MAX) TRIO_PUBLIC_STRING int trio_string_equal_max TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *second)); #endif #if defined(TRIO_FUNC_STRING_EQUAL_CASE) TRIO_PUBLIC_STRING int trio_string_equal_case TRIO_PROTO((trio_string_t *self, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_EQUAL_CASE_MAX) TRIO_PUBLIC_STRING int trio_string_equal_case_max TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_EXTRACT) TRIO_PUBLIC_STRING char * trio_string_extract TRIO_PROTO((trio_string_t *self)); #endif #if defined(TRIO_FUNC_STRING_FORMAT_DATE_MAX) TRIO_PUBLIC_STRING size_t trio_string_format_date_max TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *format, TRIO_CONST struct tm *datetime)); #endif #if defined(TRIO_FUNC_STRING_GET) TRIO_PUBLIC_STRING char * trio_string_get TRIO_PROTO((trio_string_t *self, int offset)); #endif #if defined(TRIO_FUNC_STRING_INDEX) TRIO_PUBLIC_STRING char * trio_string_index TRIO_PROTO((trio_string_t *self, int character)); #endif #if defined(TRIO_FUNC_STRING_INDEX_LAST) TRIO_PUBLIC_STRING char * trio_string_index_last TRIO_PROTO((trio_string_t *self, int character)); #endif #if defined(TRIO_FUNC_STRING_LENGTH) TRIO_PUBLIC_STRING int trio_string_length TRIO_PROTO((trio_string_t *self)); #endif #if defined(TRIO_FUNC_STRING_LOWER) TRIO_PUBLIC_STRING int trio_string_lower TRIO_PROTO((trio_string_t *self)); #endif #if defined(TRIO_FUNC_STRING_MATCH) TRIO_PUBLIC_STRING int trio_string_match TRIO_PROTO((trio_string_t *self, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_MATCH_CASE) TRIO_PUBLIC_STRING int trio_string_match_case TRIO_PROTO((trio_string_t *self, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_SIZE) TRIO_PUBLIC_STRING int trio_string_size TRIO_PROTO((trio_string_t *self)); #endif #if defined(TRIO_FUNC_STRING_SUBSTRING) TRIO_PUBLIC_STRING char * trio_string_substring TRIO_PROTO((trio_string_t *self, trio_string_t *other)); #endif #if defined(TRIO_FUNC_STRING_TERMINATE) TRIO_PUBLIC_STRING void trio_string_terminate TRIO_PROTO((trio_string_t *self)); #endif #if defined(TRIO_FUNC_STRING_UPPER) TRIO_PUBLIC_STRING int trio_string_upper TRIO_PROTO((trio_string_t *self)); #endif #if defined(TRIO_FUNC_XSTRING_APPEND) TRIO_PUBLIC_STRING int trio_xstring_append TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_APPEND_CHAR) TRIO_PUBLIC_STRING int trio_xstring_append_char TRIO_PROTO((trio_string_t *self, char character)); #endif #if defined(TRIO_FUNC_XSTRING_CONTAINS) TRIO_PUBLIC_STRING int trio_xstring_contains TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_COPY) TRIO_PUBLIC_STRING int trio_xstring_copy TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_DUPLICATE) TRIO_PUBLIC_STRING trio_string_t * trio_xstring_duplicate TRIO_PROTO((TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_EQUAL) TRIO_PUBLIC_STRING int trio_xstring_equal TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_EQUAL_MAX) TRIO_PUBLIC_STRING int trio_xstring_equal_max TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_EQUAL_CASE) TRIO_PUBLIC_STRING int trio_xstring_equal_case TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_EQUAL_CASE_MAX) TRIO_PUBLIC_STRING int trio_xstring_equal_case_max TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_MATCH) TRIO_PUBLIC_STRING int trio_xstring_match TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_MATCH_CASE) TRIO_PUBLIC_STRING int trio_xstring_match_case TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other)); #endif #if defined(TRIO_FUNC_XSTRING_SET) TRIO_PUBLIC_STRING void trio_xstring_set TRIO_PROTO((trio_string_t *self, char *buffer)); #endif #if defined(TRIO_FUNC_XSTRING_SUBSTRING) TRIO_PUBLIC_STRING char * trio_xstring_substring TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other)); #endif #ifdef __cplusplus } #endif #endif /* TRIO_TRIOSTR_H */ ================================================ FILE: src/sdk/src/libc/src/udivmoddi4.c ================================================ typedef int SItype __attribute__(( mode( SI ) )); typedef unsigned int USItype __attribute__(( mode( SI ) )); typedef int DItype __attribute__(( mode( DI ) )); typedef unsigned int UDItype __attribute__(( mode( DI ) )); #define Wtype SItype #define UWtype USItype #define DWtype DItype #define UDWtype UDItype #define W_TYPE_SIZE 32 struct DWstruct { Wtype low; Wtype high; }; typedef union { struct DWstruct s; DWtype ll; } DWunion; #define udiv_qrnnd(q, r, n1, n0, dv) \ __asm__("div{l} %4" \ : "=a" ((USItype) (q)), "=d" ((USItype) (r)) \ : "0" ((USItype) (n0)), "1" ((USItype) (n1)), "rm" ((USItype) (dv))) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__("sub{l} {%5,%1|%1,%5}\n\tsbb{l} {%3,%0|%0,%3}" \ : "=r" ((USItype) (sh)), "=&r" ((USItype) (sl)) \ : "0" ((USItype) (ah)), "g" ((USItype) (bh)), \ "1" ((USItype) (al)), "g" ((USItype) (bl))) #define umul_ppmm(w1, w0, u, v) \ __asm__("mul{l} %3" \ : "=a" ((USItype) (w0)), "=d" ((USItype) (w1)) \ : "%0" ((USItype) (u)), "rm" ((USItype) (v))) #define count_leading_zeros(count, x) ((count) = __builtin_clz (x)) static inline __attribute__(( __always_inline__ )) UDWtype __udivmoddi4( UDWtype n, UDWtype d, UDWtype* rp ) { const DWunion nn = {.ll = n}; const DWunion dd = {.ll = d}; DWunion rr; UWtype d0, d1, n0, n1, n2; UWtype q0, q1; UWtype b, bm; d0 = dd.s.low; d1 = dd.s.high; n0 = nn.s.low; n1 = nn.s.high; if ( d1 == 0 ) { if ( d0 > n1 ) { /* 0q = nn / 0D */ udiv_qrnnd (q0, n0, n1, n0, d0); q1 = 0; /* Remainder in n0. */ } else { /* qq = NN / 0d */ if (d0 == 0) d0 = 1 / d0; /* Divide intentionally by zero. */ udiv_qrnnd (q1, n1, 0, n1, d0); udiv_qrnnd (q0, n0, n1, n0, d0); /* Remainder in n0. */ } if (rp != 0) { rr.s.low = n0; rr.s.high = 0; *rp = rr.ll; } } else { if ( d1 > n1 ) { /* 00 = nn / DD */ q0 = 0; q1 = 0; /* Remainder in n1n0. */ if (rp != 0) { rr.s.low = n0; rr.s.high = n1; *rp = rr.ll; } } else { /* 0q = NN / dd */ count_leading_zeros (bm, d1); if (bm == 0) { /* From (n1 >= d1) /\ (the most significant bit of d1 is set), conclude (the most significant bit of n1 is set) /\ (the quotient digit q0 = 0 or 1). This special case is necessary, not an optimization. */ /* The condition on the next line takes advantage of that n1 >= d1 (true due to program flow). */ if (n1 > d1 || n0 >= d0) { q0 = 1; sub_ddmmss (n1, n0, n1, n0, d1, d0); } else q0 = 0; q1 = 0; if (rp != 0) { rr.s.low = n0; rr.s.high = n1; *rp = rr.ll; } } else { UWtype m1, m0; /* Normalize. */ b = W_TYPE_SIZE - bm; d1 = (d1 << bm) | (d0 >> b); d0 = d0 << bm; n2 = n1 >> b; n1 = (n1 << bm) | (n0 >> b); n0 = n0 << bm; udiv_qrnnd (q0, n1, n2, n1, d1); umul_ppmm (m1, m0, q0, d0); if (m1 > n1 || (m1 == n1 && m0 > n0)) { q0--; sub_ddmmss (m1, m0, m1, m0, d1, d0); } q1 = 0; /* Remainder in (n1n0 - m1m0) >> bm. */ if (rp != 0) { sub_ddmmss (n1, n0, n1, n0, m1, m0); rr.s.low = (n1 << b) | (n0 >> bm); rr.s.high = n1 >> bm; *rp = rr.ll; } } } } const DWunion ww = {{.low = q0, .high = q1}}; return ww.ll; } DWtype __moddi3( DWtype u, DWtype v ) { Wtype c = 0; DWunion uu = {.ll = u}; DWunion vv = {.ll = v}; DWtype w; if ( uu.s.high < 0 ) c = ~c, uu.ll = -uu.ll; if ( vv.s.high < 0 ) vv.ll = -vv.ll; ( void )__udivmoddi4( uu.ll, vv.ll, ( UDWtype* )&w ); if ( c ) w = -w; return w; } UDWtype __umoddi3( UDWtype u, UDWtype v ) { UDWtype w; ( void )__udivmoddi4( u, v, &w ); return w; } DWtype __divdi3( DWtype u, DWtype v ) { Wtype c = 0; DWunion uu = {.ll = u}; DWunion vv = {.ll = v}; DWtype w; if (uu.s.high < 0) c = ~c, uu.ll = -uu.ll; if (vv.s.high < 0) c = ~c, vv.ll = -vv.ll; w = __udivmoddi4( uu.ll, vv.ll, ( UDWtype* )0 ); if (c) w = -w; return w; } UDWtype __udivdi3( UDWtype n, UDWtype d ) { return __udivmoddi4( n, d, ( UDWtype* )0 ); } ================================================ FILE: src/sdk/src/libc/src/unistd/access.c ================================================ #include #include #include int access( const char* pathname, int mode ) { int error; error = syscall2( SYS_access, ( int )pathname, mode ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/alarm.c ================================================ #include unsigned int alarm( unsigned int seconds ) { /* TODO */ printf( "TODO: alarm() not yet implemented!\n" ); return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/chdir.c ================================================ #include #include #include int chdir( const char* path ) { int error; error = syscall1( SYS_chdir, ( int )path ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/chown.c ================================================ #include int chown( const char* path, uid_t owner, gid_t group ) { /* TODO */ printf( "TODO: chown() not yet implemented!\n" ); return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/close.c ================================================ #include #include #include int close( int fd ) { int error; error = syscall1( SYS_close, fd ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/dup.c ================================================ #include #include #include int dup( int old_fd ) { int error; error = syscall1( SYS_dup, old_fd ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/dup2.c ================================================ #include #include #include int dup2( int old_fd, int new_fd ) { int error; error = syscall2( SYS_dup2, old_fd, new_fd ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/execlp.c ================================================ #include #include #include #include int execlp( const char* file, const char* arg, ... ) { int i; int n; va_list ap; va_list bak; char* tmp; char** argv; va_start( ap, arg ); __va_copy( bak, ap ); n = 2; while ( ( tmp = va_arg( ap, char* ) ) != NULL ) { ++n; } va_end( ap ); argv = ( char** )alloca( n * sizeof( char* ) ); if ( argv != NULL ) { argv[ 0 ]= ( char* )arg; for ( i = 0 ; i < n; ++i ) { argv[ i + 1 ] = va_arg( bak, char* ); } va_end( bak ); return execvp( file, argv ); } va_end( bak ); errno = ENOMEM; return -1; } ================================================ FILE: src/sdk/src/libc/src/unistd/execv.c ================================================ #include extern char** environ; int execv( const char* file, char* const argv[] ) { return execve( file, argv, environ ); } ================================================ FILE: src/sdk/src/libc/src/unistd/execve.c ================================================ #include #include #include int execve( const char* filename, char* const argv[], char* const envp[] ) { int error; error = syscall3( SYS_execve, ( int )filename, ( int )argv, ( int )envp ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/execvp.c ================================================ #include #include #include #include #include extern char** environ; int execvp( const char* filename, char* const argv[] ) { char* path; char* separator; char tmp_path[ 128 ]; char tmp_exec[ 128 ]; execve( filename, argv, environ ); path = getenv( "PATH" ); if ( path == NULL ) { return -1; } do { separator = strchr( path, ':' ); if ( separator == NULL ) { memcpy( tmp_path, path, strlen( path ) + 1 ); } else { size_t length = ( separator - path ); memcpy( tmp_path, path, length ); tmp_path[ length ] = 0; } snprintf( tmp_exec, sizeof( tmp_exec ), "%s/%s", tmp_path, filename ); execve( tmp_exec, argv, environ ); path = separator + 1; } while ( separator != NULL ); return -1; } ================================================ FILE: src/sdk/src/libc/src/unistd/exit.c ================================================ #include #include #include #include #include typedef void ( *atexit_func_t )( void ); static uint32_t atexit_count = 0; static atexit_func_t atexit_functions[ ATEXIT_MAX ]; int atexit( void ( *function )( void ) ) { if ( atexit_count >= ATEXIT_MAX ) { return -1; } atexit_functions[ atexit_count++ ] = function; return 0; } void exit( int status ) { uint32_t i; for ( i = 0; i < atexit_count; i++ ) { atexit_functions[ i ](); } fflush( stdout ); syscall1( SYS_exit, status ); for (;;); } ================================================ FILE: src/sdk/src/libc/src/unistd/fchdir.c ================================================ #include #include #include int fchdir( int fd ) { int error; error = syscall1( SYS_fchdir, fd ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/fork.c ================================================ #include #include pid_t fork( void ) { return syscall0( SYS_fork ); } ================================================ FILE: src/sdk/src/libc/src/unistd/fpathconf.c ================================================ #include #include long fpathconf( int fd, int name ) { /* TODO */ return -1; } ================================================ FILE: src/sdk/src/libc/src/unistd/ftruncate.c ================================================ #include int ftruncate( int fd, off_t length ) { /* TODO */ printf( "TODO: ftruncate() not yet implemented!\n" ); return -1; } ================================================ FILE: src/sdk/src/libc/src/unistd/getcwd.c ================================================ #include #include #include #include #include #include #include #include char* getcwd( char* buf, size_t size ) { static const char dots[] = "../../../../../../../../../../../../../../../../../../../../../../../\ ../../../../../../../../../../../../../../../../../../../../../../../../../../\ ../../../../../../../../../../../../../../../../../../../../../../../../../.."; const char* dotp = &dots[ sizeof( dots ) ]; const char* dotlist = dots; size_t dotsize = sizeof( dots ) - 1; dev_t rootdev, thisdev; ino_t rootino, thisino; char* path; register char* pathp; struct stat st; size_t allocated = size; if ( size == 0 ) { if ( buf != NULL ) { return NULL; } allocated = PATH_MAX + 1; } if ( buf != NULL ) { path = buf; } else { path = malloc( allocated ); if ( path == NULL ) { return NULL; } } pathp = path + allocated; *--pathp = '\0'; if ( stat( ".", &st ) < 0 ) { goto lose2; } thisdev = st.st_dev; thisino = st.st_ino; if ( stat( "/", &st ) < 0 ) { goto lose2; } rootdev = st.st_dev; rootino = st.st_ino; while ( !( thisdev == rootdev && thisino == rootino ) ) { register DIR *dirstream; struct dirent* d; dev_t dotdev; ino_t dotino; char mount_point; /* Look at the parent directory. */ if ( dotp == dotlist ) { /* My, what a deep directory tree you have, Grandma. */ char* new; if ( dotlist == dots ) { new = malloc( dotsize * 2 + 1 ); if ( new == NULL ) { goto lose; } #ifdef HAVE_MEMPCPY dotp = mempcpy( new, dots, dotsize ); #else memcpy( new, dots, dotsize ); dotp = &new[ dotsize ]; #endif } else { new = realloc( ( void* )dotlist, dotsize * 2 + 1 ); if ( new == NULL ) { goto lose; } dotp = &new[ dotsize ]; } #ifdef HAVE_MEMPCPY *( ( char* )mempcpy( ( char* )dotp, new, dotsize ) ) = '\0'; dotsize *= 2; #else memcpy( ( char* )dotp, new, dotsize ); dotsize *= 2; new[ dotsize ] = '\0'; #endif dotlist = new; } dotp -= 3; /* Figure out if this directory is a mount point. */ if ( stat( dotp, &st ) < 0 ) { goto lose; } dotdev = st.st_dev; dotino = st.st_ino; mount_point = dotdev != thisdev; /* Search for the last directory. */ dirstream = opendir( dotp ); if ( dirstream == NULL ) { goto lose; } while ( ( d = readdir( dirstream ) ) != NULL ) { if ( d->d_name[ 0 ] == '.' && ( d->d_name[ 1 ] == '\0' || (d->d_name[ 1 ] == '.' && d->d_name[ 2 ] == '\0' ) ) ) { continue; } if ( mount_point || ( ino_t )d->d_ino == thisino ) { char name[ dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN( d ) ]; #ifdef HAVE_MEMPCPY char *tmp = mempcpy( name, dotp, dotlist + dotsize - dotp ); *tmp++ = '/'; strcpy( tmp, d->d_name ); #else memcpy( name, dotp, dotlist + dotsize - dotp ); name[ dotlist + dotsize - dotp ] = '/'; strcpy( &name[ dotlist + dotsize - dotp + 1 ], d->d_name ); #endif /* We don't fail here if we cannot stat() a directory entry. This can happen when (network) filesystems fail. If this entry is in fact the one we are looking for we will find out soon as we reach the end of the directory without having found anything. */ if ( stat( name, &st ) >= 0 && st.st_dev == thisdev && st.st_ino == thisino ) { break; } } } if ( d == NULL ) { ( void )closedir( dirstream ); goto lose; } else { size_t namlen = _D_EXACT_NAMLEN( d ); if ( ( size_t )( pathp - path ) <= namlen ) { if (size != 0) { ( void )closedir( dirstream ); goto lose; } else { char* tmp; size_t oldsize = allocated; allocated = 2 * MAX( allocated, namlen ); tmp = realloc( path, allocated ); if ( tmp == NULL ) { ( void )closedir( dirstream ); goto lose; } /* Move current contents up to the end of the buffer. This is guaranteed to be non-overlapping. */ pathp = memcpy( tmp + allocated - ( path + oldsize - pathp ), tmp + ( pathp - path ), path + oldsize - pathp ); path = tmp; } } pathp -= namlen; ( void )memcpy( pathp, d->d_name, namlen ); *--pathp = '/'; ( void )closedir( dirstream ); } thisdev = dotdev; thisino = dotino; } if ( pathp == &path[ allocated - 1 ] ) { *--pathp = '/'; } if ( dotlist != dots ) { free( ( void* )dotlist ); } memmove( path, pathp, path + allocated - pathp ); return path; lose: if ( dotlist != dots ) { free( ( void* )dotlist ); } lose2: if ( buf == NULL ) { free( path ); } return NULL; } ================================================ FILE: src/sdk/src/libc/src/unistd/getdents.c ================================================ #include #include #include int getdents( int fd, struct dirent* entry, unsigned int count ) { int error; error = syscall3( SYS_getdents, fd, ( int )entry, count ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/getdtablesize.c ================================================ #include int getdtablesize( void ) { return 1024; } ================================================ FILE: src/sdk/src/libc/src/unistd/getegid.c ================================================ #include gid_t getegid( void ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/geteuid.c ================================================ #include uid_t geteuid( void ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/getgid.c ================================================ #include gid_t getgid( void ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/gethostname.c ================================================ #include #include int gethostname( char* name, size_t len ) { /* TODO */ snprintf( name, len, "localhost" ); return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/getpgid.c ================================================ #include pid_t getpgid( pid_t pid ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/getpgrp.c ================================================ #include pid_t getpgrp( void ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/getpid.c ================================================ #include #include pid_t getpid( void ) { return syscall0( SYS_getpid ); } ================================================ FILE: src/sdk/src/libc/src/unistd/getppid.c ================================================ #include pid_t getppid( void ) { /* TODO! */ return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/gettid.c ================================================ #include #include #include pid_t gettid( void ) { return syscall0( SYS_gettid ); } ================================================ FILE: src/sdk/src/libc/src/unistd/getuid.c ================================================ #include #include uid_t getuid( void ) { return syscall0( SYS_getuid ); } ================================================ FILE: src/sdk/src/libc/src/unistd/isatty.c ================================================ #include #include #include int isatty( int fd ) { int error; error = syscall1( SYS_isatty, fd ); if ( error < 0 ) { errno = -error; return 0; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/link.c ================================================ #include int link( const char* oldpath, const char* newpath ) { /* TODO */ printf( "TODO: link() not yet implemented!\n" ); return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/lseek.c ================================================ #include #include #include off_t lseek( int fd, off_t offset, int whence ) { int error; off_t result; error = syscall4( SYS_lseek, fd, ( int )&offset, whence, ( int )&result ); if ( error < 0 ) { errno = -error; return ( off_t )-1; } return result; } ================================================ FILE: src/sdk/src/libc/src/unistd/mmap.c ================================================ #include #include #include void * mmap (void *addr,size_t len,int prot,int flags,int fd,off_t offset){ return (void*)syscall5(SYS_mmap,(uint32_t) len, (uint32_t) prot, (uint32_t) flags,(uint32_t) fd,(uint32_t) offset); } ================================================ FILE: src/sdk/src/libc/src/unistd/pipe.c ================================================ #include int pipe( int pipefd[2] ) { /* TODO */ printf( "TODO: pipe() not yet implemented!\n" ); return -1; } ================================================ FILE: src/sdk/src/libc/src/unistd/pread.c ================================================ #include #include #include ssize_t pread( int fd, void* buf, size_t count, off_t offset ) { int error; error = syscall4( SYS_pread, fd, ( int )buf, count, ( int )&offset ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/pwrite.c ================================================ #include #include #include ssize_t pwrite( int fd, const void* buf, size_t count, off_t offset ) { int error; error = syscall4( SYS_pwrite, fd, ( int )buf, count, ( int )&offset ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/read.c ================================================ #include #include #include ssize_t read( int fd, void* buf, size_t count ) { int error; error = syscall3( SYS_read, fd, ( int )buf, count ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/readlink.c ================================================ #include #include #include #include ssize_t readlink( const char* path, char* buf, size_t bufsiz ) { int error; error = syscall3( SYS_readlink, ( int )path, ( int )buf, bufsiz ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/sdk/src/libc/src/unistd/rmdir.c ================================================ #include #include #include int rmdir( const char* pathname ) { int error; error = syscall1( SYS_rmdir, ( int )pathname ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/sbrk.c ================================================ #include void* sbrk( int increment ) { return ( void* )syscall1( SYS_sbrk, increment ); } ================================================ FILE: src/sdk/src/libc/src/unistd/setgid.c ================================================ #include int setgid( gid_t gid ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/setpgid.c ================================================ #include int setpgid( pid_t pid, pid_t pgid ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/setpgrp.c ================================================ #include int setpgrp( void ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/setregid.c ================================================ #include int setregid( gid_t rgid, gid_t egid ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/setreuid.c ================================================ #include int setreuid( uid_t ruid, uid_t euid ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/setuid.c ================================================ #include int setuid( uid_t uid ) { return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/sleep.c ================================================ #include #include unsigned int sleep( unsigned int seconds ) { uint64_t time; time = seconds * 1000000; syscall2( SYS_sleep_thread, ( int )&time, ( int )NULL ); return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/symlink.c ================================================ #include #include #include int symlink( const char* oldpath, const char* newpath ) { int error; error = syscall2( SYS_symlink, ( int )oldpath, ( int )newpath ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/ttyname.c ================================================ #include #include #include #include static char ttyname_buffer[ 128 ]; int ttyname_r( int fd, char* buf, size_t buflen ) { int dir; int error; int found; struct stat st; struct dirent entry; error = fstat( fd, &st ); if ( error < 0 ) { return -1; } dir = open( "/device/terminal", O_RDONLY ); if ( dir < 0 ) { return -1; } found = 0; while ( getdents( dir, &entry, sizeof( struct dirent ) ) == 1 ) { if ( entry.d_ino == st.st_ino ) { snprintf( buf, buflen, "/device/terminal/%s", entry.d_name ); found = 1; break; } } close( dir ); if ( !found ) { return -1; } return 0; } char* ttyname( int fd ) { int error; error = ttyname_r( fd, ttyname_buffer, sizeof( ttyname_buffer ) ); if ( error < 0 ) { return NULL; } return ttyname_buffer; } ================================================ FILE: src/sdk/src/libc/src/unistd/unlink.c ================================================ #include #include #include int unlink( const char* pathname ) { int error; error = syscall1( SYS_unlink, ( int )pathname ); if ( error < 0 ) { errno = -error; return -1; } return 0; } ================================================ FILE: src/sdk/src/libc/src/unistd/write.c ================================================ #include #include #include ssize_t write( int fd, const void* buf, size_t count ) { int error; error = syscall3( SYS_write, fd, ( int )buf, count ); if ( error < 0 ) { errno = -error; return -1; } return error; } ================================================ FILE: src/userland/Makefile ================================================ all: make -C "helloworld" all clean: make -C "helloworld" clean ================================================ FILE: src/userland/helloworld/Makefile ================================================ SDKDIR=../../sdk TARGET = hello OBJS=main.o include $(SDKDIR)/build.mak ================================================ FILE: src/userland/helloworld/main.c ================================================ #include #include #include #include #include #include #include int main(int argc,char **argv){ printf("hello world ! \n"); return 0; }