diff --git a/.gitignore b/.gitignore index 085a7b57..251c75e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,94 +1,44 @@ -*.aux -*.idx -*.ilg -*.ind -*.log +*.so +*.a *.o -*.out -*.pdf -*.swp -*.swn -*.toc -*.ko -*.img.gz - -# Makefile magic -/.compositor-check -/.config -/.passed -/.userspace-check -/.disk_size -/.ramdisk_size -/.toolchain - -/util/*.img -/util/*.vmdk -/util/*.vdi -/util/bin/ - -/hdd/bin/ -/hdd/boot/ -/hdd/home/local/ -/hdd/home/root/ -/hdd/etc/hostname - -/hdd/lib -/hdd/opt - -/hdd/usr/bin -/hdd/usr/etc -/hdd/usr/i686-pc-toaru -/hdd/usr/include -/hdd/usr/lib -/hdd/usr/libexec -/hdd/usr/local -/hdd/usr/man -/hdd/usr/share/aclocal -/hdd/usr/share/doc -/hdd/usr/share/games -/hdd/usr/share/gcc-4.6.* -/hdd/usr/share/gtk-doc -/hdd/usr/share/info -/hdd/usr/share/locale -/hdd/usr/share/man -/hdd/usr/share/tabset -/hdd/usr/share/terminfo -/hdd/usr/share/vim -/hdd/usr/share/icons/external -/hdd/usr/share/fontconfig -/hdd/usr/share/xml -/hdd/usr/python -/hdd/usr/gcc - -# pseudo-submodules -/toaru-pdfviewer -/toaru-python -/pycairo - -# Generated files / targets -/kernel/symbols.s -/kernel/symbols.S -/tags -/toaruos-disk.img -/toaruos-kernel -/toaruos.iso -/toaruos-big.iso -/modpack.kop -/cdrom/ -/kernel-headers.img - -# Toolchain -/toolchain/build -/toolchain/local -/toolchain/tarballs - -# Tool-generated files -/qemu-vlan0.pcap -# gdb history can end up all sorts of places +*.iso +*.efi .gdb_history -/contrib +/.make/* +/base/bin/* +/cdrom/kernel +/cdrom/netinit +/cdrom/mod/* +/cdrom/ramdisk.img +/cdrom/boot.sys +/cdrom/fat.img +/fatbase/kernel +/fatbase/netinit +/fatbase/mod/* +/fatbase/ramdisk.img +/fatbase/efi/boot/bootia32.efi +/util/tarballs +/util/build +/util/local +/util/devtable +/util/tmp-gcc +/kernel/symbols.S +/base/usr/python +/base/usr/bin/* +/base/usr/lib/* +/base/usr/share/python-demos +/base/usr/share/help -# Vagrant configs shouldn't end up in git -/.vagrant -/Vagrantfile +# Generic +/base/usr/share/aclocal +/base/usr/share/gtk-doc + +# Freetype +/base/usr/include/freetype2 +/base/usr/include/ft2build.h +/base/usr/share/fonts + +# Cairo + Pixman +/base/usr/include/cairo +/base/usr/include/pixman-1 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 40004e53..00000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: c -script: - - docker run -v `pwd`:/opt/tree -w /opt/tree -t toaruos/build-tools:test util/build-travis.sh -sudo: required -dist: trusty -serivces: - - docker -before_install: - - docker pull toaruos/build-tools:test -notifications: - irc: - channels: - - secure: "YIH2do6BypI1ZiXONyldvW/xt8O2j/PDb3sPzGUwJql08pItH3t3MPN3JHtKEBU7+/yFB58HbA2C8B1gu/oAGs2tqMCFYiapVUYYv5CudvMt+XkBzxgKRFwPcvPtz+lAjVbIM0SXDdlrfjczDGKPnEvCYBIu+ZYlz8dgn5DEVX8=" - use_notice: false - skip_join: true -deploy: - provider: releases - api_key: - secure: Lcs5kHe9HAwcVLdm8c0FkAb77U9yzUQdI5PmTU1AnFyHtrPmW1+9d6HeYSPLHm+cPAUdWKqouJNKW7s76Sqhz+4IDcwro7VkbV/fd9NFQCOf9Jb5QScmCZndmYVQUiUmy/7wVqGdy+vatKEsnngctT7aVVhJ5SrWoCPmcttUez8= - file: toaruos.iso - skip_cleanup: true - overwrite: true - on: - tags: true diff --git a/LICENSE b/LICENSE index 079eefea..7b7631f8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,35 +1,33 @@ -Copyright (c) 2011-2017 Kevin Lange. All rights reserved. - Dedicated to the memory of - Dennis Ritchie - 1941-2011 +University of Illinois/NCSA Open Source License -Developed by: ToAruOS Kernel Development Team - http://toaruos.org +Copyright (c) 2011-2018 K Lange, et al. (hereafter [fullname]). All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal with the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - 3. Neither the names of the ToAruOS Kernel Development Team, Kevin Lange, - nor the names of its contributors may be used to endorse - or promote products derived from this Software without specific prior - written permission. +Developed by: ToaruOS (hereafter [project]) + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal with the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -WITH THE SOFTWARE. +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. -Additional licenses are available from hdd/usr/share/help/licenses, or through -the Help Browser > Contents > Licenses within the OS. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + +* Neither the names of [fullname], [project] nor the names of its + contributors may be used to endorse or promote products derived from + this Software without specific prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH +THE SOFTWARE. diff --git a/Makefile b/Makefile index 3dbd1b6d..b8a1b659 100644 --- a/Makefile +++ b/Makefile @@ -1,511 +1,377 @@ -# ToaruOS Build Scripts -ifneq ($(MAKECMDGOALS),toolchain) - ifeq ($(TOOLCHAIN),) - $(error $(shell util/helpful-toolchain-error.sh)) - else - $(shell util/cache-toolchain.sh) - endif +ifeq ($(TOOLCHAIN),) + ifeq ($(shell util/check.sh),y) + export PATH := $(shell util/activate.sh) + else + FOO := $(shell util/prompt.sh) + ifeq ($(shell util/check.sh),y) + export PATH := $(shell util/activate.sh) + else + $(error "No toolchain, and you did not ask to build it.") + endif + endif endif -KERNEL_TARGET=i686-elf -USER_TARGET=i686-pc-toaru - -# Pretty output utilities. -BEG = util/mk-beg -END = util/mk-end -INFO = util/mk-info -ERRORS = 2>>/tmp/.`whoami`-build-errors || util/mk-error -ERRORSS = >>/tmp/.`whoami`-build-errors || util/mk-error -BEGRM = util/mk-beg-rm -ENDRM = util/mk-end-rm - -# Rules start here. -.PHONY: all system install test toolchain userspace modules cdrom fix-cd -.PHONY: clean clean-soft clean-hard clean-user clean-mods clean-core clean-disk clean-once -.PHONY: run vga term headless curses quick -.PHONY: debug debug-vga debug-term debug-curses -.PHONY: virtualbox virtualbox-cdrom run-cdrom - # Prevents Make from removing intermediary files on failure .SECONDARY: # Disable built-in rules .SUFFIXES: -all: $(shell util/detect-make-all.sh) +all: image.iso -toolchain: - @cd toolchain; ./toolchain-build.sh +TARGET_TRIPLET=i686-pc-toaru -########################### -# Emulator Pseudo-targets # -########################### +# Userspace flags -# Specify which modules should be included on startup. -# There are a few modules that are kinda required for a working system -# such as all of the dependencies needed to mount the root partition. -# We can also include things like the debug shell... -# Note that ordering matters - list dependencies first. -BOOT_MODULES := zero random serial -BOOT_MODULES += procfs tmpfs ata -#BOOT_MODULES += dospart -BOOT_MODULES += ext2 -BOOT_MODULES += debug_shell -BOOT_MODULES += ps2mouse ps2kbd -BOOT_MODULES += lfbvideo -BOOT_MODULES += vidset -BOOT_MODULES += packetfs -BOOT_MODULES += snd -BOOT_MODULES += pcspkr -BOOT_MODULES += ac97 -BOOT_MODULES += net rtl +CC=$(TARGET_TRIPLET)-gcc +AR=$(TARGET_TRIPLET)-ar +AS=$(TARGET_TRIPLET)-as +CFLAGS= -O3 -g -std=gnu99 -I. -Iapps -pipe -mmmx -msse -msse2 -fplan9-extensions -Wall -Wextra -Wno-unused-parameter -# This is kinda silly. We're going to form an -initrd argument.. -# which is basically -initrd "hdd/mod/%.ko,hdd/mod/%.ko..." -# for each of the modules listed above in BOOT_MODULES -COMMA := , -EMPTY := -SPACE := $(EMPTY) $(EMPTY) -BOOT_MODULES_X = -initrd "$(subst $(SPACE),$(COMMA),$(foreach mod,$(BOOT_MODULES),hdd/mod/$(mod).ko))" +## +# C library objects from libc/ C sources (and setjmp, which is assembly) +LIBC_OBJS = $(patsubst %.c,%.o,$(wildcard libc/*.c)) +LIBC_OBJS += $(patsubst %.c,%.o,$(wildcard libc/*/*.c)) +LIBC_OBJS += libc/setjmp.o +LC=base/lib/libc.so -# QEMU Configuration -EMU = qemu-system-i386 +## +# APPS = C sources from apps/ +# APPS_X = binaries +# APPS_Y = generated makefiles for binaries (except init) +# APPS_SH = shell scripts to copy to base/bin/ and mark executable +# APPS_SH_X = destinations for shell scripts +APPS=$(patsubst apps/%.c,%,$(wildcard apps/*.c)) +APPS_X=$(foreach app,$(APPS),base/bin/$(app)) +APPS_Y=$(foreach app,$(filter-out init,$(APPS)),.make/$(app).mak) +APPS_SH=$(patsubst apps/%.sh,%.sh,$(wildcard apps/*.sh)) +APPS_SH_X=$(foreach app,$(APPS_SH),base/bin/$(app)) -# Force the SDL backend with no frame and English (US) keyboard. -EMUARGS = -sdl -no-frame -k en-us -# 1GB of RAM -EMUARGS += -m 1024 -# Bochs VBE display device -EMUARGS += -vga std -# Realtime clock based on localtime (we don't NTP or support timezone configs yet) -EMUARGS += -rtc base=localtime -# Network hardware: RTL8139, usermode network emulation. -EMUARGS += -net nic,model=rtl8139 -net user -# Enable TCP dumps for monitoring. -EMUARGS += -net dump -# Sound hardware: Intel AC'97, PC beeper -EMUARGS += -soundhw pcspk,ac97 -# Enable KVM if available, or fall back to TCG -EMUARGS += -M accel=kvm:tcg +## +# LIBS = C sources from lib/ +# LIBS_X = Shared libraries (.so) +# LIBS_Y = Generated makefiles for libraries +LIBS=$(patsubst lib/%.c,%,$(wildcard lib/*.c)) +LIBS_X=$(foreach lib,$(LIBS),base/lib/libtoaru_$(lib).so) +LIBS_Y=$(foreach lib,$(LIBS),.make/$(lib).lmak) -# For development images, load the kernel, modules, hard disk. -EMUKARGS = -kernel toaruos-kernel -EMUKARGS += $(BOOT_MODULES_X) -EMUKARGS += -hda toaruos-disk.img +## +# Files that must be present in the ramdisk (apps, libraries) +RAMDISK_FILES= ${APPS_X} ${APPS_SH_X} ${LIBS_X} base/lib/ld.so base/lib/libm.so -# These arguments are passed to the kernel command line. -DISK_ROOT = root=/dev/hda -VID_QEMU = vid=qemu,,1280,,720 -START_VGA = start=--vga -START_SINGLE = start=--single -START_LIVE = start=live-welcome -WITH_LOGS = logtoserial=1 +# Kernel / module flags -# Various different quick options -run: system - ${EMU} ${EMUARGS} ${EMUKARGS} -append "$(VID_QEMU) $(DISK_ROOT)" -quick: system - ${EMU} ${EMUARGS} ${EMUKARGS} -append "$(VID_QEMU) $(DISK_ROOT) start=quick-launch" -debug: system - ${EMU} ${EMUARGS} ${EMUKARGS} -serial stdio -append "$(VID_QEMU) $(WITH_LOGS) $(DISK_ROOT)" -vga: system - ${EMU} ${EMUARGS} ${EMUKARGS} -append "$(START_VGA) $(DISK_ROOT)" -debug-vga: system - ${EMU} ${EMUARGS} ${EMUKARGS} -serial stdio -append "$(WITH_LOGS) $(START_VGA) $(DISK_ROOT)" -term: system - ${EMU} ${EMUARGS} ${EMUKARGS} -append "$(VID_QEMU) $(START_SINGLE) $(DISK_ROOT)" -debug-term: system - ${EMU} ${EMUARGS} ${EMUKARGS} -serial stdio -append "$(VID_QEMU) $(START_SINGLE) $(WITH_LOGS) $(DISK_ROOT)" -headless: system - ${EMU} ${EMUARGS} ${EMUKARGS} -display none -append "$(START_VGA) $(DISK_ROOT)" -curses: system - ${EMU} ${EMUARGS} ${EMUKARGS} -curses -append "$(START_VGA) $(DISK_ROOT)" -debug-curses: system - ${EMU} ${EMUARGS} ${EMUKARGS} -serial file:serial-debug.log -curses -append "$(WITH_LOGS) $(START_VGA) $(DISK_ROOT)" -live: system - ${EMU} ${EMUARGS} ${EMUKARGS} -append "$(VID_QEMU) $(START_LIVE) $(DISK_ROOT)" +KCC = $(TARGET_TRIPLET)-gcc +KAS = $(TARGET_TRIPLET)-as +KLD = $(TARGET_TRIPLET)-ld +KNM = $(TARGET_TRIPLET)-nm -# Run the cdrom -run-cdrom: toaruos.iso - ${EMU} ${EMUARGS} -cdrom toaruos.iso +KCFLAGS = -O2 -std=c99 +KCFLAGS += -finline-functions -ffreestanding +KCFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format +KCFLAGS += -pedantic -fno-omit-frame-pointer +KCFLAGS += -D_KERNEL_ +KCFLAGS += -DKERNEL_GIT_TAG=$(shell util/make-version) +KASFLAGS = --32 -# Run VirtualBox -virtualbox: system - util/run-virtualbox.sh -virtualbox-cdrom: toaruos.iso - util/run-virtualbox-cdrom.sh - -# Run the test suite -test: system - expect util/test.exp - -################ -# Kernel # -################ - -# Kernel build flags -CFLAGS = -O2 -std=c99 -CFLAGS += -finline-functions -ffreestanding -CFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format -CFLAGS += -pedantic -fno-omit-frame-pointer -CFLAGS += -D_KERNEL_ -ASFLAGS = --32 - -# Build kernel with bare elf toolchain -KCC = $(KERNEL_TARGET)-gcc -KNM = $(KERNEL_TARGET)-nm -KCXX= $(KERNEL_TARGET)-g++ -KAR = $(KERNEL_TARGET)-ar -KAS = $(KERNEL_TARGET)-as -KSTRIP = $(KERNEL_TARGET)-strip - -# Kernel autoversioning with git sha -CFLAGS += -DKERNEL_GIT_TAG=`util/make-version` - -# All of the core parts of the kernel are built directly. +## +# Kernel objects from kernel/ C sources KERNEL_OBJS = $(patsubst %.c,%.o,$(wildcard kernel/*.c)) KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*.c)) KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*/*.c)) +## +# Kernel objects from kernel/ assembly sources KERNEL_ASMOBJS = $(filter-out kernel/symbols.o,$(patsubst %.S,%.o,$(wildcard kernel/*.S))) -toaruos-kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o - @${BEG} "CC" "$@" - @${KCC} -T kernel/link.ld ${CFLAGS} -nostdlib -o toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o -lgcc ${ERRORS} - @${END} "CC" "$@" - @${INFO} "--" "Kernel is ready!" +# Kernel +fatbase/kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o + ${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o $@ ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o -lgcc + +## +# Symbol table for the kernel. Instead of relying on getting +# the symbol table from our bootloader (eg. through ELF +# headers provided via multiboot structure), we have a dedicated +# object that build with all the symbols. This allows us to +# build the kernel as a flat binary or load it with less-capable +# multiboot loaders and still get symbols, which we need to +# load kernel modules and link them properly. kernel/symbols.o: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} util/generate_symbols.py - @-rm -f kernel/symbols.o - @${BEG} "NM" "Generating symbol list..." - @${KCC} -T kernel/link.ld ${CFLAGS} -nostdlib -o toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} -lgcc ${ERRORS} - @${KNM} toaruos-kernel -g | util/generate_symbols.py > kernel/symbols.S - @${END} "NM" "Generated symbol list." - @${BEG} "AS" "kernel/symbols.S" - @${KAS} ${ASFLAGS} kernel/symbols.S -o $@ ${ERRORS} - @${END} "AS" "kernel/symbols.S" + -rm -f kernel/symbols.o + ${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o .toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} -lgcc + ${KNM} .toaruos-kernel -g | util/generate_symbols.py > kernel/symbols.S + ${KAS} ${KASFLAGS} kernel/symbols.S -o $@ + -rm -f .toaruos-kernel +## +# version.o should be rebuilt whenever the kernel changes +# in order to get fresh git commit hash information. kernel/sys/version.o: kernel/*/*.c kernel/*.c -hdd/mod: - @mkdir -p hdd/mod +kernel/%.o: kernel/%.S + ${KAS} ${ASFLAGS} $< -o $@ -# Loadable modules -MODULES = $(patsubst modules/%.c,hdd/mod/%.ko,$(wildcard modules/*.c)) +kernel/%.o: kernel/%.c ${HEADERS} + ${KCC} ${KCFLAGS} -nostdlib -g -c -o $@ $< -# We also want to rebuild when a header changes. -# This is a naive approach, but it works... -HEADERS = $(shell find kernel/include/ -type f -name '*.h') +# Modules -hdd/mod/%.ko: modules/%.c ${HEADERS} | hdd/mod - @${BEG} "CC" "$< [module]" - @${KCC} -T modules/link.ld -I./kernel/include -nostdlib ${CFLAGS} -c -o $@ $< ${ERRORS} - @${END} "CC" "$< [module]" +fatbase/mod: + @mkdir -p $@ + +## +# Modules need to be installed on the boot image +MODULES = $(patsubst modules/%.c,fatbase/mod/%.ko,$(wildcard modules/*.c)) +HEADERS = $(shell find base/usr/include/kernel -type f -name '*.h') + +fatbase/mod/%.ko: modules/%.c ${HEADERS} | fatbase/mod + ${KCC} -T modules/link.ld -nostdlib ${KCFLAGS} -c -o $@ $< modules: ${MODULES} -kernel/%.o: kernel/%.S - @${BEG} "AS" "$<" - @${KAS} ${ASFLAGS} $< -o $@ ${ERRORS} - @${END} "AS" "$<" +# Root Filesystem -kernel/%.o: kernel/%.c ${HEADERS} - @${BEG} "CC" "$<" - @${KCC} ${CFLAGS} -nostdlib -g -I./kernel/include -c -o $@ $< ${ERRORS} - @${END} "CC" "$<" +base/dev: + mkdir -p $@ +base/tmp: + mkdir -p $@ +base/proc: + mkdir -p $@ +base/bin: + mkdir -p $@ +base/lib: + mkdir -p $@ +base/cdrom: + mkdir -p $@ +fatbase/efi/boot: + mkdir -p $@ +.make: + mkdir -p .make +dirs: base/dev base/tmp base/proc base/bin base/lib base/cdrom fatbase/efi/boot .make -system: toaruos-disk.img toaruos-kernel ${MODULES} +# C Library -############# -# Userspace # -############# +crts: base/lib/crt0.o base/lib/crti.o base/lib/crtn.o | dirs -# Userspace build flags -USER_CFLAGS = -O3 -m32 -Wa,--32 -g -Iuserspace -std=c99 -U__STRICT_ANSI__ -Lhdd/usr/lib -USER_CXXFLAGS = -O3 -m32 -Wa,--32 -g -Iuserspace -USER_BINFLAGS = -STRIP_LIBS = 1 +base/lib/crt%.o: libc/crt%.s + yasm -f elf -o $@ $< -# We always build with our targetted cross-compiler -CC = $(USER_TARGET)-gcc -NM = $(USER_TARGET)-nm -CXX= $(USER_TARGET)-g++ -AR = $(USER_TARGET)-ar -AS = $(USER_TARGET)-as -STRIP = $(USER_TARGET)-strip +libc/setjmp.o: libc/setjmp.S + $(AS) -o $@ $< -# Userspace binaries and libraries -USER_CFILES = $(filter-out userspace/core/init.c,$(shell find userspace -not -wholename '*/lib/*' -not -wholename '*.static.*' -name '*.c')) -USER_CXXFILES = $(shell find userspace -not -wholename '*/lib/*' -name '*.c++') -USER_LIBFILES = $(shell find userspace -wholename '*/lib/*' -name '*.c') +libc/%.o: libc/%.c + $(CC) $(CFLAGS) -fPIC -c -o $@ $< -LIBC=hdd/usr/lib/libc.so +base/lib/libc.a: ${LIBC_OBJS} | dirs crts + $(AR) cr $@ $^ -# PYthon sources -PYTHON_LIBS = $(shell find userspace -wholename '*/lib/*' -name '*.py') -PYTHON_BINS = $(shell find userspace -wholename '*/bin/*' -name '*.py') +base/lib/libc.so: ${LIBC_OBJS} | dirs crts + $(CC) -nodefaultlibs -o $@ $(CFLAGS) -shared -fPIC $^ -lgcc -PYTHON_FILES = $(foreach file,$(PYTHON_LIBS),$(patsubst %.py,hdd/usr/python/lib/python3.6/%.py,$(notdir ${file}))) -PYTHON_FILES += $(foreach file,$(PYTHON_BINS),$(patsubst %.py,hdd/bin/%.py,$(notdir ${file}))) +base/lib/libm.so: util/lm.c | dirs crts + $(CC) -nodefaultlibs -o $@ $(CFLAGS) -shared -fPIC $^ -lgcc -# Userspace output files (so we can define metatargets) -NONTEST_C = $(foreach f,$(USER_CFILES),$(if $(findstring /tests/,$f),,$f)) -NONTEST_CXX = $(foreach f,$(USER_CXXFILES),$(if $(findstring /tests/,$f),,$f)) +# Userspace Linker/Loader -NONTEST = $(foreach file,$(NONTEST_C),$(patsubst %.c,hdd/bin/%,$(notdir ${file}))) -NONTEST += $(foreach file,$(NONTEST_CXX),$(patsubst %.c++,hdd/bin/%,$(notdir ${file}))) -NONTEST += $(foreach file,$(USER_CSTATICFILES),$(patsubst %.static.c,hdd/bin/%,$(notdir ${file}))) -NONTEST += $(foreach file,$(USER_LIBFILES),$(patsubst %.c,hdd/usr/lib/libtoaru-%.so,$(notdir ${file}))) -NONTEST += $(LIBC) hdd/bin/init hdd/lib/ld.so +base/lib/ld.so: linker/linker.c base/lib/libc.a | dirs + $(CC) -static -Wl,-static $(CFLAGS) -o $@ -Os -T linker/link.ld $< -USERSPACE = $(foreach file,$(USER_CFILES),$(patsubst %.c,hdd/bin/%,$(notdir ${file}))) -USERSPACE += $(foreach file,$(USER_CXXFILES),$(patsubst %.c++,hdd/bin/%,$(notdir ${file}))) -USERSPACE += $(foreach file,$(USER_CSTATICFILES),$(patsubst %.static.c,hdd/bin/%,$(notdir ${file}))) -USERSPACE += $(foreach file,$(USER_LIBFILES),$(patsubst %.c,hdd/usr/lib/libtoaru-%.so,$(notdir ${file}))) -USERSPACE += $(LIBC) hdd/bin/init hdd/lib/ld.so +# Shared Libraries +.make/%.lmak: lib/%.c util/auto-dep.py | dirs + util/auto-dep.py --makelib $< > $@ -userspace: ${USERSPACE} +ifeq (,$(findstring clean,$(MAKECMDGOALS))) +-include ${LIBS_Y} +endif -# Init must be built static at the moment. -hdd/bin/init: userspace/core/init.c - @${BEG} "CC" "$< (static)" - @${CC} -o $@ -static -Wl,-static $(USER_CFLAGS) $(USER_BINFLAGS) $< ${ERRORS} - @${END} "CC" "$< (static)" +# Init (static) -# Libraries -define user-c-rule -$1: $2 $(shell util/auto-dep.py --deps $2) $(LIBC) - @${BEG} "CCSO" "$$<" - @${CC} -o $$@ $(USER_CFLAGS) -shared -fPIC $$(shell util/auto-dep.py --cflags $$<) $$< $$(shell util/auto-dep.py --libs $$<) -lc ${ERRORS} - @if [ "x$(STRIP_LIBS)" = "x1" ]; then ${STRIP} $$@; fi - @${END} "CCSO" "$$<" -endef -$(foreach file,$(USER_LIBFILES),$(eval $(call user-c-rule,$(patsubst %.c,hdd/usr/lib/libtoaru-%.so,$(notdir ${file})),${file}))) +base/bin/init: apps/init.c base/lib/libc.a | dirs + $(CC) -static -Wl,-static $(CFLAGS) -o $@ $< -# Binaries from C sources -define user-c-rule -$1: $2 $(shell util/auto-dep.py --deps $2) $(LIBC) - @${BEG} "CC" "$$<" - @${CC} -o $$@ $(USER_CFLAGS) $(USER_BINFLAGS) -fPIE $$(shell util/auto-dep.py --cflags $$<) $$< $$(shell util/auto-dep.py --libs $$<) -lc ${ERRORS} - @${END} "CC" "$$<" -endef -$(foreach file,$(USER_CFILES),$(eval $(call user-c-rule,$(patsubst %.c,hdd/bin/%,$(notdir ${file})),${file}))) +fatbase/netinit: util/netinit.c base/lib/libc.a | dirs + $(CC) -static -Wl,-static $(CFLAGS) -o $@ $< -# Binaries from C++ sources -define user-cxx-rule -$1: $2 $(shell util/auto-dep.py --deps $2) $(LIBC) - @${BEG} "C++" "$$<" - @${CXX} -o $$@ $(USER_CXXFLAGS) $(USER_BINFLAGS) $$(shell util/auto-dep.py --cflags $$<) $$< $$(shell util/auto-dep.py --libs $$<) -lc ${ERRORS} - @${END} "C++" "$$<" -endef -$(foreach file,$(USER_CXXFILES),$(eval $(call user-cxx-rule,$(patsubst %.c++,hdd/bin/%,$(notdir ${file})),${file}))) +# Userspace applications -hdd/usr/lib: - @mkdir -p hdd/usr/lib +.make/%.mak: apps/%.c util/auto-dep.py | dirs + util/auto-dep.py --make $< > $@ -# Bad implementations of shared libraries -hdd/usr/lib/libc.so: ${TOOLCHAIN}/lib/libc.a | hdd/usr/lib - @${BEG} "SO" "$@" - @cp ${TOARU_SYSROOT}/usr/lib/libc.a libc.a - @# init and fini don't belong in our shared object - @ar d libc.a lib_a-init.o - @ar d libc.a lib_a-fini.o - @# Remove references to newlib's reentrant malloc - @ar d libc.a lib_a-callocr.o - @ar d libc.a lib_a-cfreer.o - @ar d libc.a lib_a-freer.o - @ar d libc.a lib_a-malignr.o - @ar d libc.a lib_a-mallinfor.o - @ar d libc.a lib_a-mallocr.o - @ar d libc.a lib_a-malloptr.o - @ar d libc.a lib_a-msizer.o - @ar d libc.a lib_a-mallstatsr.o - @ar d libc.a lib_a-pvallocr.o - @ar d libc.a lib_a-vallocr.o - @ar d libc.a lib_a-reallocr.o - @ar d libc.a lib_a-realloc.o - @ar d libc.a lib_a-calloc.o - @ar d libc.a lib_a-reallo.o - @${CC} -shared -o libc.so -Wl,--whole-archive libc.a -Wl,--no-whole-archive ${ERRORS} - @mv libc.so hdd/usr/lib/libc.so - @if [ "x$(STRIP_LIBS)" = "x1" ]; then ${STRIP} $@; fi - @rm libc.a - @${END} "SO" "$@" +ifeq (,$(findstring clean,$(MAKECMDGOALS))) +-include ${APPS_Y} +endif + +base/bin/%.sh: apps/%.sh + cp $< $@ + chmod +x $@ + +# Ramdisk + +util/devtable: ${RAMDISK_FILES} $(shell find base) util/update-devtable.py + util/update-devtable.py + +fatbase/ramdisk.img: ${RAMDISK_FILES} $(shell find base) Makefile util/devtable | dirs + genext2fs -B 4096 -d base -D util/devtable -U -b `util/calc-size.sh` -N 2048 $@ + +# CD image + +ifeq (,$(wildcard /usr/lib32/crt0-efi-ia32.o)) +$(error Missing GNU-EFI.) +endif + +EFI_XORRISO=-eltorito-alt-boot -e fat.img -no-emul-boot -isohybrid-gpt-basdat +EFI_BOOT=cdrom/fat.img +EFI_UPDATE=util/update-extents.py + +image.iso: ${EFI_BOOT} cdrom/boot.sys fatbase/netinit ${MODULES} util/update-extents.py + xorriso -as mkisofs -R -J -c bootcat \ + -b boot.sys -no-emul-boot -boot-load-size 24 \ + ${EFI_XORRISO} \ + -o image.iso cdrom + ${EFI_UPDATE} + +# Boot loader + +## +# FAT EFI payload +# This is the filesystem the EFI loaders see, so it must contain +# the kernel, modules, and ramdisk, plus anything else we want +# available to the bootloader (eg., netinit). +cdrom/fat.img: fatbase/ramdisk.img ${MODULES} fatbase/kernel fatbase/netinit fatbase/efi/boot/bootia32.efi fatbase/efi/boot/bootx64.efi util/mkdisk.sh + util/mkdisk.sh $@ fatbase + +## +# For EFI, we build two laoders: ia32 and x64 +# We build them as ELF shared objects and the use objcopy to convert +# them to PE executables / DLLs (as expected by EFI). +EFI_CFLAGS=-fno-stack-protector -fpic -DEFI_PLATFORM -ffreestanding -fshort-wchar -I /usr/include/efi -mno-red-zone +EFI_SECTIONS=-j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc + +# ia32 +boot/efi.so: boot/cstuff.c boot/*.h + $(CC) ${EFI_CFLAGS} -I /usr/include/efi/ia32 -c -o boot/efi.o $< + $(LD) boot/efi.o /usr/lib32/crt0-efi-ia32.o -nostdlib -znocombreloc -T /usr/lib32/elf_ia32_efi.lds -shared -Bsymbolic -L /usr/lib32 -lefi -lgnuefi -o boot/efi.so + +fatbase/efi/boot/bootia32.efi: boot/efi.so + objcopy ${EFI_SECTIONS} --target=efi-app-ia32 $< $@ + +# x64 +boot/efi64.so: boot/cstuff.c boot/*.h + gcc ${EFI_CFLAGS} -I /usr/include/efi/x86_64 -DEFI_FUNCTION_WRAPPER -c -o boot/efi64.o $< + $(LD) boot/efi64.o /usr/lib/crt0-efi-x86_64.o -nostdlib -znocombreloc -T /usr/lib/elf_x86_64_efi.lds -shared -Bsymbolic -L /usr/lib -lefi -lgnuefi -o boot/efi64.so + +fatbase/efi/boot/bootx64.efi: boot/efi64.so + objcopy ${EFI_SECTIONS} --target=efi-app-x86_64 $< $@ + +# BIOS loader +cdrom/boot.sys: boot/boot.o boot/cstuff.o boot/link.ld | dirs + ${KLD} -T boot/link.ld -o $@ boot/boot.o boot/cstuff.o + +boot/cstuff.o: boot/cstuff.c boot/*.h + ${KCC} -c -Os -o $@ $< + +boot/boot.o: boot/boot.s + yasm -f elf -o $@ $< + +.PHONY: clean +clean: + rm -f base/lib/*.so + rm -f base/lib/libc.a + rm -f ${APPS_X} ${APPS_SH_X} + rm -f libc/*.o libc/*/*.o + rm -f image.iso + rm -f fatbase/ramdisk.img + rm -f cdrom/boot.sys + rm -f boot/*.o + rm -f boot/*.efi + rm -f boot/*.so + rm -f cdrom/fat.img cdrom/kernel cdrom/mod/* cdrom/ramdisk.img + rm -f fatbase/kernel fatbase/efi/boot/bootia32.efi fatbase/efi/boot/bootx64.efi + rm -f cdrom/netinit fatbase/netinit + rm -f ${KERNEL_OBJS} ${KERNEL_ASMOBJS} kernel/symbols.o kernel/symbols.S + rm -f base/lib/crt*.o + rm -f ${MODULES} + rm -f ${APPS_Y} ${LIBS_Y} ${EXT_LIBS_Y} + +ifneq (,$(findstring Microsoft,$(shell uname -r))) + QEMU_ARGS=-serial mon:stdio -m 1G -rtc base=localtime -vnc :0 +else + ifeq (,${NO_KVM}) + KVM=-enable-kvm + else + KVM= + endif + QEMU_ARGS=-serial mon:stdio -m 1G -soundhw ac97,pcspk ${KVM} -rtc base=localtime +endif -hdd/lib: - @mkdir -p hdd/lib +.PHONY: run +run: image.iso + qemu-system-i386 -cdrom $< ${QEMU_ARGS} -hdd/lib/ld.so: linker/linker.c | hdd/lib - @${BEG} "CC" "$<" - @${CC} -static -Wl,-static -std=c99 -g -U__STRICT_ANSI__ -o $@ -Os -T linker/link.ld $< ${ERRORS} - @${END} "CC" "$<" +.PHONY: fast +fast: image.iso + qemu-system-i386 -cdrom $< ${QEMU_ARGS} \ + -fw_cfg name=opt/org.toaruos.bootmode,string=normal -define basic-so-wrapper -hdd/usr/lib/lib$(1).so: ${TOOLCHAIN}/lib/lib$(1).a - @${BEG} "SO" "$$@" - @${CC} -shared -Wl,-soname,lib$(1).so -o lib$(1).so -Lhdd/usr/lib -Wl,--whole-archive ${TOOLCHAIN}/lib/lib$(1).a -Wl,--no-whole-archive $2 -lgcc - @mv lib$(1).so hdd/usr/lib/lib$(1).so - @if [ "x$(STRIP_LIBS)" = "x1" ]; then ${STRIP} $$@; fi - @${END} "SO" "$$@" +.PHONY: headless +headless: image.iso + @qemu-system-i386 -cdrom $< ${QEMU_ARGS} \ + -nographic -no-reboot \ + -fw_cfg name=opt/org.toaruos.bootmode,string=headless + +.PHONY: shell +shell: image.iso + @qemu-system-i386 -cdrom $< ${QEMU_ARGS} \ + -nographic -no-reboot \ + -fw_cfg name=opt/org.toaruos.bootmode,string=headless \ + -fw_cfg name=opt/org.toaruos.forceuser,string=local + +.PHONY: efi64 +efi64: image.iso + qemu-system-x86_64 -cdrom $< ${QEMU_ARGS} \ + -bios /usr/share/qemu/OVMF.fd + + +VMNAME=ToaruOS-NIH CD + +define virtualbox-runner = +.PHONY: $1 +$1: image.iso + -VBoxManage unregistervm "$(VMNAME)" --delete + VBoxManage createvm --name "$(VMNAME)" --ostype $2 --register + VBoxManage modifyvm "$(VMNAME)" --memory 1024 --vram 32 --audio pulse --audiocontroller ac97 --bioslogodisplaytime 1 --bioslogofadeout off --bioslogofadein off --biosbootmenu disabled $3 + VBoxManage storagectl "$(VMNAME)" --add ide --name "IDE" + VBoxManage storageattach "$(VMNAME)" --storagectl "IDE" --port 0 --device 0 --medium $$(shell pwd)/image.iso --type dvddrive + VBoxManage setextradata "$(VMNAME)" GUI/DefaultCloseAction PowerOff + VBoxManage startvm "$(VMNAME)" --type separate endef -$(eval $(call basic-so-wrapper,gcc,)) -$(eval $(call basic-so-wrapper,m,)) -$(eval $(call basic-so-wrapper,z,)) -$(eval $(call basic-so-wrapper,ncurses,)) -$(eval $(call basic-so-wrapper,panel,-lncurses)) -$(eval $(call basic-so-wrapper,png15,-lz)) -$(eval $(call basic-so-wrapper,freetype,-lz)) -$(eval $(call basic-so-wrapper,pixman-1,-lm)) -$(eval $(call basic-so-wrapper,cairo,-lpixman-1 -lpng15 -lfreetype)) +$(eval $(call virtualbox-runner,virtualbox,"Other",)) +$(eval $(call virtualbox-runner,virtualbox-efi,"Other",--firmware efi)) +$(eval $(call virtualbox-runner,virtualbox-efi64,"Other_64",--firmware efi)) -# Python parts of userspace +## +# Optional Extensions +# +# These optional extension libraries require third-party components to build, +# but allow the native applications to make use of functionality such as +# TrueType fonts or PNG images. You must have the necessary elements to build +# these already installed into your sysroot for this to work. +EXT_LIBS=$(patsubst ext/%.c,%,$(wildcard ext/*.c)) +EXT_LIBS_X=$(foreach lib,$(EXT_LIBS),base/lib/libtoaru_$(lib).so) +EXT_LIBS_Y=$(foreach lib,$(EXT_LIBS),.make/$(lib).elmak) -hdd/usr/python/lib/python3.6: - @mkdir -p $@ +.make/%.elmak: ext/%.c util/auto-dep.py | dirs + util/auto-dep.py --makelib $< > $@ -hdd/bin/%.py: userspace/py/bin/%.py - @cp $< $@ +ifeq (,$(findstring clean,$(MAKECMDGOALS))) +-include ${EXT_LIBS_Y} +endif -hdd/usr/python/lib/python3.6/%.py: userspace/py/lib/%.py hdd/usr/python/lib/python3.6 - @cp $< $@ +# Freetype: Terminal text rendering backend +ext-freetype: base/lib/libtoaru_ext_freetype_fonts.so -#################### -# Hard Disk Images # -#################### - -# Hard disk image generation -GENEXT = genext2fs -DISK_SIZE = `util/disk_size.sh` - -toaruos-disk.img: ${USERSPACE} util/devtable ${PYTHON_FILES} - @${BEG} "hdd" "Generating a Hard Disk image..." - @-rm -f toaruos-disk.img - @${GENEXT} -B 4096 -d hdd -D util/devtable -U -b ${DISK_SIZE} -N 4096 toaruos-disk.img ${ERRORS} - @${END} "hdd" "Generated Hard Disk image" - @${INFO} "--" "Hard disk image is ready!" - -############# -# CD Images # -############# - -cdrom: toaruos.iso - -hdd/usr/share/terminfo/t/toaru: util/toaru.tic - @mkdir -p hdd/usr/share/terminfo/t - @cp $< $@ - -FORCE: - -_cdrom: FORCE | ${NONTEST} toaruos-kernel - @-rm -rf _cdrom - @cp -r util/cdrom _cdrom - -_cdrom/mod: ${MODULES} _cdrom - @mv hdd/mod $@ - -_cdrom/kernel: toaruos-kernel _cdrom - @cp $< $@ - -BLACKLIST = hdd/usr/share/wallpapers/grandcanyon.png -BLACKLIST += hdd/usr/share/wallpapers/paris.png -BLACKLIST += hdd/usr/share/wallpapers/southbay.png -BLACKLIST += hdd/usr/share/wallpapers/yokohama.png -BLACKLIST += hdd/usr/share/wallpapers/yosemite.png -BLACKLIST += hdd/usr/share/wallpapers/fuji.png - -_cdrom/ramdisk.img: ${NONTEST} hdd/usr/share/wallpapers util/devtable hdd/usr/share/terminfo/t/toaru _cdrom _cdrom/mod ${PYTHON_FILES} - @${BEG} "ext" "Generating a ramdisk image..." - @rm -f $(filter-out ${NONTEST},${USERSPACE}) - @rm -f ${BLACKLIST} - @${STRIP} ${NONTEST} - @${GENEXT} -B 4096 -d hdd -D util/devtable -U -b 16384 -N 2048 $@ - @${END} "ext" "Generated ramdisk image" - -_cdrom/ramdisk.img.gz: _cdrom/ramdisk.img - @gzip $< - -define fixup-cd - @git checkout hdd/usr/share/wallpapers - @mv _cdrom/mod hdd/mod - @rm -r _cdrom -endef - -toaruos.iso: _cdrom/ramdisk.img.gz _cdrom/kernel - @${BEG} "ISO" "Building a CD image" - @if [ -e /etc/lsb-release ] && grep precise /etc/lsb-release; then grub-mkrescue -o $@ _cdrom; else grub-mkrescue -d /usr/lib/grub/i386-pc --compress=xz -o $@ _cdrom 2> /dev/null; fi - @${END} "ISO" "Building a CD image" - $(call fixup-cd) - @${INFO} "--" "CD generated" - -netboot.img.gz: _cdrom/ramdisk.img.gz - cp _cdrom/ramdisk.img.gz netboot.img.gz - $(call fixup-cd) - -fix-cd: - $(call fixup-cd) - - -############## -# packages # -############## - -kernel-headers.img.gz: kernel/include - @${BEG} "pack" "$@" - @rm -rf _kernel - @mkdir _kernel - @cp -rL kernel/include/* _kernel/ - @${GENEXT} -B 4096 -d _kernel -U -b 170 $@ ${ERRORS} - @rm -r _kernel - @${END} "pack" "$@" - -############## -# ctags # -############## -tags: kernel/*/*.c kernel/*.c userspace/**/*.c modules/*.c linker/*.c - @${BEG} "ctag" "Generating CTags..." - @-ctags -R --c++-kinds=+p --fields=+iaS --extra=+q kernel userspace modules util linker ${ERRORS} - @${END} "ctag" "Generated CTags." - -############### -# clean # -############### - -clean-soft: - @${BEGRM} "RM" "Cleaning kernel objects..." - @-rm -f kernel/*.o - @-rm -f kernel/*/*.o - @-rm -f ${KERNEL_OBJS} - @${ENDRM} "RM" "Cleaned kernel objects" - -clean-user: - @${BEGRM} "RM" "Cleaning userspace products..." - @-rm -f ${USERSPACE} - @${ENDRM} "RM" "Cleaned userspace products" - -clean-mods: - @${BEGRM} "RM" "Cleaning kernel modules..." - @-rm -f hdd/mod/* - @${ENDRM} "RM" "Cleaned kernel modules" - -clean-core: - @${BEGRM} "RM" "Cleaning final output..." - @-rm -f toaruos-kernel - @${ENDRM} "RM" "Cleaned final output" - -clean-disk: - @${BEGRM} "RM" "Deleting hard disk image..." - @-rm -f toaruos-disk.img - @${ENDRM} "RM" "Deleted hard disk image" - -clean: clean-soft clean-core - @${INFO} "--" "Finished soft cleaning" - -clean-hard: clean clean-user clean-mods - @${INFO} "--" "Finished hard cleaning" - - -# vim:noexpandtab -# vim:tabstop=4 -# vim:shiftwidth=4 +# Cairo: Compositor rendering backend +ext-cairo: base/lib/libtoaru_ext_cairo_renderer.so diff --git a/README.md b/README.md index 0a080822..e621ffa8 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,166 @@ -# ToaruOS +# ToaruOS-NIH -ToaruOS is a hobby x86 operating system, built mostly from scratch. +![screenshot](https://i.imgur.com/DqXLxaT.png) -This project has been deprecated and development has moved to [ToaruOS-NIH](https://gitlab.com/toaruos/toaru-nih), with the goal of changing the "mostly" above to "completely". +ToaruOS-NIH is a distribution of ToaruOS which contains no third-party components. Its bootloader, kernel, modules, C library, and userspace applications and libraries are all written by the ToaruOS development team and direct contributors. -## Differences between ToaruOS and ToaruOS-NIH +This distribution aims to eventually replace the core of the mainline ToaruOS, with the various third-party components building against our own C library. This is a long-term project, and developing the C library to the point where it is useful for this purpose is not expected to be completed for quite some time. -This is the traditional - or "mainline" - distribution of ToaruOS. The kernel is mostly the same, though some features have been added in ToaruOS-NIH that have not been backported here. The bulk of the differences between ToaruOS "mainline" and ToaruOS-NIH are found in the userspace. +## Features -Fundamentally, mainline ToaruOS is built using Newlib. The use of a third-party, relatively complete C standard library means that mainline ToaruOS is able to support a larger collection of third-party software. ToaruOS-NIH, on the other hand, has its own C standard library. While Python 3.6 has been ported to both distributions, ToaruOS-NIH core policy of not including third-party components means that applications written in Python are not part of the "core" experience. As such, several applications which were written in Python for mainline ToaruOS are in the process of being ported to C, allowing them to remain part of the core experience of the OS. This has the added benefit of making these applications much more performant than their Python counterparts. +ToaruOS-NIH comes with a graphical desktop environment with a compositing window manager, a featureful terminal emulator, a shell, several command-line tools, a text editor (with syntax highlighting), a dynamic loader, and can host Python 3.6 (which is included in pre-built CD releases). The kernel and included drivers support ATA hard disks and CD drives, ext2 filesystems, ISO 9660 filesystems, PS/2 mice and keyboards, RS232 serial, Intel e1000, RTL8139, and AMD PCNet-series network chipsets, TCP/IPv4, several virtual graphical framebuffers (including Bochs/QEMU and VMware, and support for framebuffers initialized by EFI), advanced VM integration (including absolute pointing devices in VMware, QEMU, and VirtualBox, as well as automatic display resizing, "Seamless Desktop" and hardware cursors in VirtualBox specifically), an implementation of the `/proc` virtual filesystem, Unix-style pipes and TTYs, shared memory, in-memory read-write temporary filesystem, Intel AC'97 audio (with a mixer), and more. -The use of Newlib and allowance of third-party libraries in mainline ToaruOS also means that the core UI is built on top of libraries like Cairo, libpng, and freetype, which ToaruOS-NIH uses its own graphical libraries. +## Pre-Built Images -## Phasing out mainline ToaruOS +Releases are occasionally posted on [GitHub](https://github.com/klange/toaru-nih/releases), and nightlies are available [from toaruos.org](https://toaruos.org/nih.iso). -As ToaruOS-NIH reaches a state of feature completeness, and libraries which had previously been ported to mainline ToaruOS are also ported to ToaruOS-NIH's C library, the mainline distribution will be discontinued and ToaruOS-NIH will become the only distribution of ToaruOS. +### Running ToaruOS-NIH -There are many obstacles to tackle on the way to making ToaruOS-NIH the core ToaruOS distribution: +It is recommended that you run ToaruOS-NIH in an emulator - specifically Qemu or VirtualBox, though some testing has been done in VMware Workstation (reasonable, but missing driver support) and Bochs (not recommended). -- Implementing enough C standard library functionality to port key applications and libraries from the mainline distribution, such as GCC, Vim, libpng, freetype, and Cairo. -- Implementing plugin architectures so that applications can use either native libraries or these third-party libraries for graphics, font rendering, and so on. -- Development of a package manager using only in-house components, so that the third-party libraries and applications may be installed. +#### QEMU + +1GB of RAM and an Intel AC'97 sound chip are recommended: + +``` +qemu-system-i386 -cdrom image.iso -serial mon:stdio -m 1G -soundhw ac97,pcspk -enable-kvm -rtc base=localtime +``` + +You may also use OVMF with the appropriate QEMU system target. Our EFI loader supports both IA32 and X64 EFIs: + +``` +qemu-system-x86_64 -cdrom image.iso -serial mon:stdio -m 1G -soundhw ac97,pcspk -enable-kvm -rtc base=localtime \ + -bios /usr/share/qemu/OVMF.fd +``` + +``` +qemu-system-i386 -cdrom image.iso -serial mon:stdio -m 1G -soundhw ac97,pcspk -enable-kvm -rtc base=localtime \ + -bios /path/to/OVMFia32.fd +``` + +#### VirtualBox + +ToaruOS should function either as an "Other/Unknown" guest or an "Other/Uknown 64-bit" guest with EFI. + +All network chipset options should work except for `virtio-net` (work on virtio drivers has not yet begun). + +It is highly recommended, due to the existence of Guest Additions drivers, that you provide your VM with at least 32MB of video memory to support larger display resolutions - especially if you are using a 4K display. + +Ensure that the audio controller is set to ICH AC97 and that audio output is enabled (as it is disabled by default in some versions of VirtualBox). + +Keep the system chipset set to PIIX3 for best compatibility. 1GB of RAM is recommended. + +#### VMWare + +Support for VMWare is experimental. + +As of writing, the following configuration has been tested as functioning: + +- Create a virtual machine for a 64-bit guest. (ToaruOS-NIH is 32-bit, but this configuration selects some hardware defaults that are desirable) +- Ensure the VM has 1GB of RAM. +- It is recommended you remove the hard disk and the audio device. +- For network settings, the NAT option is recommended. + +#### Bochs + +Using Bochs to run ToaruOS is not advised; however the following configuration options are recommended if you wish to try it: + +- Attach the CD and set it as a boot device. +- Ensure that the `pcivga` device is enabled or ToaruOS will not be able to find the video card through PCI. +- Provide at least 512MB of RAM to the guest. +- If available, enable the `e1000` network device using the `slirp` backend. +- Clock settings of `sync=realtime, time0=local, rtc_sync=1` are recommended. + +## Implementation Details + +All source code for the entire operating system is included in this repository. + +### Kernel + +The NIH kernel is essentially the same as the mainline kernel, though the PCI vendor and device ID list has been replaced with our own slimmed down version. This was the only third-party element of the ToaruOS kernel. Additionally, the headers for the kernel have been relocated from their original directories to facilitate a cleaner build. The NIH kernel should be considered the latest version of the ToaruOS kernel. + +### Bootloader + +Mainline ToaruOS shipped with GRUB, which provided a multiboot-compatible ELF loader. To that end, our native bootloader also implements multiboot. However, as writing a feature-complete bootloader is not a goal of this project, the native bootloader is very limited, supporting only ATAPI CDs on systems with El Torito "no-emulation" support. It is not guaranteed to work on real hardware, but has been tested in QEMU, Bochs, VirtualBox, and VMware Player. + +### Userspace + +The userspace includes a work-in-progress C standard library, the ToaruOS native libraries, the compositor (using only in-house graphics routines), and various other first-party utilities and applications. + +#### Notable Components + +- **Yutani** (window compositor), [apps/compositor.c](apps/compositor.c), manages window buffers, layout, and input routing. +- **Bim** (text editor), [apps/bim.c](apps/bim.c), is a vim-inspired editor with syntax highlighting. +- **Terminal**, [apps/terminal.c](apps/terminal.c), xterm-esque terminal emulator with 256 and 24-bit color support. +- **ld.so** (dynamic linker/loader), [linker/linker.c](linker/linker.c), loads dynamically-linked ELF binaries. +- **Esh** (shell), [apps/sh.c](apps/sh.c), supports pipes, redirections, variables, and more. + +## Building + +First, ensure you have the necessary build tools, which are mostly the same as mainline ToaruOS: `yasm`, `xorriso`, `genext2fs` (with Debian patches), `python`, `mtools` (for building FAT EFI payloads) and `gnu-efi` to build the EFI bootloader (I'll explore implementing necessary headers and functionality myself in the future, but for now just pull in gnu-efi and make my life easier). + +Run `make` and you will be prompted to build a toolchain. Reply `y` and allow the toolchain to build. + +### Third-Party Ports + +#### Python + +There are instructions on building Python 3.6 available from [the gitlab wiki](https://gitlab.com/toaruos/toaru-nih/wikis/Installing-Python). + +#### Freetype + +Currently only the Terminal supports using Freetype as a text rendering backend, but this will be expanded in the future. + +Freetype should mostly build as-is, though libtool needs to be taught how to build a shared object for ToaruOS called `libfreetype.so` - this is left as an exercise for the reader until I've had time to formalize the process. + +Once freetype is built and installed to `base/usr`, `make ext-freetype` will build the extension library. Place the required fonts, which you can get from maineline ToaruOS, in `base/usr/share/fonts`. + +With fonts available, the build scripts will build larger ramdisks to accomodate the additional files. The font server will automatically run on startup if a GUI boot target is selected, and the Terminal will automatically use the Freetype backend if it loads. + +#### Cairo / Pixman + +The compositor can use Cairo for rendering, which improves performance over the naïve in-house SSE-accelerated blitter. + +## Backwards Compatibility Notes + +No ABI or API compatibility is guaranteed through the development of ToaruOS-NIH. Until a larger corpus of third-party software is ported to our new C library, APIs may change to improve or simplify library use, or to fix bugs. Even kernel ABI compatibility is not guaranteed as system calls are improved or made more compliant with expectations of POSIX or the C standard. + +## Rationale + +ToaruOS's kernel is entirely in-house. Its userspace, however, is built on several third-party libraries and tools, such as the Newlib C library, Freetype, Cairo, libpng, and most notably Python. While the decision to build ToaruOS on these technologies is not at all considered a mistake, the possibility remains to build a userspace entirely from scratch. + +## Goals + +Many of our initial goals have been met, including sufficient C library support to port Python 3.6. + +Our current unmet goals include: + +- Enough C library support to port binutils/gcc (needs enough C to get libstdc++ working) +- Plugin systems for the compositor and general graphics APIs to support third-party libraries in the future (including support for Cairo as a backend for the compositor, PNG support in the graphics sprite API, Truetype rendering support through FreeType in the text rendering engine). +- Porting the complete native desktop experience from ToaruOS mainline (which mostly means porting Python prototype applications and libraries to C). + +## Project Layout + +- **apps** - Userspace applications, all first-party. +- **base** - Ramdisk root filesystem staging directory. Includes C headers in `base/usr/include`, as well as graphical resources for the compositor and window decorator. +- **boot** - Bootloader, including BIOS and EFI IA32 and X64 support. +- **cdrom** - Staging area for ISO9660 CD image, containing mostly blank shadow files for the FAT image. +- **ext** - Optional runtime-loaded bindings for third-party libraries. +- **fatbase** - Staging area for FAT image used by EFI. +- **kernel** - The ToaruOS kernel. +- **lib** - Userspace libraries. +- **libc** - C standard library implementation. +- **linker** - Userspace dynamic linker/loader, implements shared library support. +- **modules** - Kernel modules/drivers. +- **util** - Utility scripts, staging directory for the toolchain (binutils/gcc). +- **.make** - Generated Makefiles. + +## Mirrors + +ToaruOS-NIH is regularly mirrored to multiple Git hosting sites. The recommended source is [Gitlab](https://gitlab.com/toaruos/toaru-nih). + +- Gitlab: [toaruos/toaru-nih](https://gitlab.com/toaruos/toaru-nih) +- GitHub: [klange/toaru-nih](https://github.com/klange/toaru-nih) +- Bitbucket: [klange/toaru-nih](https://bitbucket.org/klange/toaru-nih) +- ToaruOS.org: [klange/toaru-nih](https://git.toaruos.org/klange/toaru-nih) diff --git a/README_OLD.md b/README_OLD.md deleted file mode 100644 index 0908d442..00000000 --- a/README_OLD.md +++ /dev/null @@ -1,65 +0,0 @@ -![](https://i.imgur.com/QGVoRJD.png) -![](https://i.imgur.com/MlAxGpj.png) -![](https://i.imgur.com/OpMGfHP.png) - -# ToaruOS (とあるOS) # - -とあるOS (ToaruOS) is a hobby operating system built mostly from scratch, including both a kernel and userspace. - -This repository contains the kernel, modules, and core userspace applications and libraries. Some third-party libraries and utilities are required to build a working system. - -## Build Instructions ## - -If you just want to build the kernel and userspace and get a working CD image, you can use Docker: - - docker pull toaruos/build-tools:test - docker run -v `pwd`:/opt/tree -w /opt/tree -t toaruos/build-tools:test util/build-travis.sh - -To build a full toolchain locally, set up [a supported environment](https://github.com/klange/toaruos/wiki/Testing-and-Building#requirements) and run: - - make toolchain - -You may be prompted to enter your password for `sudo` to install required packages. The toolchain build scripts will then build several dependencies for building ToaruOS such as a GCC cross compiler and a few libraries used by the userspace. This may take around thirty minutes to an hour to complete, depending on your hardware. Once it is done, verify there were no errors and then follow the instructions provided to continue with the build. - -If you experience issues, please join our [IRC channel](#irc) for help. - -## History ## - -ToaruOS started as a side project at the University of Illinois at Urbana-Champaign. For several months in late 2011 and early 2012, the University's [SIGOps](http://www.acm.uiuc.edu/sigops/) chapter managed development efforts focused on building the original compositing GUI. Since then, the project has mostly been a one-man effort with a handful of third party contributions. - -## Kernel ## - -The Toaru kernel provides a basic Unix-like environment. The kernel uses a hybrid modular architecture, with loadable modules providing most device driver support. The core kernel includes support for Unix pipes and TTYs, a virtual file system, multitasking, ELF binary support, and various core platform features on x86 systems. - -Modules provide support for disk drives, ext2 filesystems, serial, keyboards and mice, a `/proc` filesystem similar to the one found in Linux, as well as an expanding collection of other device drivers. - -## Userspace ## - -ToaruOS's userspace is focused on a rich graphical environment, backed by an in-house compositing window manager. ToaruOS's terminal emulator supports xterm-compatible 256-color modes, as well as Konsole 24-bit color modes and anti-aliased text with basic Unicode support. Program binaries are dynamically linked. Several graphical demos are provided, alongside a number of command-line applications. A port of SDL targetting the native graphical environment is also available. - -### Third-Party Software ### - -The userspace depends on a number of third-party libraries which are outside of the development scope of the project. Additionally, several third-party applications and libraries have been integrated into ToaruOS's core userspace, or otherwise ported to ToaruOS. - -License for the included third-party tools and libraries can be found [here](hdd/usr/share/help/licenses). - -## Community ## - -### Git ### - -ToaruOS is hosted across multiple social git hosting sites: - -- [Gitlab](https://gitlab.com/toaruos/toaruos) -- [Github](https://github.com/klange/toaruos) -- [Bitbucket](https://bitbucket.org/klange/toaruos) -- [git.toaruos.org](https://git.toaruos.org/klange/toaruos) - -### Wiki ### - -For additional screenshots, see [Screenshots](https://github.com/klange/toaruos/wiki/Screenshots). - -For instructions on building, see [Testing and Building](https://github.com/klange/toaruos/wiki/Testing-and-Building). - -### IRC ### - -For help building the kernel and userspace, join us in `#toaruos` on Freenode (`irc.freenode.net`). diff --git a/apps/about.c b/apps/about.c new file mode 100644 index 00000000..606bea51 --- /dev/null +++ b/apps/about.c @@ -0,0 +1,223 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * about - Show an "About " dialog. + * + * By default, shows "About ToaruOS", suitable for use as an application + * menu entry. Optionally, takes arguments specifying another application + * to describe, suitable for the "Help > About" menu bar entry. + */ +#include +#include +#include +#include +#include + +#include + +static yutani_t * yctx; +static yutani_window_t * window = NULL; +static gfx_context_t * ctx = NULL; +static sprite_t logo; + +static int32_t width = 350; +static int32_t height = 250; +static char * version_str; + +static char * icon_path; +static char * title_str; +static char * version_str; +static char * copyright_str[20] = {NULL}; + +static int center_x(int x) { + return (width - x) / 2; +} + +static void draw_string(int y, const char * string, int font, uint32_t color) { + + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); + + draw_sdf_string(ctx, bounds.left_width + center_x(draw_sdf_string_width(string, 16, font)), bounds.top_height + 10 + logo.height + 10 + y, string, 16, color, font); +} + +static void redraw(void) { + + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); + + draw_fill(ctx, rgb(204,204,204)); + draw_sprite(ctx, &logo, bounds.left_width + center_x(logo.width), bounds.top_height + 10); + + draw_string(0, version_str, SDF_FONT_BOLD, rgb(0,0,0)); + + int offset = 20; + + for (char ** copy_str = copyright_str; *copy_str; ++copy_str) { + if (**copy_str == '-') { + offset += 10; + } else if (**copy_str == '%') { + draw_string(offset, *copy_str+1, SDF_FONT_THIN, rgb(0,0,255)); + offset += 20; + } else { + draw_string(offset, *copy_str, SDF_FONT_THIN, rgb(0,0,0)); + offset += 20; + } + } + + window->decorator_flags |= DECOR_FLAG_NO_MAXIMIZE; + render_decorations(window, ctx, title_str); + + flip(ctx); + yutani_flip(yctx, window); +} + +static void init_default(void) { + title_str = "About ToaruOS-NIH"; + icon_path = "/usr/share/logo_login.bmp"; + + { + version_str = malloc(100); + struct utsname u; + uname(&u); + char * tmp = strstr(u.release, "-"); + if (tmp) { + *tmp = '\0'; + } + sprintf(version_str, "ToaruOS-NIH %s", u.release); + } + + copyright_str[0] = "(C) 2011-2018 K. Lange, et al."; + copyright_str[1] = "-"; + copyright_str[2] = "ToaruOS is free software released under the"; + copyright_str[3] = "NCSA/University of Illinois license."; + copyright_str[4] = "-"; + copyright_str[5] = "%https://toaruos.org"; + copyright_str[6] = "%https://gitlab.com/toaruos"; + +} + +int main(int argc, char * argv[]) { + int req_center_x, req_center_y; + yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } + init_decorations(); + + struct decor_bounds bounds; + decor_get_bounds(NULL, &bounds); + + window = yutani_window_create(yctx, width + bounds.width, height + bounds.height); + req_center_x = yctx->display_width / 2; + req_center_y = yctx->display_height / 2; + + if (argc < 2) { + init_default(); + } else if (argc < 5) { + fprintf(stderr, "Invalid arguments.\n"); + return 1; + } else { + title_str = argv[1]; + icon_path = argv[2]; + version_str = argv[3]; + + int i = 0; + char * me = argv[4], * end; + do { + copyright_str[i] = me; + i++; + end = strchr(me,'\n'); + if (end) { + *end = '\0'; + me = end+1; + } + } while (end); + + if (argc > 6) { + req_center_x = atoi(argv[5]); + req_center_y = atoi(argv[6]); + } + } + + yutani_window_move(yctx, window, req_center_x - window->width / 2, req_center_y - window->height / 2); + + yutani_window_advertise_icon(yctx, window, title_str, "star"); + + ctx = init_graphics_yutani_double_buffer(window); + load_sprite(&logo, icon_path); + logo.alpha = ALPHA_EMBEDDED; + + redraw(); + + int playing = 1; + while (playing) { + yutani_msg_t * m = yutani_poll(yctx); + while (m) { + if (menu_process_event(yctx, m)) { + redraw(); + } + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { + playing = 0; + } + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * wf = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + if (win) { + win->focused = wf->focused; + redraw(); + } + } + break; +#if 0 + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + resize_finish(wr->width, wr->height); + } + break; +#endif + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + int result = decor_handle_event(yctx, m); + switch (result) { + case DECOR_CLOSE: + playing = 0; + break; + case DECOR_RIGHT: + /* right click in decoration, show appropriate menu */ + decor_show_default_menu(window, window->x + me->new_x, window->y + me->new_y); + break; + default: + /* Other actions */ + break; + } + } + break; + case YUTANI_MSG_WINDOW_CLOSE: + case YUTANI_MSG_SESSION_END: + playing = 0; + break; + default: + break; + } + free(m); + m = yutani_poll_async(yctx); + } + } + + yutani_close(yctx, window); + + return 0; +} diff --git a/apps/background.c b/apps/background.c new file mode 100644 index 00000000..af37da12 --- /dev/null +++ b/apps/background.c @@ -0,0 +1,173 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * background - Draw a desktop wallpaper. + * + * TODO: This is a very minimal wallpaper renderer. + * ToaruOS-mainline, before it went all Python, + * included a more complete wallpaper application, + * which supported icons and config files. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static yutani_t * yctx; +static yutani_window_t * wallpaper_window; +static gfx_context_t * wallpaper_ctx; +static sprite_t * wallpaper; +static struct MenuList * _rc_menu = NULL; + +static void draw_background(int width, int height) { + + float x = (float)wallpaper_window->width / (float)wallpaper->width; + float y = (float)wallpaper_window->height / (float)wallpaper->height; + + int nh = (int)(x * (float)wallpaper->height); + int nw = (int)(y * (float)wallpaper->width); + + if (nw == wallpaper->width && nh == wallpaper->height) { + // special case + draw_sprite(wallpaper_ctx, wallpaper, 0, 0); + } else if (nw >= width) { + draw_sprite_scaled(wallpaper_ctx, wallpaper, ((int)wallpaper_window->width - nw) / 2, 0, nw+2, wallpaper_window->height); + } else { + draw_sprite_scaled(wallpaper_ctx, wallpaper, 0, ((int)wallpaper_window->height - nh) / 2, wallpaper_window->width+2, nh); + } +} + +static void show_right_click_menu(int x, int y) { + if (_rc_menu->window) return; /* Already shown */ + + menu_show(_rc_menu, yctx); + if (x + _rc_menu->window->width > yctx->display_width) { + yutani_window_move(yctx, _rc_menu->window, x - _rc_menu->window->width, y); + } else { + yutani_window_move(yctx, _rc_menu->window, x, y); + } +} + +static void resize_finish_wallpaper(int width, int height) { + yutani_window_resize_accept(yctx, wallpaper_window, width, height); + reinit_graphics_yutani(wallpaper_ctx, wallpaper_window); + draw_background(width, height); + yutani_window_resize_done(yctx, wallpaper_window); + yutani_flip(yctx, wallpaper_window); +} + +static void launch_application(char * app) { + if (!fork()) { + printf("Starting %s\n", app); + char * args[] = {"/bin/sh", "-c", app, NULL}; + execvp(args[0], args); + exit(1); + } +} + +static void launch_application_menu(struct MenuEntry * self) { + struct MenuEntry_Normal * _self = (void *)self; + launch_application((char *)_self->action); +} + +static void check_click(struct yutani_msg_window_mouse_event * evt) { + if (evt->wid == wallpaper_window->wid) { + if (evt->buttons & YUTANI_MOUSE_BUTTON_RIGHT) { + show_right_click_menu(evt->new_x, evt->new_y); + } + } +} + +static void sig_usr2(int sig) { + yutani_set_stack(yctx, wallpaper_window, YUTANI_ZORDER_BOTTOM); + yutani_flip(yctx, wallpaper_window); +} + +int main (int argc, char ** argv) { + + if (argc < 2 || strcmp(argv[1],"--really")) { + fprintf(stderr, + "%s: Desktop environment wallpaper\n" + "\n" + " Renders the desktop wallpaper. You probably don't want\n" + " to be running this directly - it is started by the\n" + " session manager along with the panel.\n", argv[0]); + return 1; + } + + signal(SIGUSR2, sig_usr2); + + wallpaper = malloc(sizeof(sprite_t)); + load_sprite(wallpaper, "/usr/share/wallpaper.bmp"); + wallpaper->alpha = 0; + + yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } + + _rc_menu = menu_create(); + menu_insert(_rc_menu, menu_create_normal("utilities-terminal", "terminal", "Open Terminal", launch_application_menu)); + + /* wallpaper */ + wallpaper_window = yutani_window_create(yctx, yctx->display_width, yctx->display_height); + yutani_window_move(yctx, wallpaper_window, 0, 0); + yutani_set_stack(yctx, wallpaper_window, YUTANI_ZORDER_BOTTOM); + + wallpaper_ctx = init_graphics_yutani(wallpaper_window); + draw_background(yctx->display_width, yctx->display_height); + yutani_flip(yctx, wallpaper_window); + + int should_exit = 0; + + while (!should_exit) { + int fds[1] = {fileno(yctx->sock)}; + int index = fswait2(1,fds,200); + if (index == 0) { + yutani_msg_t * m = yutani_poll(yctx); + while (m) { + menu_process_event(yctx, m); + switch (m->type) { + case YUTANI_MSG_WELCOME: + yutani_window_resize_offer(yctx, wallpaper_window, yctx->display_width, yctx->display_height); + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + if (wr->wid == wallpaper_window->wid) { + resize_finish_wallpaper(wr->width, wr->height); + } + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + check_click((struct yutani_msg_window_mouse_event *)m->data); + break; + case YUTANI_MSG_SESSION_END: + should_exit = 1; + break; + default: + break; + } + free(m); + m = yutani_poll_async(yctx); + } + } else { + /* Perform timer events here. Animations? */ + waitpid(-1, NULL, WNOHANG); + } + } + + yutani_close(yctx, wallpaper_window); + + return 0; +} + diff --git a/userspace/extra/beep.c b/apps/beep.c similarity index 85% rename from userspace/extra/beep.c rename to apps/beep.c index c7d0d154..51b69ab7 100644 --- a/userspace/extra/beep.c +++ b/apps/beep.c @@ -1,6 +1,7 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014 K. Lange */ #include #include diff --git a/apps/bim.c b/apps/bim.c new file mode 100644 index 00000000..2ae80a72 --- /dev/null +++ b/apps/bim.c @@ -0,0 +1,5999 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * Copyright (C) 2012-2018 K. Lange + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * bim - Text editor + * + * Bim is inspired by vim, and its name is short for "Bad IMitation". + * + * Bim supports syntax highlighting, extensive editing, line selection + * and copy-paste, undo/redo stack, forward and backward search, and can + * be built for ToaruOS, Sortix, Linux, macOS, and BSDs. + */ +#define _XOPEN_SOURCE +#define _DEFAULT_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BIM_VERSION "1.0.2" +#define BIM_COPYRIGHT "Copyright 2013-2018 K. Lange <\033[3mklange@toaruos.org\033[23m>" + +#define BLOCK_SIZE 4096 +#define ENTER_KEY '\n' +#define BACKSPACE_KEY 0x08 +#define DELETE_KEY 0x7F + +/** + * Theming data + * + * This is all overridden by a load_colorscheme_ method. + * The default is to load_colorscheme_ansi, but config + * files can be used to set a different default theme. + */ +const char * COLOR_FG = "@17"; +const char * COLOR_BG = "@0"; +const char * COLOR_ALT_FG = "@17"; +const char * COLOR_ALT_BG = "@0"; +const char * COLOR_NUMBER_FG = "@17"; +const char * COLOR_NUMBER_BG = "@0"; +const char * COLOR_STATUS_FG = "@17"; +const char * COLOR_STATUS_BG = "@0"; +const char * COLOR_TABBAR_BG = "@0"; +const char * COLOR_TAB_BG = "@0"; +const char * COLOR_ERROR_FG = "@17"; +const char * COLOR_ERROR_BG = "@0"; +const char * COLOR_SEARCH_FG = "@17"; +const char * COLOR_SEARCH_BG = "@0"; +const char * COLOR_KEYWORD = "@17"; +const char * COLOR_STRING = "@17"; +const char * COLOR_COMMENT = "@17"; +const char * COLOR_TYPE = "@17"; +const char * COLOR_PRAGMA = "@17"; +const char * COLOR_NUMERAL = "@17"; +const char * COLOR_SELECTFG = "@0"; +const char * COLOR_SELECTBG = "@17"; +const char * COLOR_RED = "@1"; +const char * COLOR_GREEN = "@2"; +const char * current_theme = "none"; + +/** + * Syntax highlighting flags. + */ +#define FLAG_NONE 0 +#define FLAG_KEYWORD 1 +#define FLAG_STRING 2 +#define FLAG_COMMENT 3 +#define FLAG_TYPE 4 +#define FLAG_PRAGMA 5 +#define FLAG_NUMERAL 6 +#define FLAG_SELECT 7 +#define FLAG_STRING2 8 +#define FLAG_DIFFPLUS 9 +#define FLAG_DIFFMINUS 10 + +#define FLAG_CONTINUES (1 << 6) + +/** + * Convert syntax hilighting flag to color code + */ +const char * flag_to_color(int _flag) { + int flag = _flag & 0x3F; + switch (flag) { + case FLAG_KEYWORD: + return COLOR_KEYWORD; + case FLAG_STRING: + case FLAG_STRING2: /* allows python to differentiate " and ' */ + return COLOR_STRING; + case FLAG_COMMENT: + return COLOR_COMMENT; + case FLAG_TYPE: + return COLOR_TYPE; + case FLAG_NUMERAL: + return COLOR_NUMERAL; + case FLAG_PRAGMA: + return COLOR_PRAGMA; + case FLAG_DIFFPLUS: + return COLOR_GREEN; + case FLAG_DIFFMINUS: + return COLOR_RED; + case FLAG_SELECT: + return COLOR_FG; + default: + return COLOR_FG; + } +} + +/** + * Line buffer definitions + * + * Lines are essentially resizable vectors of char_t structs, + * which represent single codepoints in the file. + */ +typedef struct { + uint32_t display_width:4; + uint32_t flags:7; + uint32_t codepoint:21; +} __attribute__((packed)) char_t; + +/** + * Lines have available and actual lengths, describing + * how much space was allocated vs. how much is being + * used at the moment. + */ +typedef struct { + int available; + int actual; + int istate; + char_t text[0]; +} line_t; + +/** + * Global configuration state + */ +struct { + /* Terminal size */ + int term_width, term_height; + int bottom_size; + + /* Command-line parameters */ + int hilight_on_open; + int initial_file_is_read_only; + + line_t ** yanks; + size_t yank_count; + int yank_is_full_lines; + + int tty_in; + + const char * bimrc_path; + + int can_scroll; + int can_hideshow; + int can_altscreen; + int can_mouse; + int can_unicode; + int can_bright; + int can_title; + int can_bce; + int history_enabled; + + int cursor_padding; +} global_config = { + 0, /* term_width */ + 0, /* term_height */ + 2, /* bottom_size */ + 1, /* hilight_on_open */ + 0, /* initial_file_is_read_only */ + NULL, /* yanks */ + 0, /* yank_count */ + 0, + STDIN_FILENO, /* tty_in */ + "~/.bimrc", /* bimrc_path */ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 4, /* cursor padding */ +}; + +void redraw_line(int j, int x); + +/** + * Special implementation of getch with a timeout + */ +int _bim_unget = -1; + +void bim_unget(int c) { + _bim_unget = c; +} + +#define bim_getch() bim_getch_timeout(200) +int bim_getch_timeout(int timeout) { + if (_bim_unget != -1) { + int out = _bim_unget; + _bim_unget = -1; + return out; + } + struct pollfd fds[1]; + fds[0].fd = global_config.tty_in; + fds[0].events = POLLIN; + int ret = poll(fds,1,timeout); + if (ret > 0 && fds[0].revents & POLLIN) { + unsigned char buf[1]; + read(global_config.tty_in, buf, 1); + return buf[0]; + } else { + return -1; + } +} + +#define HISTORY_SENTINEL 0 +#define HISTORY_INSERT 1 +#define HISTORY_DELETE 2 +#define HISTORY_REPLACE 3 +#define HISTORY_REMOVE_LINE 4 +#define HISTORY_ADD_LINE 5 +#define HISTORY_REPLACE_LINE 6 +#define HISTORY_MERGE_LINES 7 +#define HISTORY_SPLIT_LINE 8 + +#define HISTORY_BREAK 10 + +typedef struct history { + struct history * previous; + struct history * next; + int type; + union { + struct { + int lineno; + int offset; + int codepoint; + int old_codepoint; + } insert_delete_replace; + + struct { + int lineno; + line_t * contents; + line_t * old_contents; + } remove_replace_line; + + struct { + int lineno; + int split; + } add_merge_split_lines; + }; +} history_t; + +/** + * Buffer data + * + * A buffer describes a file, and stores + * its name as well as the editor state + * (cursor offsets, etc.) and the actual + * line buffers. + */ +typedef struct _env { + short loading:1; + short tabs:1; + short modified:1; + short readonly:1; + short indent:1; + + short mode; + short tabstop; + + char * file_name; + int offset; + int coffset; + int line_no; + int line_count; + int line_avail; + int col_no; + uint32_t * search; + struct syntax_definition * syntax; + line_t ** lines; + + history_t * history; + history_t * last_save_history; +} buffer_t; + +/** + * Pointer to current active buffer + */ +buffer_t * env; + +/** + * Editor modes (like in vim) + */ +#define MODE_NORMAL 0 +#define MODE_INSERT 1 +#define MODE_LINE_SELECTION 2 +#define MODE_REPLACE 3 +#define MODE_CHAR_SELECTION 4 + +/** + * Available buffers + */ +int buffers_len; +int buffers_avail; +buffer_t ** buffers; + +/** + * Create a new buffer + */ +buffer_t * buffer_new(void) { + if (buffers_len == buffers_avail) { + /* If we are out of buffer space, expand the buffers vector */ + buffers_avail *= 2; + buffers = realloc(buffers, sizeof(buffer_t *) * buffers_avail); + } + + /* Allocate a new buffer */ + buffers[buffers_len] = malloc(sizeof(buffer_t)); + memset(buffers[buffers_len], 0x00, sizeof(buffer_t)); + buffers_len++; + + return buffers[buffers_len-1]; +} + +/** + * Close a buffer + */ +buffer_t * buffer_close(buffer_t * buf) { + int i; + + /* Locate the buffer in the buffer pointer vector */ + for (i = 0; i < buffers_len; i++) { + if (buf == buffers[i]) + break; + } + + /* Invalid buffer? */ + if (i == buffers_len) { + return env; /* wtf */ + } + + /* Remove the buffer from the vector, moving others up */ + if (i != buffers_len - 1) { + memmove(&buffers[i], &buffers[i+1], sizeof(*buffers) * (buffers_len - i)); + } + + /* There is one less buffer */ + buffers_len--; + if (!buffers_len) { + /* There are no more buffers. */ + return NULL; + } + + /* If this was the last buffer, return the previous last buffer */ + if (i == buffers_len) { + return buffers[buffers_len-1]; + } + + /* Otherwise return the new last buffer */ + return buffers[i]; +} + +/** + * Themes + */ + +/* Based on the wombat256 theme for vim */ +void load_colorscheme_wombat(void) { + COLOR_FG = "5;230"; + COLOR_BG = "5;235"; + COLOR_ALT_FG = "5;244"; + COLOR_ALT_BG = "5;236"; + COLOR_NUMBER_BG = "5;232"; + COLOR_NUMBER_FG = "5;101"; + COLOR_STATUS_FG = "5;230"; + COLOR_STATUS_BG = "5;238"; + COLOR_TABBAR_BG = "5;230"; + COLOR_TAB_BG = "5;248"; + COLOR_KEYWORD = "5;117"; + COLOR_STRING = "5;113"; + COLOR_COMMENT = "5;102;3"; + COLOR_TYPE = "5;185"; + COLOR_PRAGMA = "5;173"; + COLOR_NUMERAL = COLOR_PRAGMA; + + COLOR_ERROR_FG = "5;15"; + COLOR_ERROR_BG = "5;196"; + COLOR_SEARCH_FG = "5;234"; + COLOR_SEARCH_BG = "5;226"; + + COLOR_SELECTFG = "5;235"; + COLOR_SELECTBG = "5;230"; + + COLOR_RED = "@1"; + COLOR_GREEN = "@2"; + + current_theme = "wombat"; +} + +/* "City Lights" based on citylights.xyz */ +void load_colorscheme_citylights(void) { + COLOR_FG = "2;151;178;198"; + COLOR_BG = "2;29;37;44"; + COLOR_ALT_FG = "2;45;55;65"; + COLOR_ALT_BG = "2;33;42;50"; + COLOR_NUMBER_FG = "2;71;89;103"; + COLOR_NUMBER_BG = "2;37;47;56"; + COLOR_STATUS_FG = "2;116;144;166"; + COLOR_STATUS_BG = "2;53;67;78"; + COLOR_TABBAR_BG = "2;37;47;56"; + COLOR_TAB_BG = "2;29;37;44"; + COLOR_KEYWORD = "2;94;196;255"; + COLOR_STRING = "2;83;154;252"; + COLOR_COMMENT = "2;107;133;153;3"; + COLOR_TYPE = "2;139;212;156"; + COLOR_PRAGMA = "2;0;139;148"; + COLOR_NUMERAL = "2;207;118;132"; + + COLOR_ERROR_FG = "5;15"; + COLOR_ERROR_BG = "5;196"; + COLOR_SEARCH_FG = "5;234"; + COLOR_SEARCH_BG = "5;226"; + + COLOR_SELECTFG = "2;29;37;44"; + COLOR_SELECTBG = "2;151;178;198"; + + COLOR_RED = "2;222;53;53"; + COLOR_GREEN = "2;55;167;0"; + + current_theme = "citylights"; +} + +/* Solarized Dark, popular theme */ +void load_colorscheme_solarized_dark(void) { + COLOR_FG = "2;147;161;161"; + COLOR_BG = "2;0;43;54"; + COLOR_ALT_FG = "2;147;161;161"; + COLOR_ALT_BG = "2;7;54;66"; + COLOR_NUMBER_FG = "2;131;148;149"; + COLOR_NUMBER_BG = "2;7;54;66"; + COLOR_STATUS_FG = "2;131;148;150"; + COLOR_STATUS_BG = "2;7;54;66"; + COLOR_TABBAR_BG = "2;7;54;66"; + COLOR_TAB_BG = "2;131;148;150"; + COLOR_KEYWORD = "2;133;153;0"; + COLOR_STRING = "2;42;161;152"; + COLOR_COMMENT = "2;101;123;131"; + COLOR_TYPE = "2;181;137;0"; + COLOR_PRAGMA = "2;203;75;22"; + COLOR_NUMERAL = "2;220;50;47"; + + COLOR_ERROR_FG = "5;15"; + COLOR_ERROR_BG = "5;196"; + COLOR_SEARCH_FG = "5;234"; + COLOR_SEARCH_BG = "5;226"; + + COLOR_SELECTFG = "2;0;43;54"; + COLOR_SELECTBG = "2;147;161;161"; + + COLOR_RED = "2;222;53;53"; + COLOR_GREEN = "2;55;167;0"; + + current_theme = "solarized-dark"; +} + +/* Custom theme */ +void load_colorscheme_sunsmoke(void) { + COLOR_FG = "2;230;230;230"; + COLOR_BG = "2;31;31;31"; + COLOR_ALT_FG = "2;122;122;122"; + COLOR_ALT_BG = "2;46;43;46"; + COLOR_NUMBER_FG = "2;150;139;57"; + COLOR_NUMBER_BG = "2;0;0;0"; + COLOR_STATUS_FG = "2;230;230;230"; + COLOR_STATUS_BG = "2;71;64;58"; + COLOR_TABBAR_BG = "2;71;64;58"; + COLOR_TAB_BG = "2;71;64;58"; + COLOR_KEYWORD = "2;51;162;230"; + COLOR_STRING = "2;72;176;72"; + COLOR_COMMENT = "2;158;153;129;3"; + COLOR_TYPE = "2;230;206;110"; + COLOR_PRAGMA = "2;194;70;54"; + COLOR_NUMERAL = "2;230;43;127"; + + COLOR_ERROR_FG = "5;15"; + COLOR_ERROR_BG = "5;196"; + COLOR_SEARCH_FG = "5;234"; + COLOR_SEARCH_BG = "5;226"; + + COLOR_SELECTFG = "2;0;43;54"; + COLOR_SELECTBG = "2;147;161;161"; + + COLOR_RED = "2;222;53;53"; + COLOR_GREEN = "2;55;167;0"; + + current_theme = "sunsmoke"; +} + +/* 16-color theme, default */ +void load_colorscheme_ansi(void) { + COLOR_FG = global_config.can_bright ? "@17" : "@7"; + COLOR_BG = global_config.can_bright ? "@9" : "@0"; + COLOR_ALT_FG = global_config.can_bright ? "@10" : "@5"; + COLOR_ALT_BG = "@9"; + COLOR_NUMBER_FG = "@3"; + COLOR_NUMBER_BG = "@9"; + COLOR_STATUS_FG = global_config.can_bright ? "@17" : "@7"; + COLOR_STATUS_BG = "@4"; + COLOR_TABBAR_BG = "@4"; + COLOR_TAB_BG = "@4"; + COLOR_KEYWORD = global_config.can_bright ? "@14" : "@4"; + COLOR_STRING = "@2"; + COLOR_COMMENT = global_config.can_bright ? "@10" : "@5"; + COLOR_TYPE = "@3"; + COLOR_PRAGMA = "@1"; + COLOR_NUMERAL = "@1"; + + COLOR_ERROR_FG = global_config.can_bright ? "@17" : "@7"; + COLOR_ERROR_BG = "@1"; + COLOR_SEARCH_FG = "@0"; + COLOR_SEARCH_BG = global_config.can_bright ? "@13" : "@3"; + + COLOR_SELECTBG = global_config.can_bright ? "@17" : "@7"; + COLOR_SELECTFG = "@0"; + + COLOR_RED = "@1"; + COLOR_GREEN = "@2"; + + current_theme = "ansi"; +} + +struct theme_def { + const char * name; + void (*load)(void); +} themes[] = { + {"wombat", load_colorscheme_wombat}, + {"citylights", load_colorscheme_citylights}, + {"solarized-dark", load_colorscheme_solarized_dark}, + {"ansi", load_colorscheme_ansi}, + {"sunsmoke", load_colorscheme_sunsmoke}, + {NULL, NULL} +}; + + +/** + * Syntax definition for C + */ +int syn_c_iskeywordchar(int c) { + if (isalnum(c)) return 1; + if (c == '_') return 1; + return 0; +} + +static char * syn_c_keywords[] = { + "while","if","for","continue","return","break","switch","case","sizeof", + "struct","union","typedef","do","default","else","goto", + "alignas","alignof","offsetof", + /* C++ stuff */ + "public","private","class","using","namespace", + NULL +}; + +static char * syn_c_types[] = { + "static","int","char","short","float","double","void","unsigned","volatile","const", + "register","long","inline","restrict","enum","auto","extern","bool","complex", + "uint8_t","uint16_t","uint32_t","uint64_t", + "int8_t","int16_t","int32_t","int64_t","FILE", + NULL +}; + +static char * syn_c_special[] = { + "NULL", + "stdin","stdout","stderr", + "STDIN_FILENO","STDOUT_FILENO","STDERR_FILENO", + NULL +}; + +static int syn_c_extended(line_t * line, int i, int c, int last, int * out_left) { + if (i == 0 && c == '#') { + *out_left = line->actual+1; + if (line->text[line->actual-1].codepoint == '\\') { + return FLAG_PRAGMA | FLAG_CONTINUES; + } + return FLAG_PRAGMA; + } + + if ((!last || !syn_c_iskeywordchar(last)) && syn_c_iskeywordchar(c)) { + int j = i; + for (int s = 0; syn_c_special[s]; ++s) { + int d = 0; + while (j + d < line->actual && line->text[j+d].codepoint == syn_c_special[s][d]) d++; + if (syn_c_special[s][d] == '\0' && (j+d > line->actual || !syn_c_iskeywordchar(line->text[j+d].codepoint))) { + *out_left = d-1; + return FLAG_NUMERAL; + } + } + } + + if ((!last || !syn_c_iskeywordchar(last)) && isdigit(c)) { + if (c == '0' && i < line->actual - 1 && line->text[i+1].codepoint == 'x') { + int j = 2; + for (; i + j < line->actual && isxdigit(line->text[i+j].codepoint); ++j); + if (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) { + return FLAG_NONE; + } + *out_left = j - 1; + return FLAG_NUMERAL; + } else { + int j = 1; + while (i + j < line->actual && isdigit(line->text[i+j].codepoint)) { + j++; + } + if (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) { + return FLAG_NONE; + } + *out_left = j - 1; + return FLAG_NUMERAL; + } + } + + if (c == '/') { + if (i < line->actual - 1 && line->text[i+1].codepoint == '/') { + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT; + } + + if (i < line->actual - 1 && line->text[i+1].codepoint == '*') { + int last = 0; + for (int j = i + 2; j < line->actual; ++j) { + int c = line->text[j].codepoint; + if (c == '/' && last == '*') { + *out_left = j - i; + return FLAG_COMMENT; + } + last = c; + } + /* TODO multiline - update next */ + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT | FLAG_CONTINUES; + } + } + + if (c == '\'') { + if (i < line->actual - 3 && line->text[i+1].codepoint == '\\' && + line->text[i+3].codepoint == '\'') { + *out_left = 3; + return FLAG_NUMERAL; + } + if (i < line->actual - 2 && line->text[i+2].codepoint == '\'') { + *out_left = 2; + return FLAG_NUMERAL; + } + } + + if (c == '"') { + int last = 0; + for (int j = i+1; j < line->actual; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '"') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + return 0; +} + +char * syn_c_ext[] = {".c",".h",".cpp",".hpp",".c++",".h++",NULL}; + +static int syn_c_finish(line_t * line, int * left, int state) { + if (state == (FLAG_COMMENT | FLAG_CONTINUES)) { + int last = 0; + for (int i = 0; i < line->actual; ++i) { + if (line->text[i].codepoint == '/' && last == '*') { + *left = i+2; + return FLAG_COMMENT; + } + last = line->text[i].codepoint; + } + return FLAG_COMMENT | FLAG_CONTINUES; + } + if (state == (FLAG_PRAGMA | FLAG_CONTINUES)) { + *left = line->actual + 1; + if (line->text[line->actual-1].codepoint == '\\') { + return FLAG_PRAGMA | FLAG_CONTINUES; + } + return FLAG_PRAGMA; + } + return 0; +} + +/** + * Syntax definition for Python + */ +static char * syn_py_keywords[] = { + "class","def","return","del","if","else","elif", + "for","while","continue","break","assert", + "as","and","or","except","finally","from", + "global","import","in","is","lambda","with", + "nonlocal","not","pass","raise","try","yield", + NULL +}; + +static char * syn_py_types[] = { + "True","False","None", + "object","set","dict","int","str","bytes", + NULL +}; + +static int syn_py_extended(line_t * line, int i, int c, int last, int * out_left) { + + if (i == 0 && c == 'i') { + /* Check for import */ + char * import = "import "; + for (int j = 0; j < line->actual + 1; ++j) { + if (import[j] == '\0') { + *out_left = j - 2; + return FLAG_PRAGMA; + } + if (line->text[j].codepoint != import[j]) break; + } + } + + if (c == '#') { + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT; + } + + if (c == '@') { + for (int j = i+1; j < line->actual + 1; ++j) { + if (!syn_c_iskeywordchar(line->text[j].codepoint)) { + *out_left = j - i - 1; + return FLAG_PRAGMA; + } + *out_left = (line->actual + 1) - i; + return FLAG_PRAGMA; + } + } + + if ((!last || !syn_c_iskeywordchar(last)) && isdigit(c)) { + if (c == '0' && i < line->actual - 1 && line->text[i+1].codepoint == 'x') { + int j = 2; + for (; i + j < line->actual && isxdigit(line->text[i+j].codepoint); ++j); + if (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) { + return FLAG_NONE; + } + *out_left = j - 1; + return FLAG_NUMERAL; + } else { + int j = 1; + while (i + j < line->actual && isdigit(line->text[i+j].codepoint)) { + j++; + } + if (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) { + return FLAG_NONE; + } + *out_left = j - 1; + return FLAG_NUMERAL; + } + } + + if (line->text[i].codepoint == '\'') { + if (i + 2 < line->actual && line->text[i+1].codepoint == '\'' && line->text[i+2].codepoint == '\'') { + /* Begin multiline */ + for (int j = i + 3; j < line->actual - 2; ++j) { + if (line->text[j].codepoint == '\'' && + line->text[j+1].codepoint == '\'' && + line->text[j+2].codepoint == '\'') { + *out_left = (j+2) - i; + return FLAG_STRING; + } + } + return FLAG_STRING | FLAG_CONTINUES; + } + + int last = 0; + for (int j = i+1; j < line->actual; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '\'') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + if (line->text[i].codepoint == '"') { + if (i + 2 < line->actual && line->text[i+1].codepoint == '"' && line->text[i+2].codepoint == '"') { + /* Begin multiline */ + for (int j = i + 3; j < line->actual - 2; ++j) { + if (line->text[j].codepoint == '"' && + line->text[j+1].codepoint == '"' && + line->text[j+2].codepoint == '"') { + *out_left = (j+2) - i; + return FLAG_STRING; + } + } + return FLAG_STRING2 | FLAG_CONTINUES; + } + + int last = 0; + for (int j = i+1; j < line->actual; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '"') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + return 0; +} + +static int syn_py_finish(line_t * line, int * left, int state) { + /* TODO support multiline quotes */ + if (state == (FLAG_STRING | FLAG_CONTINUES)) { + for (int j = 0; j < line->actual - 2; ++j) { + if (line->text[j].codepoint == '\'' && + line->text[j+1].codepoint == '\'' && + line->text[j+2].codepoint == '\'') { + *left = (j+3); + return FLAG_STRING; + } + } + return FLAG_STRING | FLAG_CONTINUES; + } + if (state == (FLAG_STRING2 | FLAG_CONTINUES)) { + for (int j = 0; j < line->actual - 2; ++j) { + if (line->text[j].codepoint == '"' && + line->text[j+1].codepoint == '"' && + line->text[j+2].codepoint == '"') { + *left = (j+3); + return FLAG_STRING2; + } + } + return FLAG_STRING2 | FLAG_CONTINUES; + } + return 0; +} + +char * syn_py_ext[] = {".py",NULL}; + +/** + * Syntax definition for ToaruOS shell + */ +static char * syn_sh_keywords[] = { + "cd","exit","export","help","history","if", + "empty?","equals?","return","export-cmd", + "source","exec","not","while","then","else", + NULL, +}; + +static int variable_char(uint8_t c) { + if (c >= 'A' && c <= 'Z') return 1; + if (c >= 'a' && c <= 'z') return 1; + if (c >= '0' && c <= '9') return 1; + if (c == '_') return 1; + if (c == '?') return 1; + return 0; +} + +static int syn_sh_extended(line_t * line, int i, int c, int last, int * out_left) { + (void)last; + + if (c == '#' && last != '\\') { + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT; + } + + if (line->text[i].codepoint == '\'' && last != '\\') { + int last = 0; + for (int j = i+1; j < line->actual + 1; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '\'') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + if (line->text[i].codepoint == '$' && last != '\\') { + if (i < line->actual - 1 && line->text[i+1].codepoint == '{') { + int j = i + 2; + for (; j < line->actual+1; ++j) { + if (line->text[j].codepoint == '}') break; + } + *out_left = (j - i); + return FLAG_NUMERAL; + } + int j = i + 1; + for (; j < line->actual + 1; ++j) { + if (!variable_char(line->text[j].codepoint)) break; + } + *out_left = (j - i) - 1; + return FLAG_NUMERAL; + } + + if (line->text[i].codepoint == '"' && last != '\\') { + int last = 0; + for (int j = i+1; j < line->actual + 1; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '"') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + return 0; +} + +static int syn_sh_iskeywordchar(int c) { + if (isalnum(c)) return 1; + if (c == '-') return 1; + if (c == '_') return 1; + if (c == '?') return 1; + return 0; +} + +static char * syn_sh_ext[] = {".sh",".eshrc",".esh",NULL}; + +static char * syn_make_ext[] = {"Makefile","makefile","GNUmakefile",".mak",NULL}; + +static char * syn_make_commands[] = { + "define","endef","undefine","ifdef","ifndef","ifeq","ifneq","else","endif", + "include","sinclude","override","export","unexport","private","vpath", + "-include", + NULL +}; + +static char * syn_make_functions[] = { + "subst","patsubst","findstring","filter","filter-out", + "sort","word","words","wordlist","firstword","lastword", + "dir","notdir","suffix","basename","addsuffix","addprefix", + "join","wildcard","realpath","abspath","error","warning", + "shell","origin","flavor","foreach","if","or","and", + "call","eval","file","value", + NULL +}; + +static int syn_make_extended(line_t * line, int i, int c, int last, int * out_left) { + (void)last; + + if (c == '#') { + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT; + } + + if (c == '\t') { + *out_left = (line->actual + 1) - i; + return FLAG_NUMERAL; + } + + if (i == 0) { + int j = 0; + for (; j < line->actual; ++j) { + /* Handle leading spaces */ + if (line->text[j].codepoint != ' ') break; + } + for (int s = 0; syn_make_commands[s]; ++s) { + int d = 0; + while (j + d < line->actual && line->text[j+d].codepoint == syn_make_commands[s][d]) d++; + if (syn_make_commands[s][d] == '\0') { + *out_left = j+d; + return FLAG_PRAGMA; + } + } + } + + if (last == '(' && i > 1) { + if (line->text[i-2].codepoint == '$') { + int j = i; + for (int s = 0; syn_make_functions[s]; ++s) { + int d = 0; + while (j + d < line->actual && line->text[j+d].codepoint == syn_make_functions[s][d]) d++; + if (syn_make_functions[s][d] == '\0' && (j + d == line->actual + || line->text[j+d].codepoint == ')' || line->text[j+d].codepoint == ' ')) { + *out_left = d; + return FLAG_KEYWORD; + } + } + } + } + + if (i == 0) { + int j = 0; + for (; j < line->actual; ++j) { + if (line->text[j].codepoint == '=') { + *out_left = j; + return FLAG_TYPE; + } + if (line->text[j].codepoint == ':') { + *out_left = j; + return FLAG_TYPE; + } + } + } + + + return FLAG_NONE; +} + +static char * syn_bimrc_keywords[] = { + "theme", + "padding", + NULL, +}; + +static int syn_bimrc_extended(line_t * line, int i, int c, int last, int * out_left) { + (void)last; + if (i == 0 && c == '#') { + *out_left = line->actual+1; + return FLAG_COMMENT; + } + return FLAG_NONE; +} + +static char * syn_bimrc_ext[] = {".bimrc",NULL}; + +static int syn_gitcommit_extended(line_t * line, int i, int c, int last, int * out_left) { + (void)last; + + if (c == '#') { + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT; + } + + return FLAG_NONE; +} + +static char * syn_gitcommit_ext[] = {"COMMIT_EDITMSG",NULL}; + +static char * syn_gitrebase_commands[] = { + "p ","r ","e ","s ","f ","x "," d", + "pick ","reword ","edit ","squash ","fixup ", + "exec ","drop ", + NULL +}; + +static int syn_gitrebase_extended(line_t * line, int i, int c, int last, int * out_left) { + (void)last; + + if (c == '#') { + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT; + } + + if (i == 0) { + int j = i; + for (int s = 0; syn_gitrebase_commands[s]; ++s) { + int d = 0; + while (j + d < line->actual && line->text[j+d].codepoint == syn_gitrebase_commands[s][d]) d++; + if (syn_gitrebase_commands[s][d] == '\0') { + *out_left = j+d-1; + return FLAG_KEYWORD; + } + } + } + + if (i > 0 && (line->text[i-1].flags & FLAG_KEYWORD)) { + int j = i; + while (isxdigit(line->text[j].codepoint)) { + j++; + } + *out_left = j-i-1; + return FLAG_NUMERAL; + } + + return FLAG_NONE; +} + +static char * syn_gitrebase_ext[] = {"git-rebase-todo",NULL}; + +static int syn_diff_extended(line_t * line, int i, int c, int last, int * out_left) { + (void)last; + + if (i == 0) { + if (c == '+') { + *out_left = (line->actual + 1); + return FLAG_DIFFPLUS; + } else if (c == '-') { + *out_left = (line->actual + 1); + return FLAG_DIFFMINUS; + } else if (c == '@') { + *out_left = (line->actual + 1); + return FLAG_TYPE; + } else if (c != ' ') { + *out_left = (line->actual + 1); + return FLAG_KEYWORD; + } + } + + return FLAG_NONE; +} + +static char * syn_diff_ext[] = {".diff",".patch",NULL}; + +/** + * Syntax hilighting definition database + */ +struct syntax_definition { + char * name; + char ** ext; + char ** keywords; + char ** types; + int (*extended)(line_t *, int, int, int, int *); + int (*iskwchar)(int); + int (*finishml)(line_t *, int *, int); +} syntaxes[] = { + {"c",syn_c_ext,syn_c_keywords,syn_c_types,syn_c_extended,syn_c_iskeywordchar,syn_c_finish}, + {"python",syn_py_ext,syn_py_keywords,syn_py_types,syn_py_extended,syn_c_iskeywordchar,syn_py_finish}, + {"esh",syn_sh_ext,syn_sh_keywords,NULL,syn_sh_extended,syn_sh_iskeywordchar,NULL}, + {"make",syn_make_ext,NULL,NULL,syn_make_extended,NULL,NULL}, + {"bimrc",syn_bimrc_ext,syn_bimrc_keywords,NULL,syn_bimrc_extended,syn_c_iskeywordchar,NULL}, + {"gitcommit",syn_gitcommit_ext,NULL,NULL,syn_gitcommit_extended,NULL,NULL}, + {"gitrebase",syn_gitrebase_ext,NULL,NULL,syn_gitrebase_extended,NULL,NULL}, + {"diff",syn_diff_ext,NULL,NULL,syn_diff_extended,NULL,NULL}, + {NULL} +}; + +/** + * Checks whether the character pointed to by `c` is the start of a match for + * keyword or type name `str`. + */ +int check_line(line_t * line, int c, char * str, int last) { + if (env->syntax->iskwchar(last)) return 0; + for (int i = c; i < line->actual; ++i, ++str) { + if (*str == '\0' && !env->syntax->iskwchar(line->text[i].codepoint)) return 1; + if (line->text[i].codepoint == *str) continue; + return 0; + } + if (*str == '\0') return 1; + return 0; +} + +/** + * Calculate syntax hilighting for the given line. + */ +void recalculate_syntax(line_t * line, int offset) { + if (!env->syntax) { + for (int i = 0; i < line->actual; ++i) { + line->text[i].flags = 0; + } + return; + } + + /* Start from the line's stored in initial state */ + int state = line->istate; + int left = 0; + int last = 0; + + if (state) { + /* + * If we are already highlighting coming in, then we need to check + * for a finishing sequence for the curent state. + */ + state = env->syntax->finishml(line,&left,state); + + if (state & FLAG_CONTINUES) { + /* The finish check said that this multiline state continues. */ + for (int i = 0; i < line->actual; i++) { + /* Set the entire line to draw with this state */ + line->text[i].flags = state; + } + + /* Recalculate later lines if needed */ + goto _multiline; + } + } + + for (int i = 0; i < line->actual; last = line->text[i++].codepoint) { + if (!left) state = 0; + + if (state) { + /* Currently hilighting, have `left` characters remaining with this state */ + left--; + line->text[i].flags = state; + + if (!left) { + /* Done hilighting this state, go back to parsing on next character */ + state = 0; + } + + /* If we are hilighting something, don't parse */ + continue; + } + + int c = line->text[i].codepoint; + line->text[i].flags = FLAG_NONE; + + /* Language-specific syntax hilighting */ + if (env->syntax->extended) { + int s = env->syntax->extended(line,i,c,last,&left); + if (s) { + state = s; + if (state & FLAG_CONTINUES) { + /* A multiline state was returned. Fill the rest of the line */ + for (; i < line->actual; i++) { + line->text[i].flags = state; + } + /* And recalculate later lines if needed */ + goto _multiline; + } + goto _continue; + } + } + + /* Keywords */ + if (env->syntax->keywords) { + for (char ** kw = env->syntax->keywords; *kw; kw++) { + int c = check_line(line, i, *kw, last); + if (c == 1) { + left = strlen(*kw)-1; + state = FLAG_KEYWORD; + goto _continue; + } + } + } + + /* Type names */ + if (env->syntax->types) { + for (char ** kw = env->syntax->types; *kw; kw++) { + int c = check_line(line, i, *kw, last); + if (c == 1) { + left = strlen(*kw)-1; + state = FLAG_TYPE; + goto _continue; + } + } + } + +_continue: + line->text[i].flags = state; + } + + state = 0; + +_multiline: + /* + * If the next line's initial state does not match the state we ended on, + * then it needs to be recalculated (and redraw). This may lead to multiple + * recursive calls until a match is found. + */ + if (offset + 1 < env->line_count && env->lines[offset+1]->istate != state) { + /* Set the next line's initial state to our ending state */ + env->lines[offset+1]->istate = state; + + /* Recursively recalculate */ + recalculate_syntax(env->lines[offset+1],offset+1); + + /* + * Determine if this is an on-screen line so we can redraw it; + * this ends up drawing from bottom to top when multiple lines + * need to be redrawn by a recursive call. + */ + if (offset+1 >= env->offset && offset+1 < env->offset + global_config.term_height - global_config.bottom_size - 1) { + redraw_line(offset + 1 - env->offset,offset+1); + } + } +} + +/** + * Recalculate tab widths. + */ +void recalculate_tabs(line_t * line) { + if (env->loading) return; + + int j = 0; + for (int i = 0; i < line->actual; ++i) { + if (line->text[i].codepoint == '\t') { + line->text[i].display_width = env->tabstop - (j % env->tabstop); + } + j += line->text[i].display_width; + } +} + +/** + * TODO: + * + * The line editing functions should probably take a buffer_t * + * so that they can act on buffers other than the active one. + */ + +void recursive_history_free(history_t * root) { + if (!root->next) return; + + history_t * n = root->next; + recursive_history_free(n); + + switch (n->type) { + case HISTORY_REPLACE_LINE: + free(n->remove_replace_line.contents); + /* fall-through */ + case HISTORY_REMOVE_LINE: + free(n->remove_replace_line.old_contents); + break; + default: + /* Nothing extra to free */ + break; + } + + free(n); + root->next = NULL; +} + +#define HIST_APPEND(e) do { \ + if (env->history) { \ + e->previous = env->history; \ + recursive_history_free(env->history); \ + env->history->next = e; \ + e->next = NULL; \ + } \ + env->history = e; \ + } while (0) + +/** + * Mark a point where a complete set of actions has ended. + */ +void set_history_break(void) { + if (!global_config.history_enabled) return; + + if (env->history->type != HISTORY_BREAK && env->history->type != HISTORY_SENTINEL) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_BREAK; + HIST_APPEND(e); + } +} + +/** + * Insert a character into an existing line. + */ +line_t * line_insert(line_t * line, char_t c, int offset, int lineno) { + + if (!env->loading && global_config.history_enabled) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_INSERT; + e->insert_delete_replace.lineno = lineno; + e->insert_delete_replace.offset = offset; + e->insert_delete_replace.codepoint = c.codepoint; + HIST_APPEND(e); + } + + /* If there is not enough space... */ + if (line->actual == line->available) { + /* Expand the line buffer */ + line->available *= 2; + line = realloc(line, sizeof(line_t) + sizeof(char_t) * line->available); + } + + /* If this was not the last character, then shift remaining characters forward. */ + if (offset < line->actual) { + memmove(&line->text[offset+1], &line->text[offset], sizeof(char_t) * (line->actual - offset)); + } + + /* Insert the new character */ + line->text[offset] = c; + + /* There is one new character in the line */ + line->actual += 1; + + if (!env->loading) { + recalculate_tabs(line); + recalculate_syntax(line, lineno); + } + + return line; +} + +/** + * Delete a character from a line + */ +void line_delete(line_t * line, int offset, int lineno) { + + /* Can't delete character before start of line. */ + if (offset == 0) return; + + if (!env->loading && global_config.history_enabled) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_DELETE; + e->insert_delete_replace.lineno = lineno; + e->insert_delete_replace.offset = offset; + e->insert_delete_replace.old_codepoint = line->text[offset-1].codepoint; + HIST_APPEND(e); + } + + /* If this isn't the last character, we need to move all subsequent characters backwards */ + if (offset < line->actual) { + memmove(&line->text[offset-1], &line->text[offset], sizeof(char_t) * (line->actual - offset)); + } + + /* The line is one character shorter */ + line->actual -= 1; + + recalculate_tabs(line); + recalculate_syntax(line, lineno); +} + +/** + * Replace a character in a line + */ +void line_replace(line_t * line, char_t _c, int offset, int lineno) { + + if (!env->loading && global_config.history_enabled) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_REPLACE; + e->insert_delete_replace.lineno = lineno; + e->insert_delete_replace.offset = offset; + e->insert_delete_replace.codepoint = _c.codepoint; + e->insert_delete_replace.old_codepoint = line->text[offset].codepoint; + HIST_APPEND(e); + } + + line->text[offset] = _c; + + if (!env->loading) { + recalculate_tabs(line); + recalculate_syntax(line, lineno); + } +} + +/** + * Remove a line from the active buffer + */ +line_t ** remove_line(line_t ** lines, int offset) { + + /* If there is only one line, clear it instead of removing it. */ + if (env->line_count == 1) { + while (lines[offset]->actual > 0) { + line_delete(lines[offset], lines[offset]->actual, offset); + } + return lines; + } + + if (!env->loading && global_config.history_enabled) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_REMOVE_LINE; + e->remove_replace_line.lineno = offset; + e->remove_replace_line.old_contents = malloc(sizeof(line_t) + sizeof(char_t) * lines[offset]->available); + memcpy(e->remove_replace_line.old_contents, lines[offset], sizeof(line_t) + sizeof(char_t) * lines[offset]->available); + HIST_APPEND(e); + } + + /* Otherwise, free the data used by the line */ + free(lines[offset]); + + /* Move other lines up */ + if (offset < env->line_count) { + memmove(&lines[offset], &lines[offset+1], sizeof(line_t *) * (env->line_count - (offset - 1))); + lines[env->line_count-1] = NULL; + } + + /* There is one less line */ + env->line_count -= 1; + return lines; +} + +/** + * Add a new line to the active buffer. + */ +line_t ** add_line(line_t ** lines, int offset) { + + /* Invalid offset? */ + if (offset > env->line_count) return lines; + + if (!env->loading && global_config.history_enabled) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_ADD_LINE; + e->add_merge_split_lines.lineno = offset; + HIST_APPEND(e); + } + + /* Not enough space */ + if (env->line_count == env->line_avail) { + /* Allocate more space */ + env->line_avail *= 2; + lines = realloc(lines, sizeof(line_t *) * env->line_avail); + } + + /* If this isn't the last line, move other lines down */ + if (offset < env->line_count) { + memmove(&lines[offset+1], &lines[offset], sizeof(line_t *) * (env->line_count - offset)); + } + + /* Allocate the new line */ + lines[offset] = malloc(sizeof(line_t) + sizeof(char_t) * 32); + lines[offset]->available = 32; + lines[offset]->actual = 0; + lines[offset]->istate = 0; + + /* There is one new line */ + env->line_count += 1; + env->lines = lines; + + if (offset > 0 && !env->loading) { + recalculate_syntax(lines[offset-1],offset-1); + } + return lines; +} + +/** + * Replace a line with data from another line (used by paste to paste yanked lines) + */ +void replace_line(line_t ** lines, int offset, line_t * replacement) { + + if (!env->loading && global_config.history_enabled) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_REPLACE_LINE; + e->remove_replace_line.lineno = offset; + e->remove_replace_line.old_contents = malloc(sizeof(line_t) + sizeof(char_t) * lines[offset]->available); + memcpy(e->remove_replace_line.old_contents, lines[offset], sizeof(line_t) + sizeof(char_t) * lines[offset]->available); + e->remove_replace_line.contents = malloc(sizeof(line_t) + sizeof(char_t) * replacement->available); + memcpy(e->remove_replace_line.contents, replacement, sizeof(line_t) + sizeof(char_t) * replacement->available); + HIST_APPEND(e); + } + + if (lines[offset]->available < replacement->actual) { + lines[offset] = realloc(lines[offset], sizeof(line_t) + sizeof(char_t) * replacement->available); + lines[offset]->available = replacement->available; + } + lines[offset]->actual = replacement->actual; + memcpy(&lines[offset]->text, &replacement->text, sizeof(char_t) * replacement->actual); + + if (!env->loading) { + recalculate_syntax(lines[offset],offset); + } +} + +/** + * Merge two consecutive lines. + * lineb is the offset of the second line. + */ +line_t ** merge_lines(line_t ** lines, int lineb) { + + /* linea is the line immediately before lineb */ + int linea = lineb - 1; + + if (!env->loading && global_config.history_enabled) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_MERGE_LINES; + e->add_merge_split_lines.lineno = lineb; + e->add_merge_split_lines.split = env->lines[linea]->actual; + HIST_APPEND(e); + } + + /* If there isn't enough space in linea hold both... */ + while (lines[linea]->available < lines[linea]->actual + lines[lineb]->actual) { + /* ... allocate more space until it fits */ + lines[linea]->available *= 2; + /* XXX why not just do this once after calculating appropriate size */ + lines[linea] = realloc(lines[linea], sizeof(line_t) + sizeof(char_t) * lines[linea]->available); + } + + /* Copy the second line into the first line */ + memcpy(&lines[linea]->text[lines[linea]->actual], &lines[lineb]->text, sizeof(char_t) * lines[lineb]->actual); + + /* The first line is now longer */ + lines[linea]->actual = lines[linea]->actual + lines[lineb]->actual; + + if (!env->loading) { + recalculate_tabs(lines[linea]); + recalculate_syntax(lines[linea], linea); + } + + /* Remove the second line */ + free(lines[lineb]); + + /* Move other lines up */ + if (lineb < env->line_count) { + memmove(&lines[lineb], &lines[lineb+1], sizeof(line_t *) * (env->line_count - (lineb - 1))); + lines[env->line_count-1] = NULL; + } + + /* There is one less line */ + env->line_count -= 1; + return lines; +} + +/** + * Split a line into two lines at the given column + */ +line_t ** split_line(line_t ** lines, int line, int split) { + + /* If we're trying to split from the start, just add a new blank line before */ + if (split == 0) { + return add_line(lines, line); + } + + if (!env->loading && global_config.history_enabled) { + history_t * e = malloc(sizeof(history_t)); + e->type = HISTORY_SPLIT_LINE; + e->add_merge_split_lines.lineno = line; + e->add_merge_split_lines.split = split; + HIST_APPEND(e); + } + + /* Allocate more space as needed */ + if (env->line_count == env->line_avail) { + env->line_avail *= 2; + lines = realloc(lines, sizeof(line_t *) * env->line_avail); + } + + /* Shift later lines down */ + if (line < env->line_count) { + memmove(&lines[line+2], &lines[line+1], sizeof(line_t *) * (env->line_count - line)); + } + + /* I have no idea what this is doing */ + int remaining = lines[line]->actual - split; + + int v = remaining; + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + + /* Allocate space for the new line */ + lines[line+1] = malloc(sizeof(line_t) + sizeof(char_t) * v); + lines[line+1]->available = v; + lines[line+1]->actual = remaining; + lines[line+1]->istate = 0; + + /* Move the data from the old line into the new line */ + memmove(lines[line+1]->text, &lines[line]->text[split], sizeof(char_t) * remaining); + lines[line]->actual = split; + + if (!env->loading) { + recalculate_tabs(lines[line]); + recalculate_tabs(lines[line+1]); + recalculate_syntax(lines[line], line); + recalculate_syntax(lines[line+1], line+1); + } + + /* There is one new line */ + env->line_count += 1; + + /* We may have reallocated lines */ + return lines; +} + +/** + * Add indentation from the previous (temporally) line + */ +void add_indent(int new_line, int old_line) { + if (env->indent) { + int changed = 0; + for (int i = 0; i < env->lines[old_line]->actual; ++i) { + if (env->lines[old_line]->text[i].codepoint == ' ' || + env->lines[old_line]->text[i].codepoint == '\t') { + env->lines[new_line] = line_insert(env->lines[new_line],env->lines[old_line]->text[i],i,new_line); + env->col_no++; + changed = 1; + } else { + break; + } + } + if (old_line < new_line && + (env->lines[old_line]->text[env->lines[old_line]->actual-1].codepoint == '{' || + env->lines[old_line]->text[env->lines[old_line]->actual-1].codepoint == ':')) { + if (env->tabs) { + char_t c; + c.codepoint = '\t'; + c.display_width = env->tabstop; + env->lines[new_line] = line_insert(env->lines[new_line], c, env->lines[new_line]->actual, new_line); + env->col_no++; + changed = 1; + } else { + for (int j = 0; j < env->tabstop; ++j) { + char_t c; + c.codepoint = ' '; + c.display_width = 1; + c.flags = FLAG_SELECT; + env->lines[new_line] = line_insert(env->lines[new_line], c, env->lines[new_line]->actual, new_line); + env->col_no++; + } + changed = 1; + } + } + if (changed) { + recalculate_syntax(env->lines[new_line],new_line); + } + } +} + +/** + * Initialize a buffer with default values + */ +void setup_buffer(buffer_t * env) { + /* If this buffer was already initialized, clear out its line data */ + if (env->lines) { + for (int i = 0; i < env->line_count; ++i) { + free(env->lines[i]); + } + free(env->lines); + } + + /* Default state parameters */ + env->line_no = 1; /* Default cursor position */ + env->col_no = 1; + env->line_count = 1; /* Buffers always have at least one line */ + env->modified = 0; + env->readonly = 0; + env->offset = 0; + env->line_avail = 8; /* Default line buffer capacity */ + env->tabs = 1; /* Tabs by default */ + env->tabstop = 4; /* Tab stop width */ + env->indent = 1; /* Auto-indent by default */ + env->history = malloc(sizeof(struct history)); + memset(env->history, 0, sizeof(struct history)); + env->last_save_history = env->history; + + /* Allocate line buffer */ + env->lines = malloc(sizeof(line_t *) * env->line_avail); + + /* Initialize the first line */ + env->lines[0] = malloc(sizeof(line_t) + sizeof(char_t) * 32); + env->lines[0]->available = 32; + env->lines[0]->actual = 0; + env->lines[0]->istate = 0; +} + +/** + * Toggle buffered / unbuffered modes + */ +struct termios old; +void get_initial_termios(void) { + tcgetattr(STDOUT_FILENO, &old); +} + +void set_unbuffered(void) { + struct termios new = old; + new.c_lflag &= (~ICANON & ~ECHO); + new.c_cc[VINTR] = 0; + tcsetattr(STDOUT_FILENO, TCSAFLUSH, &new); +} + +void set_buffered(void) { + tcsetattr(STDOUT_FILENO, TCSAFLUSH, &old); +} + +/** + * Convert codepoint to utf-8 string + */ +int to_eight(uint32_t codepoint, char * out) { + memset(out, 0x00, 7); + + if (codepoint < 0x0080) { + out[0] = (char)codepoint; + } else if (codepoint < 0x0800) { + out[0] = 0xC0 | (codepoint >> 6); + out[1] = 0x80 | (codepoint & 0x3F); + } else if (codepoint < 0x10000) { + out[0] = 0xE0 | (codepoint >> 12); + out[1] = 0x80 | ((codepoint >> 6) & 0x3F); + out[2] = 0x80 | (codepoint & 0x3F); + } else if (codepoint < 0x200000) { + out[0] = 0xF0 | (codepoint >> 18); + out[1] = 0x80 | ((codepoint >> 12) & 0x3F); + out[2] = 0x80 | ((codepoint >> 6) & 0x3F); + out[3] = 0x80 | ((codepoint) & 0x3F); + } else if (codepoint < 0x4000000) { + out[0] = 0xF8 | (codepoint >> 24); + out[1] = 0x80 | (codepoint >> 18); + out[2] = 0x80 | ((codepoint >> 12) & 0x3F); + out[3] = 0x80 | ((codepoint >> 6) & 0x3F); + out[4] = 0x80 | ((codepoint) & 0x3F); + } else { + out[0] = 0xF8 | (codepoint >> 30); + out[1] = 0x80 | ((codepoint >> 24) & 0x3F); + out[2] = 0x80 | ((codepoint >> 18) & 0x3F); + out[3] = 0x80 | ((codepoint >> 12) & 0x3F); + out[4] = 0x80 | ((codepoint >> 6) & 0x3F); + out[5] = 0x80 | ((codepoint) & 0x3F); + } + + return strlen(out); +} + +/** + * Get the presentation width of a codepoint + */ +int codepoint_width(wchar_t codepoint) { + if (codepoint == '\t') { + return 1; /* Recalculate later */ + } + if (codepoint < 32) { + /* We render these as ^@ */ + return 2; + } + if (codepoint == 0x7F) { + /* Renders as ^? */ + return 2; + } + if (codepoint > 0x7f && codepoint < 0xa0) { + /* Upper control bytes */ + return 4; + } + if (codepoint == 0xa0) { + /* Non-breaking space _ */ + return 1; + } + /* Skip wcwidth for anything under 256 */ + if (codepoint > 256) { + if (global_config.can_unicode) { + /* Higher codepoints may be wider (eg. Japanese) */ + int out = wcwidth(codepoint); + if (out >= 1) return out; + } + /* Invalid character, render as [U+ABCD] or [U+ABCDEF] */ + return (codepoint < 0x10000) ? 8 : 10; + } + return 1; +} + +/** + * Move the terminal cursor + */ +void place_cursor(int x, int y) { + printf("\033[%d;%dH", y, x); + fflush(stdout); +} + +/** + * Set text colors + * + * Normally, text colors are just strings, but if they + * start with @ they will be parsed as integers + * representing one of the 16 standard colors, suitable + * for terminals without support for the 256- or 24-bit + * color modes. + */ +void set_colors(const char * fg, const char * bg) { + printf("\033[22;23;"); + if (*bg == '@') { + int _bg = atoi(bg+1); + if (_bg < 10) { + printf("4%d;", _bg); + } else { + printf("10%d;", _bg-10); + } + } else { + printf("48;%s;", bg); + } + if (*fg == '@') { + int _fg = atoi(fg+1); + if (_fg < 10) { + printf("3%dm", _fg); + } else { + printf("9%dm", _fg-10); + } + } else { + printf("38;%sm", fg); + } + fflush(stdout); +} + +/** + * Set just the foreground color + * + * (See set_colors above) + */ +void set_fg_color(const char * fg) { + printf("\033[22;23;"); + if (*fg == '@') { + int _fg = atoi(fg+1); + if (_fg < 10) { + printf("3%dm", _fg); + } else { + printf("9%dm", _fg-10); + } + } else { + printf("38;%sm", fg); + } + fflush(stdout); +} + +/** + * Clear the rest of this line + */ +void clear_to_end(void) { + if (global_config.can_bce) { + printf("\033[K"); + fflush(stdout); + } +} + +/** + * For terminals without bce, + * prepaint the whole line, so we don't have to track + * where the cursor is for everything. Inefficient, + * but effective. + */ +void paint_line(const char * bg) { + if (!global_config.can_bce) { + set_colors(COLOR_FG, bg); + for (int i = 0; i < global_config.term_width; ++i) { + printf(" "); + } + printf("\r"); + } +} + +/** + * Enable bold text display + */ +void set_bold(void) { + printf("\033[1m"); + fflush(stdout); +} + +/** + * Enable underlined text display + */ +void set_underline(void) { + printf("\033[4m"); + fflush(stdout); +} + +/** + * Reset text display attributes + */ +void reset(void) { + printf("\033[0m"); + fflush(stdout); +} + +/** + * Clear the entire screen + */ +void clear_screen(void) { + printf("\033[H\033[2J"); + fflush(stdout); +} + +/** + * Hide the cursor + */ +void hide_cursor(void) { + if (global_config.can_hideshow) { + printf("\033[?25l"); + } + fflush(stdout); +} + +/* + * Show the cursor + */ +void show_cursor(void) { + if (global_config.can_hideshow) { + printf("\033[?25h"); + } + fflush(stdout); +} + +/** + * Request mouse events + */ +void mouse_enable(void) { + if (global_config.can_mouse) { + printf("\033[?1000h"); + } + fflush(stdout); +} + +/** + * Stop mouse events + */ +void mouse_disable(void) { + if (global_config.can_mouse) { + printf("\033[?1000l"); + } + fflush(stdout); +} + +/** + * Shift the screen up one line + */ +void shift_up(void) { + printf("\033[1S"); +} + +/** + * Shift the screen down one line. + */ +void shift_down(void) { + printf("\033[1T"); +} + +/** + * Switch to the alternate terminal screen. + */ +void set_alternate_screen(void) { + if (global_config.can_altscreen) { + printf("\033[?1049h"); + } +} + +/** + * Restore the standard terminal screen. + */ +void unset_alternate_screen(void) { + if (global_config.can_altscreen) { + printf("\033[?1049l"); + } +} + +/** + * Redaw the tabbar, with a tab for each buffer. + * + * The active buffer is highlighted. + */ +void redraw_tabbar(void) { + /* Hide cursor while rendering UI */ + hide_cursor(); + + /* Move to upper left */ + place_cursor(1,1); + + paint_line(COLOR_TABBAR_BG); + + /* For each buffer... */ + for (int i = 0; i < buffers_len; i++) { + buffer_t * _env = buffers[i]; + + if (_env == env) { + /* If this is the active buffer, hilight it */ + reset(); + set_colors(COLOR_FG, COLOR_BG); + set_bold(); + } else { + /* Otherwise use default tab color */ + reset(); + set_colors(COLOR_FG, COLOR_TAB_BG); + set_underline(); + } + + /* If this buffer is modified, indicate that with a prepended + */ + if (_env->modified) { + printf(" +"); + } + + /* Print the filename */ + if (_env->file_name) { + printf(" %s ", _env->file_name); + } else { + printf(" [No Name] "); + } + } + + /* Reset bold/underline */ + reset(); + /* Fill the rest of the tab bar */ + set_colors(COLOR_FG, COLOR_TABBAR_BG); + clear_to_end(); +} + +/** + * Braindead log10 implementation for the line numbers + */ +int log_base_10(unsigned int v) { + int r = (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 : + (v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 : + (v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0; + return r; +} + +/** + * Render a line of text + * + * This handles rendering the actual text content. A full line of text + * also includes a line number and some padding. + * + * width: width of the text display region (term width - line number width) + * offset: how many cells into the line to start rendering at + */ +void render_line(line_t * line, int width, int offset) { + int i = 0; /* Offset in char_t line data entries */ + int j = 0; /* Offset in terminal cells */ + + const char * last_color = NULL; + int was_selecting = 0; + + /* Set default text colors */ + set_colors(COLOR_FG, COLOR_BG); + + /* + * When we are rendering in the middle of a wide character, + * we render -'s to fill the remaining amount of the + * charater's width + */ + int remainder = 0; + + /* For each character in the line ... */ + while (i < line->actual) { + + /* If there is remaining text... */ + if (remainder) { + + /* If we should be drawing by now... */ + if (j >= offset) { + /* Fill remainder with -'s */ + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("-"); + set_colors(COLOR_FG, COLOR_BG); + } + + /* One less remaining width cell to fill */ + remainder--; + + /* Terminal offset moves forward */ + j++; + + /* + * If this was the last remaining character, move to + * the next codepoint in the line + */ + if (remainder == 0) { + i++; + } + + continue; + } + + /* Get the next character to draw */ + char_t c = line->text[i]; + + /* If we should be drawing by now... */ + if (j >= offset) { + + /* If this character is going to fall off the edge of the screen... */ + if (j - offset + c.display_width >= width) { + /* We draw this with special colors so it isn't ambiguous */ + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + + /* If it's wide, draw ---> as needed */ + while (j - offset < width - 1) { + printf("-"); + j++; + } + + /* End the line with a > to show it overflows */ + printf(">"); + set_colors(COLOR_FG, COLOR_BG); + return; + } + + /* Syntax hilighting */ + const char * color = flag_to_color(c.flags); + if (c.flags == FLAG_SELECT) { + set_colors(COLOR_SELECTFG, COLOR_SELECTBG); + was_selecting = 1; + } else { + if (was_selecting) { + set_colors(color, COLOR_BG); + last_color = color; + } else if (!last_color || strcmp(color, last_color)) { + set_fg_color(color); + last_color = color; + } + } + +#define _set_colors(fg,bg) if (c.flags != FLAG_SELECT) { set_colors(fg,bg); } + + /* Render special characters */ + if (c.codepoint == '\t') { + _set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + if (global_config.can_unicode) { + printf("»"); + for (int i = 1; i < c.display_width; ++i) { + printf("·"); + } + } else { + printf(">"); + for (int i = 1; i < c.display_width; ++i) { + printf("-"); + } + } + _set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint < 32) { + /* Codepoints under 32 to get converted to ^@ escapes */ + _set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("^%c", '@' + c.codepoint); + _set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint == 0x7f) { + _set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("^?"); + _set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint > 0x7f && c.codepoint < 0xa0) { + _set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("<%2x>", c.codepoint); + _set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint == 0xa0) { + _set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("_"); + _set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.display_width == 8) { + _set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("[U+%04x]", c.codepoint); + _set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.display_width == 10) { + _set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("[U+%06x]", c.codepoint); + _set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint == ' ' && i == line->actual - 1) { + /* Special case: space at end of line */ + _set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("·"); + _set_colors(COLOR_FG, COLOR_BG); + } else { + /* Normal characters get output */ + char tmp[7]; /* Max six bytes, use 7 to ensure last is always nil */ + to_eight(c.codepoint, tmp); + printf("%s", tmp); + } + + /* Advance the terminal cell offset by the render width of this character */ + j += c.display_width; + + /* Advance to the next character */ + i++; + } else if (c.display_width > 1) { + /* + * If this is a wide character but we aren't ready to render yet, + * we may need to draw some filler text for the remainder of its + * width to ensure we don't jump around when horizontally scrolling + * past wide characters. + */ + remainder = c.display_width - 1; + j++; + } else { + /* Regular character, not ready to draw, advance without doing anything */ + j++; + i++; + } + } + + if (env->mode == MODE_CHAR_SELECTION) { + set_colors(COLOR_FG, COLOR_BG); + } + + if (!global_config.can_bce) { + /* Paint the rest of the line */ + for (; j < global_config.term_width; ++j) { + printf(" "); + } + } + + /* Clear the rest of the line */ + clear_to_end(); +} + +/** + * Get the width of the line number region + */ +int num_width(void) { + int w = log_base_10(env->line_count) + 1; + if (w < 2) return 2; + return w; +} + +/** + * Draw the gutter and line numbers. + */ +void draw_line_number(int x) { + /* Draw the line number */ + set_colors(COLOR_NUMBER_FG, COLOR_NUMBER_BG); + int num_size = num_width(); + for (int y = 0; y < num_size - log_base_10(x + 1); ++y) { + printf(" "); + } + printf("%d%c", x + 1, (x+1 == env->line_no && env->coffset > 0) ? '<' : ' '); +} + +/** + * Redraw line. + * + * This draws the line number as well as the actual text. + * j = screen-relative line offset. + */ +void redraw_line(int j, int x) { + if (env->loading) return; + /* Hide cursor when drawing */ + hide_cursor(); + + /* Move cursor to upper left most cell of this line */ + place_cursor(1,2 + j); + + /* Draw a gutter on the left. + * TODO: The gutter can be used to show single-character + * line annotations, such as collapse state, or + * whether a search result was found on this line. + */ + set_colors(COLOR_NUMBER_FG, COLOR_ALT_FG); + printf(" "); + + draw_line_number(x); + + /* + * Draw the line text + * If this is the active line, the current character cell offset should be used. + * (Non-active lines are not shifted and always render from the start of the line) + */ + render_line(env->lines[x], global_config.term_width - 3 - num_width(), (x + 1 == env->line_no) ? env->coffset : 0); +} + +/** + * Draw a ~ line where there is no buffer text. + */ +void draw_excess_line(int j) { + place_cursor(1,2 + j); + paint_line(COLOR_ALT_BG); + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("~"); + clear_to_end(); +} + +/** + * Redraw the entire text area + */ +void redraw_text(void) { + /* Hide cursor while rendering */ + hide_cursor(); + + /* Figure out the available size of the text region */ + int l = global_config.term_height - global_config.bottom_size - 1; + int j = 0; + + /* Draw each line */ + for (int x = env->offset; j < l && x < env->line_count; x++) { + redraw_line(j,x); + j++; + } + + /* Draw the rest of the text region as ~ lines */ + for (; j < l; ++j) { + draw_excess_line(j); + } +} + +/** + * Draw the status bar + * + * The status bar shows the name of the file, whether it has modifications, + * and (in the future) what syntax highlighting mode is enabled. + * + * The right side of the tatus bar shows the line number and column. + */ +void redraw_statusbar(void) { + /* Hide cursor while rendering */ + hide_cursor(); + + /* Move cursor to the status bar line (second from bottom */ + place_cursor(1, global_config.term_height - 1); + + /* Set background colors for status line */ + paint_line(COLOR_STATUS_BG); + set_colors(COLOR_STATUS_FG, COLOR_STATUS_BG); + + /* Print the file name */ + if (env->file_name) { + printf("%s", env->file_name); + } else { + printf("[No Name]"); + } + + printf(" "); + + if (env->syntax) { + printf("[%s]", env->syntax->name); + } + + /* Print file status indicators */ + if (env->modified) { + printf("[+]"); + } + + if (env->readonly) { + printf("[ro]"); + } + + printf(" "); + + if (env->tabs) { + printf("[tabs]"); + } else { + printf("[spaces=%d]", env->tabstop); + } + + if (global_config.yanks) { + printf("[y:%ld]", global_config.yank_count); + } + + if (env->indent) { + printf("[indent]"); + } + + /* Clear the rest of the status bar */ + clear_to_end(); + + /* Pre-render the right hand side of the status bar */ + char right_hand[1024]; + snprintf(right_hand, 1024, "Line %d/%d Col: %d ", env->line_no, env->line_count, env->col_no); + + /* Move the cursor appropriately to draw it */ + place_cursor(global_config.term_width - strlen(right_hand), global_config.term_height - 1); + /* TODO: What if we're localized and this has wide chars? */ + printf("%s",right_hand); + fflush(stdout); +} + +/** + * Draw the command line + * + * The command line either has input from the user (:quit, :!make, etc.) + * or shows the INSERT (or VISUAL in the future) mode name. + */ +void redraw_commandline(void) { + /* Hide cursor while rendering */ + hide_cursor(); + + /* Move cursor to the last line */ + place_cursor(1, global_config.term_height); + + /* Set background color */ + paint_line(COLOR_BG); + set_colors(COLOR_FG, COLOR_BG); + + /* If we are in an edit mode, note that. */ + if (env->mode == MODE_INSERT) { + set_bold(); + printf("-- INSERT --"); + clear_to_end(); + reset(); + } else if (env->mode == MODE_LINE_SELECTION) { + set_bold(); + printf("-- LINE SELECTION --"); + clear_to_end(); + reset(); + } else if (env->mode == MODE_REPLACE) { + set_bold(); + printf("-- REPLACE --"); + clear_to_end(); + reset(); + } else if (env->mode == MODE_CHAR_SELECTION) { + set_bold(); + printf("-- CHAR SELECTION --"); + clear_to_end(); + reset(); + } else { + clear_to_end(); + } +} + +/** + * Draw a message on the command line. + */ +void render_commandline_message(char * message, ...) { + /* varargs setup */ + va_list args; + va_start(args, message); + char buf[1024]; + + /* Process format string */ + vsnprintf(buf, 1024, message, args); + va_end(args); + + /* Hide cursor while rendering */ + hide_cursor(); + + /* Move cursor to the last line */ + place_cursor(1, global_config.term_height); + + /* Set background color */ + paint_line(COLOR_BG); + set_colors(COLOR_FG, COLOR_BG); + + printf("%s", buf); + + /* Clear the rest of the status bar */ + clear_to_end(); +} + +/** + * Draw all screen elements + */ +void redraw_all(void) { + redraw_tabbar(); + redraw_text(); + redraw_statusbar(); + redraw_commandline(); +} + +/** + * Update the terminal title bar + */ +void update_title(void) { + if (!global_config.can_title) return; + + char cwd[1024] = {'/',0}; + getcwd(cwd, 1024); + + for (int i = 1; i < 3; ++i) { + printf("\033]%d;%s%s (%s) - BIM\007", i, env->file_name ? env->file_name : "[No Name]", env->modified ? " +" : "", cwd); + } +} + +/** + * Mark this buffer as modified and + * redraw the status and tabbar if needed. + */ +void set_modified(void) { + /* If it was already marked modified, no need to do anything */ + if (env->modified) return; + + /* Mark as modified */ + env->modified = 1; + + /* Redraw some things */ + update_title(); + redraw_tabbar(); + redraw_statusbar(); +} + +/** + * Draw a message on the status line + */ +void render_status_message(char * message, ...) { + /* varargs setup */ + va_list args; + va_start(args, message); + char buf[1024]; + + /* Process format string */ + vsnprintf(buf, 1024, message, args); + va_end(args); + + /* Hide cursor while rendering */ + hide_cursor(); + + /* Move cursor to the status bar line (second from bottom */ + place_cursor(1, global_config.term_height - 1); + + /* Set background colors for status line */ + paint_line(COLOR_STATUS_BG); + set_colors(COLOR_STATUS_FG, COLOR_STATUS_BG); + + printf("%s", buf); + + /* Clear the rest of the status bar */ + clear_to_end(); +} + +/** + * Draw an errormessage to the command line. + */ +void render_error(char * message, ...) { + /* varargs setup */ + va_list args; + va_start(args, message); + char buf[1024]; + + /* Process format string */ + vsnprintf(buf, 1024, message, args); + va_end(args); + + /* Hide cursor while rendering */ + hide_cursor(); + + /* Move cursor to the command line */ + place_cursor(1, global_config.term_height); + + /* Set appropriate error message colors */ + set_colors(COLOR_ERROR_FG, COLOR_ERROR_BG); + + /* Draw the message */ + printf("%s", buf); + fflush(stdout); +} + +/** + * Move the cursor to the appropriate location based + * on where it is in the text region. + * + * This does some additional math to set the text + * region horizontal offset. + */ +void place_cursor_actual(void) { + + /* Invalid positions */ + if (env->line_no < 1) env->line_no = 1; + if (env->col_no < 1) env->col_no = 1; + + /* Account for the left hand gutter */ + int num_size = num_width() + 3; + int x = num_size + 1 - env->coffset; + + /* Determine where the cursor is physically */ + for (int i = 0; i < env->col_no - 1; ++i) { + char_t * c = &env->lines[env->line_no-1]->text[i]; + x += c->display_width; + } + + /* y is a bit easier to calculate */ + int y = env->line_no - env->offset + 1; + + int needs_redraw = 0; + + while (y < 2 + global_config.cursor_padding && env->offset > 0) { + y++; + env->offset--; + needs_redraw = 1; + } + + while (y > global_config.term_height - global_config.bottom_size - global_config.cursor_padding) { + y--; + env->offset++; + needs_redraw = 1; + } + + if (needs_redraw) { + redraw_text(); + redraw_tabbar(); + redraw_statusbar(); + redraw_commandline(); + } + + /* If the cursor has gone off screen to the right... */ + if (x > global_config.term_width - 1) { + /* Adjust the offset appropriately to scroll horizontally */ + int diff = x - (global_config.term_width - 1); + env->coffset += diff; + x -= diff; + redraw_text(); + } + + /* Same for scrolling horizontally to the left */ + if (x < num_size + 1) { + int diff = (num_size + 1) - x; + env->coffset -= diff; + x += diff; + redraw_text(); + } + + /* Move the actual terminal cursor */ + place_cursor(x,y); + + /* Show the cursor */ + show_cursor(); +} + +/** + * Update screen size + */ +void update_screen_size(void) { + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + global_config.term_width = w.ws_col; + global_config.term_height = w.ws_row; +} + +/** + * Handle terminal size changes + */ +void SIGWINCH_handler(int sig) { + (void)sig; + update_screen_size(); + redraw_all(); + + signal(SIGWINCH, SIGWINCH_handler); +} + +/** + * Handle suspend + */ +void SIGTSTP_handler(int sig) { + (void)sig; + mouse_disable(); + set_buffered(); + reset(); + clear_screen(); + show_cursor(); + unset_alternate_screen(); + fflush(stdout); + + signal(SIGTSTP, SIG_DFL); + raise(SIGTSTP); +} + +void SIGCONT_handler(int sig) { + (void)sig; + set_alternate_screen(); + set_unbuffered(); + mouse_enable(); + redraw_all(); + signal(SIGCONT, SIGCONT_handler); + signal(SIGTSTP, SIGTSTP_handler); +} + +/** + * Move the cursor to a specific line. + */ +void goto_line(int line) { + + /* Respect file bounds */ + if (line < 1) line = 1; + if (line > env->line_count) line = env->line_count; + + /* Move the cursor / text region offsets */ + env->coffset = 0; + env->offset = line - 1; + env->line_no = line; + env->col_no = 1; + redraw_all(); +} + + +/** + * UTF-8 parser state + */ +static uint32_t codepoint_r; +static uint32_t state = 0; + +#define UTF8_ACCEPT 0 +#define UTF8_REJECT 1 + +static inline uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t byte) { + static int state_table[32] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xxxxxxx */ + 1,1,1,1,1,1,1,1, /* 10xxxxxx */ + 2,2,2,2, /* 110xxxxx */ + 3,3, /* 1110xxxx */ + 4, /* 11110xxx */ + 1 /* 11111xxx */ + }; + + static int mask_bytes[32] = { + 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, + 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x1F,0x1F,0x1F,0x1F, + 0x0F,0x0F, + 0x07, + 0x00 + }; + + static int next[5] = { + 0, + 1, + 0, + 2, + 3 + }; + + if (*state == UTF8_ACCEPT) { + *codep = byte & mask_bytes[byte >> 3]; + *state = state_table[byte >> 3]; + } else if (*state > 0) { + *codep = (byte & 0x3F) | (*codep << 6); + *state = next[*state]; + } + return *state; +} + +/** + * Processs (part of) a file and add it to a buffer. + */ +void add_buffer(uint8_t * buf, int size) { + for (int i = 0; i < size; ++i) { + if (!decode(&state, &codepoint_r, buf[i])) { + uint32_t c = codepoint_r; + if (c == '\n') { + env->lines = add_line(env->lines, env->line_no); + env->col_no = 1; + env->line_no += 1; + } else { + char_t _c; + _c.codepoint = (uint32_t)c; + _c.flags = 0; + _c.display_width = codepoint_width((wchar_t)c); + line_t * line = env->lines[env->line_no - 1]; + line_t * nline = line_insert(line, _c, env->col_no - 1, env->line_no-1); + if (line != nline) { + env->lines[env->line_no - 1] = nline; + } + env->col_no += 1; + } + } else if (state == UTF8_REJECT) { + state = 0; + } + } +} + +struct syntax_definition * match_syntax(char * file) { + for (struct syntax_definition * s = syntaxes; s->name; ++s) { + for (char ** ext = s->ext; *ext; ++ext) { + int i = strlen(file); + int j = strlen(*ext); + + do { + if (file[i] != (*ext)[j]) break; + if (j == 0) return s; + if (i == 0) break; + i--; + j--; + } while (1); + } + } + + return NULL; +} + +/** + * Create a new buffer from a file. + */ +void open_file(char * file) { + env = buffer_new(); + env->loading = 1; + + setup_buffer(env); + + FILE * f; + + if (!strcmp(file,"-")) { + /** + * Read file from stdin. stderr provides terminal input. + */ + f = stdin; + global_config.tty_in = STDERR_FILENO; + env->modified = 1; + } else { + f = fopen(file, "r"); + env->file_name = strdup(file); + } + + if (!f) { + if (global_config.hilight_on_open) { + env->syntax = match_syntax(file); + } + env->loading = 0; + return; + } + + uint8_t buf[BLOCK_SIZE]; + + state = 0; + + while (!feof(f) && !ferror(f)) { + size_t r = fread(buf, 1, BLOCK_SIZE, f); + add_buffer(buf, r); + } + + if (ferror(f)) { + env->loading = 0; + return; + } + + if (env->line_no && env->lines[env->line_no-1] && env->lines[env->line_no-1]->actual == 0) { + /* Remove blank line from end */ + remove_line(env->lines, env->line_no-1); + } + + if (global_config.hilight_on_open) { + env->syntax = match_syntax(file); + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + } + + /* Try to automatically figure out tabs vs. spaces */ + int tabs = 0, spaces = 0; + for (int i = 0; i < env->line_count; ++i) { + if (env->lines[i]->actual > 1) { /* Make sure line has at least some text on it */ + if (env->lines[i]->text[0].codepoint == '\t') tabs++; + if (env->lines[i]->text[0].codepoint == ' ' && + env->lines[i]->text[1].codepoint == ' ') /* Ignore spaces at the start of asterisky C comments */ + spaces++; + } + } + if (spaces > tabs) { + env->tabs = 0; + } + + /* TODO figure out tabstop for spaces? */ + + env->loading = 0; + + for (int i = 0; i < env->line_count; ++i) { + recalculate_tabs(env->lines[i]); + } + + fclose(f); +} + +/** + * Clean up the terminal and exit the editor. + */ +void quit(void) { + mouse_disable(); + set_buffered(); + reset(); + clear_screen(); + show_cursor(); + unset_alternate_screen(); + exit(0); +} + +/** + * Try to quit, but don't continue if there are + * modified buffers open. + */ +void try_quit(void) { + for (int i = 0; i < buffers_len; i++ ) { + buffer_t * _env = buffers[i]; + if (_env->modified) { + if (_env->file_name) { + render_error("Modifications made to file `%s` in tab %d. Aborting.", _env->file_name, i+1); + } else { + render_error("Unsaved new file in tab %d. Aborting.", i+1); + } + return; + } + } + quit(); +} + +/** + * Switch to the previous buffer + */ +void previous_tab(void) { + buffer_t * last = NULL; + for (int i = 0; i < buffers_len; i++) { + buffer_t * _env = buffers[i]; + if (_env == env) { + if (last) { + /* Wrap around */ + env = last; + redraw_all(); + return; + } else { + env = buffers[buffers_len-1]; + redraw_all(); + return; + } + } + last = _env; + } +} + +/** + * Switch to the next buffer + */ +void next_tab(void) { + for (int i = 0; i < buffers_len; i++) { + buffer_t * _env = buffers[i]; + if (_env == env) { + if (i != buffers_len - 1) { + env = buffers[i+1]; + redraw_all(); + return; + } else { + /* Wrap around */ + env = buffers[0]; + redraw_all(); + return; + } + } + } +} + +/** + * Write active buffer to file + */ +void write_file(char * file) { + if (!file) { + render_error("Need a file to write to."); + return; + } + + FILE * f = fopen(file, "w+"); + + if (!f) { + render_error("Failed to open file for writing."); + return; + } + + /* Go through each line and convert it back to UTF-8 */ + int i, j; + for (i = 0; i < env->line_count; ++i) { + line_t * line = env->lines[i]; + for (j = 0; j < line->actual; j++) { + char_t c = line->text[j]; + if (c.codepoint == 0) { + char buf[1] = {0}; + fwrite(buf, 1, 1, f); + } else { + char tmp[8] = {0}; + int i = to_eight(c.codepoint, tmp); + fwrite(tmp, i, 1, f); + } + } + fputc('\n', f); + } + fclose(f); + + /* Mark it no longer modified */ + env->modified = 0; + env->last_save_history = env->history; + + /* If there was no file name set, set one */ + if (!env->file_name) { + env->file_name = malloc(strlen(file) + 1); + memcpy(env->file_name, file, strlen(file) + 1); + } + + update_title(); + redraw_all(); +} + +/** + * Close the active buffer + */ +void close_buffer(void) { + buffer_t * previous_env = env; + buffer_t * new_env = buffer_close(env); + if (new_env == previous_env) { + /* ?? Failed to close buffer */ + render_error("lolwat"); + } + /* No more buffers, exit */ + if (!new_env) { + quit(); + } + /* Clean up the old buffer */ + free(previous_env); + + /* Set the new active buffer */ + env = new_env; + + /* Redraw the screen */ + redraw_all(); +} + +/** + * Move the cursor down one line in the text region + */ +void cursor_down(void) { + /* If this isn't already the last line... */ + if (env->line_no < env->line_count) { + + /* Move the cursor down */ + env->line_no += 1; + + /* + * If the horizontal cursor position exceeds the width the new line, + * then move the cursor left to the extent of the new line. + * + * If we're in insert mode, we can go one cell beyond the end of the line + */ + if (env->col_no > env->lines[env->line_no-1]->actual + (env->mode == MODE_INSERT)) { + env->col_no = env->lines[env->line_no-1]->actual + (env->mode == MODE_INSERT); + if (env->col_no == 0) env->col_no = 1; + } + + /* + * If the screen was scrolled horizontally, unscroll it; + * if it will be scrolled on this line as well, that will + * be handled by place_cursor_actual + */ + int redraw = 0; + if (env->coffset != 0) { + env->coffset = 0; + redraw = 1; + } + + /* If we've scrolled past the bottom of the screen, scroll the screen */ + if (env->line_no > env->offset + global_config.term_height - global_config.bottom_size - 1 - global_config.cursor_padding) { + env->offset += 1; + + /* Tell terminal to scroll */ + if (global_config.can_scroll) { + shift_up(); + + /* A new line appears on screen at the bottom, draw it */ + int l = global_config.term_height - global_config.bottom_size - 1; + if (env->offset + l < env->line_count + 1) { + redraw_line(l-1, env->offset + l-1); + } else { + draw_excess_line(l - 1); + } + + /* Redraw elements that were moved by scrolling */ + redraw_tabbar(); + redraw_statusbar(); + redraw_commandline(); + place_cursor_actual(); + } else { + redraw_all(); + } + return; + } else if (redraw) { + /* Otherwise, if we need to redraw because of coffset change, do that */ + redraw_text(); + } + + /* Update the status bar */ + redraw_statusbar(); + + /* Place the terminal cursor again */ + place_cursor_actual(); + } +} + +/** + * Move the cursor up one line in the text region + */ +void cursor_up(void) { + /* If this isn't the first line already */ + if (env->line_no > 1) { + + /* Move the cursor down */ + env->line_no -= 1; + + /* + * If the horizontal cursor position exceeds the width the new line, + * then move the cursor left to the extent of the new line. + * + * If we're in insert mode, we can go one cell beyond the end of the line + */ + if (env->col_no > env->lines[env->line_no-1]->actual + (env->mode == MODE_INSERT)) { + env->col_no = env->lines[env->line_no-1]->actual + (env->mode == MODE_INSERT); + if (env->col_no == 0) env->col_no = 1; + } + + /* + * If the screen was scrolled horizontally, unscroll it; + * if it will be scrolled on this line as well, that will + * be handled by place_cursor_actual + */ + int redraw = 0; + if (env->coffset != 0) { + env->coffset = 0; + redraw = 1; + } + + int e = (env->offset == 0) ? env->offset : env->offset + global_config.cursor_padding; + if (env->line_no <= e) { + env->offset -= 1; + + /* Tell terminal to scroll */ + if (global_config.can_scroll) { + shift_down(); + + /* + * The line at the top of the screen should always be real + * so we can just call redraw_line here + */ + redraw_line(0,env->offset); + + /* Redraw elements that were moved by scrolling */ + redraw_tabbar(); + redraw_statusbar(); + redraw_commandline(); + place_cursor_actual(); + } else { + redraw_all(); + } + return; + } else if (redraw) { + /* Otherwise, if we need to redraw because of coffset change, do that */ + redraw_text(); + } + + /* Update the status bar */ + redraw_statusbar(); + + /* Place the terminal cursor again */ + place_cursor_actual(); + } +} + +/** + * Move the cursor one column left. + */ +void cursor_left(void) { + if (env->col_no > 1) { + env->col_no -= 1; + + /* Update the status bar */ + redraw_statusbar(); + + /* Place the terminal cursor again */ + place_cursor_actual(); + } +} + +/** + * Move the cursor one column right. + */ +void cursor_right(void) { + + /* If this isn't already the rightmost column we can reach on this line in this mode... */ + if (env->col_no < env->lines[env->line_no-1]->actual + !!(env->mode == MODE_INSERT)) { + env->col_no += 1; + + /* Update the status bar */ + redraw_statusbar(); + + /* Place the terminal cursor again */ + place_cursor_actual(); + } +} + +/** + * Move the cursor to the fron the of the line + */ +void cursor_home(void) { + env->col_no = 1; + + /* Update the status bar */ + redraw_statusbar(); + + /* Place the terminal cursor again */ + place_cursor_actual(); +} + +/** + * Move the cursor to the end of the line. + * + * In INSERT mode, moves one cell right of the end of the line. + * In NORMAL mode, moves the cursor to the last occupied cell. + */ +void cursor_end(void) { + env->col_no = env->lines[env->line_no-1]->actual+!!(env->mode == MODE_INSERT); + + /* Update the status bar */ + redraw_statusbar(); + + /* Place the terminal cursor again */ + place_cursor_actual(); +} + +/** + * Leave INSERT mode + * + * If the cursor is too far right, adjust it. + * Redraw the command line. + */ +void leave_insert(void) { + if (env->col_no > env->lines[env->line_no-1]->actual) { + env->col_no = env->lines[env->line_no-1]->actual; + if (env->col_no == 0) env->col_no = 1; + } + set_history_break(); + env->mode = MODE_NORMAL; + redraw_commandline(); +} + +/** + * Process a user command. + */ +void process_command(char * cmd) { + /* Special case ! to run shell commands without parsing tokens */ + if (*cmd == '!') { + /* Reset and draw some line feeds */ + reset(); + printf("\n\n"); + + /* Set buffered for shell application */ + set_buffered(); + + /* Call the shell and wait for completion */ + system(&cmd[1]); + + /* Return to the editor, wait for user to press enter. */ + set_unbuffered(); + printf("\n\nPress ENTER to continue."); + fflush(stdout); + while (bim_getch() != ENTER_KEY); + + /* Redraw the screen */ + redraw_all(); + + /* Done processing command */ + return; + } + + /* Tokenize argument string on spaces */ + char *p, *argv[512], *last; + int argc = 0; + for ((p = strtok_r(cmd, " ", &last)); p; + (p = strtok_r(NULL, " ", &last)), argc++) { + if (argc < 511) argv[argc] = p; + } + argv[argc] = NULL; + + if (argc < 1) { + /* no op */ + return; + } + + if (!strcmp(argv[0], "e")) { + /* e: edit file */ + if (argc > 1) { + /* This actually opens a new tab */ + open_file(argv[1]); + update_title(); + goto_line(0); + } else { + /* TODO: Reopen file? */ + render_error("Expected a file to open..."); + } + } else if (!strcmp(argv[0], "tabnew")) { + if (argc > 1) { + open_file(argv[1]); + update_title(); + goto_line(0); + } else { + env = buffer_new(); + setup_buffer(env); + redraw_all(); + update_title(); + } + } else if (!strcmp(argv[0], "w")) { + /* w: write file */ + if (argc > 1) { + write_file(argv[1]); + } else { + write_file(env->file_name); + } + } else if (!strcmp(argv[0], "wq")) { + /* wq: write file and close buffer; if there's no file to write to, may do weird things */ + write_file(env->file_name); + close_buffer(); + } else if (!strcmp(argv[0], "q")) { + /* close buffer if unmodified */ + if (env->modified) { + render_error("No write since last change. Use :q! to force exit."); + } else { + close_buffer(); + } + } else if (!strcmp(argv[0], "q!")) { + /* close buffer without warning if unmodified */ + close_buffer(); + } else if (!strcmp(argv[0], "qa") || !strcmp(argv[0], "qall")) { + /* Close all */ + try_quit(); + } else if (!strcmp(argv[0], "qa!")) { + /* Forcefully exit editor */ + quit(); + } else if (!strcmp(argv[0], "tabp")) { + /* Next tab */ + previous_tab(); + update_title(); + } else if (!strcmp(argv[0], "tabn")) { + /* Previous tab */ + next_tab(); + update_title(); + } else if (!strcmp(argv[0], "indent")) { + env->indent = 1; + redraw_statusbar(); + } else if (!strcmp(argv[0], "noindent")) { + env->indent = 0; + redraw_statusbar(); + } else if (!strcmp(argv[0], "noh")) { + if (env->search) { + free(env->search); + env->search = NULL; + redraw_text(); + } + } else if (!strcmp(argv[0], "help")) { + /* + * The repeated calls to redraw_commandline here make use + * of scrolling to draw this multiline help message on + * the same background as the command line. + */ + render_commandline_message(""); /* To clear command line */ + render_commandline_message("\n"); + render_commandline_message(" \033[1mbim - The standard ToaruOS Text Editor\033[22m\n"); + render_commandline_message("\n"); + render_commandline_message(" Available commands:\n"); + render_commandline_message(" Quit with \033[3m:q\033[23m, \033[3m:qa\033[23m, \033[3m:q!\033[23m, \033[3m:qa!\033[23m\n"); + render_commandline_message(" Write out with \033[3m:w \033[4mfile\033[24;23m\n"); + render_commandline_message(" Set syntax with \033[3m:syntax \033[4mlanguage\033[24;23m\n"); + render_commandline_message(" Open a new tab with \033[3m:e \033[4mpath/to/file\033[24;23m\n"); + render_commandline_message(" \033[3m:tabn\033[23m and \033[3m:tabp\033[23m can be used to switch tabs\n"); + render_commandline_message(" Set the color scheme with \033[3m:theme \033[4mtheme\033[24;23m\n"); + render_commandline_message(" Set the behavior of the tab key with \033[3m:tabs\033[23m or \033[3m:spaces\033[23m\n"); + render_commandline_message(" Set tabstop with \033[3m:tabstop \033[4mwidth\033[24;23m\n"); + render_commandline_message("\n"); + render_commandline_message(" %s\n", BIM_COPYRIGHT); + render_commandline_message("\n"); + /* Redrawing the tabbar makes it look like we just shifted the whole view up */ + redraw_tabbar(); + redraw_commandline(); + fflush(stdout); + /* Wait for a character so we can redraw the screen before continuing */ + int c; + while ((c = bim_getch())== -1); + /* Make sure that key press actually gets used */ + bim_unget(c); + /* + * Redraw everything to hide the help message and get the + * upper few lines of text on screen again + */ + redraw_all(); + } else if (!strcmp(argv[0], "theme")) { + if (argc < 2) { + render_status_message("theme=%s", current_theme); + return; + } + for (struct theme_def * d = themes; d->name; ++d) { + if (!strcmp(argv[1], d->name)) { + d->load(); + redraw_all(); + return; + } + } + } else if (!strcmp(argv[0], "syntax")) { + if (argc < 2) { + render_status_message("syntax=%s", env->syntax ? env->syntax->name : "none"); + return; + } + if (!strcmp(argv[1],"none")) { + for (int i = 0; i < env->line_count; ++i) { + env->lines[i]->istate = 0; + for (int j = 0; j < env->lines[i]->actual; ++j) { + env->lines[i]->text[j].flags = 0; + } + } + redraw_all(); + return; + } + for (struct syntax_definition * s = syntaxes; s->name; ++s) { + if (!strcmp(argv[1],s->name)) { + env->syntax = s; + for (int i = 0; i < env->line_count; ++i) { + env->lines[i]->istate = 0; + } + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + redraw_all(); + return; + } + } + render_error("unrecognized syntax type"); + } else if (!strcmp(argv[0], "recalc")) { + for (int i = 0; i < env->line_count; ++i) { + env->lines[i]->istate = 0; + } + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + redraw_all(); + } else if (!strcmp(argv[0], "tabs")) { + env->tabs = 1; + redraw_statusbar(); + } else if (!strcmp(argv[0], "spaces")) { + env->tabs = 0; + redraw_statusbar(); + } else if (!strcmp(argv[0], "tabstop")) { + if (argc < 2) { + render_status_message("tabstop=%d", env->tabstop); + } else { + int t = atoi(argv[1]); + if (t > 0 && t < 32) { + env->tabstop = t; + for (int i = 0; i < env->line_count; ++i) { + recalculate_tabs(env->lines[i]); + } + redraw_all(); + } else { + render_error("Invalid tabstop: %s", argv[1]); + } + } + } else if (!strcmp(argv[0], "clearyank")) { + if (global_config.yanks) { + for (unsigned int i = 0; i < global_config.yank_count; ++i) { + free(global_config.yanks[i]); + } + free(global_config.yanks); + global_config.yanks = NULL; + global_config.yank_count = 0; + redraw_statusbar(); + } + } else if (!strcmp(argv[0], "padding")) { + if (argc < 2) { + render_status_message("padding=%d", global_config.cursor_padding); + } else { + global_config.cursor_padding = atoi(argv[1]); + place_cursor_actual(); + } + } else if (isdigit(*argv[0])) { + /* Go to line number */ + goto_line(atoi(argv[0])); + } else { + /* Unrecognized command */ + render_error("Not an editor command: %s", argv[0]); + } +} + +/** + * Tab completion for command mode. + */ +void command_tab_complete(char * buffer) { + /* Figure out which argument this is and where it starts */ + int arg = 0; + char * buf = strdup(buffer); + char * b = buf; + + char * args[32]; + + int candidate_count= 0; + int candidate_space = 4; + char ** candidates = malloc(sizeof(char*)*candidate_space); + + /* Accept whitespace before first argument */ + while (*b == ' ') b++; + char * start = b; + args[0] = start; + while (*b && *b != ' ') b++; + while (*b) { + while (*b == ' ') { + *b = '\0'; + b++; + } + start = b; + arg++; + if (arg < 32) { + args[arg] = start; + } + while (*b && *b != ' ') b++; + } + + /** + * Check a possible candidate and add it to the + * candidates list, expanding as necessary, + * if it matches for the current argument. + */ +#define add_candidate(candidate) \ + do { \ + char * _arg = args[arg]; \ + int r = strncmp(_arg, candidate, strlen(_arg)); \ + if (!r) { \ + if (candidate_count == candidate_space) { \ + candidate_space *= 2; \ + candidates = realloc(candidates,sizeof(char *) * candidate_space); \ + } \ + candidates[candidate_count] = strdup(candidate); \ + candidate_count++; \ + } \ + } while (0) + + if (arg == 0) { + /* Complete command names */ + add_candidate("help"); + add_candidate("recalc"); + add_candidate("syntax"); + add_candidate("tabn"); + add_candidate("tabp"); + add_candidate("tabnew"); + add_candidate("theme"); + add_candidate("tabs"); + add_candidate("tabstop"); + add_candidate("spaces"); + add_candidate("noh"); + add_candidate("clearyank"); + add_candidate("indent"); + add_candidate("noindent"); + add_candidate("padding"); + goto _accept_candidate; + } + + if (arg == 1 && !strcmp(args[0], "syntax")) { + /* Complete syntax options */ + add_candidate("none"); + for (struct syntax_definition * s = syntaxes; s->name; ++s) { + add_candidate(s->name); + } + goto _accept_candidate; + } + + if (arg == 1 && !strcmp(args[0], "theme")) { + /* Complete color theme names */ + for (struct theme_def * s = themes; s->name; ++s) { + add_candidate(s->name); + } + goto _accept_candidate; + } + + if (arg == 1 && (!strcmp(args[0], "e") || !strcmp(args[0], "tabnew"))) { + /* Complete file paths */ + + /* First, find the deepest directory match */ + char * tmp = strdup(args[arg]); + char * last_slash = strrchr(tmp, '/'); + DIR * dirp; + if (last_slash) { + *last_slash = '\0'; + if (last_slash == tmp) { + /* Started with slash, and it was the only slash */ + dirp = opendir("/"); + } else { + dirp = opendir(tmp); + } + } else { + /* No directory match, completing from current directory */ + dirp = opendir("."); + tmp[0] = '\0'; + } + + if (!dirp) { + /* Directory match doesn't exist, no candidates to populate */ + free(tmp); + goto done; + } + + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (ent->d_name[0] != '.' || (last_slash ? (last_slash[1] == '.') : (tmp[0] == '.'))) { + struct stat statbuf; + /* Figure out if this file is a directory */ + if (last_slash) { + char * x = malloc(strlen(tmp) + 1 + strlen(ent->d_name) + 1); + snprintf(x, strlen(tmp) + 1 + strlen(ent->d_name) + 1, "%s/%s",tmp,ent->d_name); + stat(x, &statbuf); + free(x); + } else { + stat(ent->d_name, &statbuf); + } + + /* Build the complete argument name to tab complete */ + char s[1024] = {0}; + if (last_slash == tmp) { + strcat(s,"/"); + } else if (*tmp) { + strcat(s,tmp); + strcat(s,"/"); + } + strcat(s,ent->d_name); + /* + * If it is a directory, add a / to the end so the next completion + * attempt will complete the directory's contents. + */ + if (S_ISDIR(statbuf.st_mode)) { + strcat(s,"/"); + } + add_candidate(s); + } + ent = readdir(dirp); + } + closedir(dirp); + free(tmp); + goto _accept_candidate; + } + +_accept_candidate: + if (candidate_count == 0) { + redraw_statusbar(); + goto done; + } + + if (candidate_count == 1) { + /* Only one completion possibility */ + redraw_statusbar(); + + /* Fill out the rest of the command */ + char * cstart = (buffer) + (start - buf); + for (unsigned int i = 0; i < strlen(candidates[0]); ++i) { + *cstart = candidates[0][i]; + cstart++; + } + *cstart = '\0'; + } else { + /* Print candidates in status bar */ + char tmp[global_config.term_width+1]; + memset(tmp, 0, global_config.term_width+1); + int offset = 0; + for (int i = 0; i < candidate_count; ++i) { + if (offset + 1 + (signed)strlen(candidates[i]) > global_config.term_width - 5) { + strcat(tmp, "..."); + break; + } + if (offset > 0) { + strcat(tmp, " "); + offset++; + } + strcat(tmp, candidates[i]); + offset += strlen(candidates[i]); + } + render_status_message("%s", tmp); + + /* Complete to longest common substring */ + char * cstart = (buffer) + (start - buf); + for (int i = 0; i < 1023 /* max length of command */; i++) { + for (int j = 1; j < candidate_count; ++j) { + if (candidates[0][i] != candidates[j][i]) goto _reject; + } + *cstart = candidates[0][i]; + cstart++; + } + /* End of longest common substring */ +_reject: + *cstart = '\0'; + } + + /* Free candidates */ + for (int i = 0; i < candidate_count; ++i) { + free(candidates[i]); + } + + /* Redraw command line */ +done: + redraw_commandline(); + printf(":%s", buffer); + + free(candidates); + free(buf); +} + +/** + * Command mode + * + * Accept a user command and then process it and + * return to normal mode. + * + * TODO: We only have basic line editing here; it might be + * nice to add more advanced line editing, like cursor + * movement, tab completion, etc. This is easier than + * with the shell since we have a lot more control over + * where the command input bar is rendered. + */ +void command_mode(void) { + int c; + char buffer[1024] = {0}; + int buffer_len = 0; + + redraw_commandline(); + printf(":"); + show_cursor(); + + while ((c = bim_getch())) { + if (c == -1) { + /* Time out */ + continue; + } + if (c == '\033') { + /* Escape, cancel command */ + break; + } else if (c == ENTER_KEY) { + /* Enter, run command */ + process_command(buffer); + break; + } else if (c == '\t') { + /* Handle tab completion */ + command_tab_complete(buffer); + buffer_len = strlen(buffer); + } else if (c == BACKSPACE_KEY || c == DELETE_KEY) { + /* Backspace, delete last character in command buffer */ + if (buffer_len > 0) { + buffer_len -= 1; + buffer[buffer_len] = '\0'; + redraw_commandline(); + printf(":%s", buffer); + } else { + /* If backspaced through entire command, cancel command mode */ + redraw_commandline(); + break; + } + } else { + /* Regular character */ + buffer[buffer_len] = c; + buffer_len++; + printf("%c", c); + } + show_cursor(); + } +} + +/** + * Search forward from the given cursor position + * to find a basic search match. + * + * This could be more complicated... + */ +void find_match(int from_line, int from_col, int * out_line, int * out_col, uint32_t * str) { + int col = from_col; + for (int i = from_line; i <= env->line_count; ++i) { + line_t * line = env->lines[i - 1]; + + int j = col - 1; + while (j < line->actual + 1) { + int k = j; + uint32_t * match = str; + while (k < line->actual + 1) { + if (*match == '\0') { + *out_line = i; + *out_col = j + 1; + return; + } + /* TODO search for UTF-8 sequences? */ + if (*match != line->text[k].codepoint) break; + match++; + k++; + } + j++; + } + col = 0; + } +} + +/** + * Search backwards for matching string. + */ +void find_match_backwards(int from_line, int from_col, int * out_line, int * out_col, uint32_t * str) { + int col = from_col; + for (int i = from_line; i >= 1; --i) { + line_t * line = env->lines[i-1]; + + int j = col - 1; + while (j > -1) { + int k = j; + uint32_t * match = str; + while (k < line->actual + 1) { + if (*match == '\0') { + *out_line = i; + *out_col = j + 1; + return; + } + /* TODO search for UTF-8 sequences? */ + if (*match != line->text[k].codepoint) break; + match++; + k++; + } + j--; + } + col = (i > 1) ? (env->lines[i-2]->actual) : -1; + } + +} + +/** + * Draw the matched search result. + */ +void draw_search_match(int line, uint32_t * buffer, int redraw_buffer) { + place_cursor_actual(); + redraw_text(); + if (line != -1) { + /* + * TODO this should probably mark the relevant + * regions so that redraw_text can hilight it + */ + set_colors(COLOR_SEARCH_FG, COLOR_SEARCH_BG); + place_cursor_actual(); + + uint32_t * c = buffer; + while (*c) { + char tmp[7] = {0}; /* Max six bytes, use 7 to ensure last is always nil */ + to_eight(*c, tmp); + printf("%s", tmp); + c++; + } + } + redraw_statusbar(); + redraw_commandline(); + if (redraw_buffer != -1) { + printf(redraw_buffer == 1 ? "/" : "?"); + uint32_t * c = buffer; + while (*c) { + char tmp[7] = {0}; /* Max six bytes, use 7 to ensure last is always nil */ + to_eight(*c, tmp); + printf("%s", tmp); + c++; + } + } +} + +/** + * Search mode + * + * Search text for substring match. + */ +void search_mode(int direction) { + uint32_t c; + uint32_t buffer[1024] = {0}; + int buffer_len = 0; + + /* utf-8 decoding */ + + /* Remember where the cursor is so we can cancel */ + int prev_line = env->line_no; + int prev_col = env->col_no; + int prev_coffset = env->coffset; + int prev_offset = env->offset; + + redraw_commandline(); + printf(direction == 1 ? "/" : "?"); + show_cursor(); + + uint32_t state = 0; + int cin; + + while ((cin = bim_getch())) { + if (cin == -1) { + /* Time out */ + continue; + } + if (!decode(&state, &c, cin)) { + if (c == '\033') { + /* Cancel search */ + env->line_no = prev_line; + env->col_no = prev_col; + redraw_all(); + break; + } else if (c == ENTER_KEY) { + /* Exit search */ + if (env->search) { + free(env->search); + } + env->search = malloc((buffer_len + 1) * sizeof(uint32_t)); + memcpy(env->search, buffer, (buffer_len + 1) * sizeof(uint32_t)); + break; + } else if (c == BACKSPACE_KEY || c == DELETE_KEY) { + /* Backspace, delete last character in search buffer */ + if (buffer_len > 0) { + buffer_len -= 1; + buffer[buffer_len] = '\0'; + /* Search from beginning to find first match */ + int line = -1, col = -1; + if (direction == 1) { + find_match(prev_line, prev_col, &line, &col, buffer); + } else { + find_match_backwards(prev_line, prev_col, &line, &col, buffer); + } + + if (line != -1) { + env->col_no = col; + env->line_no = line; + } + + draw_search_match(line, buffer, direction); + + } else { + /* If backspaced through entire search term, cancel search */ + redraw_commandline(); + env->coffset = prev_coffset; + env->offset = prev_offset; + env->col_no = prev_col; + env->line_no = prev_line; + redraw_all(); + break; + } + } else { + /* Regular character */ + buffer[buffer_len] = c; + buffer_len++; + buffer[buffer_len] = '\0'; + char tmp[7] = {0}; /* Max six bytes, use 7 to ensure last is always nil */ + to_eight(c, tmp); + printf("%s", tmp); + + /* Find the next search match */ + int line = -1, col = -1; + if (direction == 1) { + find_match(prev_line, prev_col, &line, &col, buffer); + } else { + find_match_backwards(prev_line, prev_col, &line, &col, buffer); + } + + if (line != -1) { + env->col_no = col; + env->line_no = line; + } else { + env->coffset = prev_coffset; + env->offset = prev_offset; + env->col_no = prev_col; + env->line_no = prev_line; + } + draw_search_match(line, buffer, direction); + } + show_cursor(); + } else if (state == UTF8_REJECT) { + state = 0; + } + } +} + +/** + * Find the next search result, or loop back around if at the end. + */ +void search_next(void) { + if (!env->search) return; + int line = -1, col = -1; + find_match(env->line_no, env->col_no+1, &line, &col, env->search); + + if (line == -1) { + find_match(1,1, &line, &col, env->search); + if (line == -1) return; + } + + env->col_no = col; + env->line_no = line; + draw_search_match(line, env->search, -1); +} + +/** + * Find the previous search result, or loop to the end of the file. + */ +void search_prev(void) { + if (!env->search) return; + int line = -1, col = -1; + find_match_backwards(env->line_no, env->col_no-1, &line, &col, env->search); + + if (line == -1) { + find_match_backwards(env->line_count, env->lines[env->line_count-1]->actual, &line, &col, env->search); + if (line == -1) return; + } + + env->col_no = col; + env->line_no = line; + draw_search_match(line, env->search, -1); +} + +/** + * Find the matching paren for this one. + * + * This approach skips having to do its own syntax parsing + * to deal with, eg., erroneous parens in comments. It does + * this by finding the matching paren with the same flag + * value, thus parens in strings will match, parens outside + * of strings will match, but parens in strings won't + * match parens outside of strings and so on. + */ +void find_matching_paren(void) { + if (env->col_no > env->lines[env->line_no-1]->actual) { + return; /* Invalid cursor position */ + } + + /* TODO: vim can find the nearest paren to start searching from, we need to be on one right now */ + + int paren_match = 0; + int direction = 0; + int start = env->lines[env->line_no-1]->text[env->col_no-1].codepoint; + int flags = env->lines[env->line_no-1]->text[env->col_no-1].flags; + int count = 0; + + /* TODO what about unicode parens? */ + char * p = "()[]{}<>"; + for (int i = 0; p[i]; ++i) { + if (start == p[i]) { + direction = (i % 2 == 0) ? 1 : -1; + paren_match = p[(i % 2 == 0) ? (i+1) : (i-1)]; + break; + } + } + + if (!paren_match) return; + + /* Scan for match */ + int line = env->line_no; + int col = env->col_no; + + do { + while (col > 0 && col < env->lines[line-1]->actual + 1) { + /* Only match on same syntax */ + if (env->lines[line-1]->text[col-1].flags == flags) { + /* Count up on same direction */ + if (env->lines[line-1]->text[col-1].codepoint == start) count++; + /* Count down on opposite direction */ + if (env->lines[line-1]->text[col-1].codepoint == paren_match) { + count--; + /* When count == 0 we have a match */ + if (count == 0) goto _match_found; + } + } + col += direction; + } + + line += direction; + + /* Reached first/last line with no match */ + if (line == 0 || line == env->line_count + 1) { + return; + } + + /* Reset column to start/end of line, depending on direction */ + if (direction > 0) { + col = 1; + } else { + col = env->lines[line-1]->actual; + } + } while (1); + +_match_found: + env->line_no = line; + env->col_no = col; + place_cursor_actual(); +} + +/** + * Handle mouse event + */ +void handle_mouse(void) { + int buttons = bim_getch() - 32; + int x = bim_getch() - 32; + int y = bim_getch() - 32; + + if (buttons == 64) { + /* Scroll up */ + for (int i = 0; i < 5; ++i) { + cursor_up(); + } + return; + } else if (buttons == 65) { + /* Scroll down */ + for (int i = 0; i < 5; ++i) { + cursor_down(); + } + return; + } else if (buttons == 3) { + /* Move cursor to position */ + + if (x < 0) return; + if (y < 0) return; + + if (y == 1) { + /* Pick from tabs */ + int _x = 0; + for (int i = 0; i < buffers_len; i++) { + buffer_t * _env = buffers[i]; + if (_env->modified) { + _x += 2; + } + if (_env->file_name) { + _x += 2 + strlen(_env->file_name); + } else { + _x += strlen(" [No Name] "); + } + if (_x > x) { + env = buffers[i]; + redraw_all(); + return; + } + } + return; + } + + /* Figure out y coordinate */ + int line_no = y + env->offset - 1; + int col_no = -1; + + if (line_no > env->line_count) { + line_no = env->line_count; + } + + /* Account for the left hand gutter */ + int num_size = num_width() + 3; + int _x = num_size - (line_no == env->line_no ? env->coffset : 0); + + /* Determine where the cursor is physically */ + for (int i = 0; i < env->lines[line_no-1]->actual; ++i) { + char_t * c = &env->lines[line_no-1]->text[i]; + _x += c->display_width; + if (_x > x-1) { + col_no = i+1; + break; + } + } + + if (col_no == -1 || col_no > env->lines[line_no-1]->actual) { + col_no = env->lines[line_no-1]->actual; + } + + env->line_no = line_no; + env->col_no = col_no; + place_cursor_actual(); + } + return; +} + +/** + * Append a character at the current cursor point. + */ +void insert_char(unsigned int c) { + if (!c) { + render_error("Inserted nil byte?"); + return; + } + char_t _c; + _c.codepoint = c; + _c.flags = 0; + _c.display_width = codepoint_width(c); + line_t * line = env->lines[env->line_no - 1]; + line_t * nline = line_insert(line, _c, env->col_no - 1, env->line_no - 1); + if (line != nline) { + env->lines[env->line_no - 1] = nline; + } + env->col_no += 1; + set_modified(); +} + +/** + * Replace a single character at the current cursor point + */ +void replace_char(unsigned int c) { + if (env->col_no < 1 || env->col_no > env->lines[env->line_no-1]->actual) return; + + char_t _c; + _c.codepoint = c; + _c.flags = 0; + _c.display_width = codepoint_width(c); + + line_replace(env->lines[env->line_no-1], _c, env->col_no-1, env->line_no-1); + + redraw_line(env->line_no - env->offset - 1, env->line_no-1); + set_modified(); +} + +/** + * Undo a history entry. + */ +void undo_history(void) { + if (!global_config.history_enabled) return; + + env->loading = 1; + history_t * e = env->history; + + if (e->type == HISTORY_SENTINEL) { + env->loading = 0; + render_commandline_message("Already at oldest change"); + return; + } + + int count_chars = 0; + int count_lines = 0; + + do { + if (e->type == HISTORY_SENTINEL) break; + + switch (e->type) { + case HISTORY_INSERT: + /* Delete */ + line_delete( + env->lines[e->insert_delete_replace.lineno], + e->insert_delete_replace.offset+1, + e->insert_delete_replace.lineno + ); + env->line_no = e->insert_delete_replace.lineno + 1; + env->col_no = e->insert_delete_replace.offset + 1; + count_chars++; + break; + case HISTORY_DELETE: + { + char_t _c = {codepoint_width(e->insert_delete_replace.old_codepoint),0,e->insert_delete_replace.old_codepoint}; + env->lines[e->insert_delete_replace.lineno] = line_insert( + env->lines[e->insert_delete_replace.lineno], + _c, + e->insert_delete_replace.offset-1, + e->insert_delete_replace.lineno + ); + } + env->line_no = e->insert_delete_replace.lineno + 1; + env->col_no = e->insert_delete_replace.offset + 2; + count_chars++; + break; + case HISTORY_REPLACE: + { + char_t _o = {codepoint_width(e->insert_delete_replace.old_codepoint),0,e->insert_delete_replace.old_codepoint}; + line_replace( + env->lines[e->insert_delete_replace.lineno], + _o, + e->insert_delete_replace.offset, + e->insert_delete_replace.lineno + ); + } + env->line_no = e->insert_delete_replace.lineno + 1; + env->col_no = e->insert_delete_replace.offset + 1; + count_chars++; + break; + case HISTORY_REMOVE_LINE: + env->lines = add_line(env->lines, e->remove_replace_line.lineno); + replace_line(env->lines, e->remove_replace_line.lineno, e->remove_replace_line.old_contents); + env->line_no = e->remove_replace_line.lineno + 2; + env->col_no = 1; + count_lines++; + break; + case HISTORY_ADD_LINE: + env->lines = remove_line(env->lines, e->add_merge_split_lines.lineno); + env->line_no = e->add_merge_split_lines.lineno + 1; + env->col_no = 1; + count_lines++; + break; + case HISTORY_REPLACE_LINE: + replace_line(env->lines, e->remove_replace_line.lineno, e->remove_replace_line.old_contents); + env->line_no = e->remove_replace_line.lineno + 1; + env->col_no = 1; + count_lines++; + break; + case HISTORY_SPLIT_LINE: + env->lines = merge_lines(env->lines, e->add_merge_split_lines.lineno+1); + env->line_no = e->add_merge_split_lines.lineno + 2; + env->col_no = 1; + count_lines++; + break; + case HISTORY_MERGE_LINES: + env->lines = split_line(env->lines, e->add_merge_split_lines.lineno-1, e->add_merge_split_lines.split); + env->line_no = e->add_merge_split_lines.lineno; + env->col_no = 1; + count_lines++; + break; + case HISTORY_BREAK: + /* Ignore break */ + break; + default: + render_error("Unknown type %d!\n", e->type); + break; + } + + env->history = e->previous; + e = env->history; + } while (e->type != HISTORY_BREAK); + + if (env->line_no > env->line_count) env->line_no = env->line_count; + if (env->col_no > env->lines[env->line_no-1]->actual) env->col_no = env->lines[env->line_no-1]->actual; + + env->modified = (env->history != env->last_save_history); + + env->loading = 0; + + for (int i = 0; i < env->line_count; ++i) { + env->lines[i]->istate = 0; + recalculate_tabs(env->lines[i]); + } + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + place_cursor_actual(); + update_title(); + redraw_all(); + render_commandline_message("%d character%s, %d line%s changed", + count_chars, (count_chars == 1) ? "" : "s", + count_lines, (count_lines == 1) ? "" : "s"); +} + +/** + * Replay a history entry. + */ +void redo_history(void) { + if (!global_config.history_enabled) return; + + env->loading = 1; + history_t * e = env->history->next; + + if (!e) { + env->loading = 0; + render_commandline_message("Already at newest change"); + return; + } + + int count_chars = 0; + int count_lines = 0; + + while (e) { + if (e->type == HISTORY_BREAK) { + env->history = e; + break; + } + + switch (e->type) { + case HISTORY_INSERT: + { + char_t _c = {codepoint_width(e->insert_delete_replace.codepoint),0,e->insert_delete_replace.codepoint}; + env->lines[e->insert_delete_replace.lineno] = line_insert( + env->lines[e->insert_delete_replace.lineno], + _c, + e->insert_delete_replace.offset, + e->insert_delete_replace.lineno + ); + } + env->line_no = e->insert_delete_replace.lineno + 1; + env->col_no = e->insert_delete_replace.offset + 2; + count_chars++; + break; + case HISTORY_DELETE: + /* Delete */ + line_delete( + env->lines[e->insert_delete_replace.lineno], + e->insert_delete_replace.offset, + e->insert_delete_replace.lineno + ); + env->line_no = e->insert_delete_replace.lineno + 1; + env->col_no = e->insert_delete_replace.offset + 1; + count_chars++; + break; + case HISTORY_REPLACE: + { + char_t _o = {codepoint_width(e->insert_delete_replace.codepoint),0,e->insert_delete_replace.codepoint}; + line_replace( + env->lines[e->insert_delete_replace.lineno], + _o, + e->insert_delete_replace.offset, + e->insert_delete_replace.lineno + ); + } + env->line_no = e->insert_delete_replace.lineno + 1; + env->col_no = e->insert_delete_replace.offset + 2; + count_chars++; + break; + case HISTORY_ADD_LINE: + env->lines = add_line(env->lines, e->remove_replace_line.lineno); + env->line_no = e->remove_replace_line.lineno + 2; + env->col_no = 1; + count_lines++; + break; + case HISTORY_REMOVE_LINE: + env->lines = remove_line(env->lines, e->remove_replace_line.lineno); + env->line_no = e->add_merge_split_lines.lineno + 1; + env->col_no = 1; + count_lines++; + break; + case HISTORY_REPLACE_LINE: + replace_line(env->lines, e->remove_replace_line.lineno, e->remove_replace_line.contents); + env->line_no = e->remove_replace_line.lineno + 2; + env->col_no = 1; + count_lines++; + break; + case HISTORY_MERGE_LINES: + env->lines = merge_lines(env->lines, e->add_merge_split_lines.lineno); + env->line_no = e->remove_replace_line.lineno + 1; + env->col_no = 1; + count_lines++; + break; + case HISTORY_SPLIT_LINE: + env->lines = split_line(env->lines, e->add_merge_split_lines.lineno, e->add_merge_split_lines.split); + env->line_no = e->remove_replace_line.lineno + 2; + env->col_no = 1; + count_lines++; + break; + case HISTORY_BREAK: + /* Ignore break */ + break; + default: + render_error("Unknown type %d!\n", e->type); + break; + } + + env->history = e; + e = e->next; + } + + if (env->line_no > env->line_count) env->line_no = env->line_count; + if (env->col_no > env->lines[env->line_no-1]->actual) env->col_no = env->lines[env->line_no-1]->actual; + + env->modified = (env->history != env->last_save_history); + + env->loading = 0; + + for (int i = 0; i < env->line_count; ++i) { + env->lines[i]->istate = 0; + recalculate_tabs(env->lines[i]); + } + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + place_cursor_actual(); + update_title(); + redraw_all(); + render_commandline_message("%d character%s, %d line%s changed", + count_chars, (count_chars == 1) ? "" : "s", + count_lines, (count_lines == 1) ? "" : "s"); +} + +/** + * Move the cursor the start of the previous word. + */ +void word_left(void) { + int line_no = env->line_no; + int col_no = env->col_no; + + do { + col_no--; + if (col_no == 0) { + line_no--; + if (line_no == 0) { + goto_line(1); + return; + } + col_no = env->lines[line_no-1]->actual + 1; + } + } while (isspace(env->lines[line_no-1]->text[col_no-1].codepoint)); + + do { + col_no--; + if (col_no == 0) { + line_no--; + if (line_no == 0) { + goto_line(1); + return; + } + col_no = env->lines[line_no-1]->actual + 1; + } + if (col_no == 1) { + env->col_no = 1; + env->line_no = line_no; + redraw_statusbar(); + place_cursor_actual(); + return; + } + } while (!isspace(env->lines[line_no-1]->text[col_no-1].codepoint)); + + env->col_no = col_no; + env->line_no = line_no; + cursor_right(); +} + +/** + * Word right + */ +void word_right(void) { + int line_no = env->line_no; + int col_no = env->col_no; + + do { + col_no++; + if (col_no >= env->lines[line_no-1]->actual + 1) { + line_no++; + if (line_no >= env->line_count) { + env->col_no = env->lines[env->line_count-1]->actual; + env->line_no = env->line_count; + redraw_statusbar(); + place_cursor_actual(); + return; + } + col_no = 0; + break; + } + } while (!isspace(env->lines[line_no-1]->text[col_no-1].codepoint)); + + do { + col_no++; + if (col_no >= env->lines[line_no-1]->actual + 1) { + line_no++; + if (line_no >= env->line_count) { + env->col_no = env->lines[env->line_count-1]->actual; + env->line_no = env->line_count; + redraw_statusbar(); + place_cursor_actual(); + return; + } + col_no = 1; + break; + } + } while (isspace(env->lines[line_no-1]->text[col_no-1].codepoint)); + + env->col_no = col_no; + env->line_no = line_no; + redraw_statusbar(); + place_cursor_actual(); + return; +} + +/** + * Backspace from the current cursor position. + */ +void delete_at_cursor(void) { + if (env->col_no > 1) { + line_delete(env->lines[env->line_no - 1], env->col_no - 1, env->line_no - 1); + env->col_no -= 1; + if (env->coffset > 0) env->coffset--; + redraw_line(env->line_no - env->offset - 1, env->line_no-1); + set_modified(); + redraw_statusbar(); + place_cursor_actual(); + } else if (env->line_no > 1) { + int tmp = env->lines[env->line_no - 2]->actual; + merge_lines(env->lines, env->line_no - 1); + env->line_no -= 1; + env->col_no = tmp+1; + redraw_text(); + set_modified(); + redraw_statusbar(); + place_cursor_actual(); + } +} + +void delete_word(void) { + if (!env->lines[env->line_no-1]) return; + if (env->col_no > 1) { + + do { + if (env->col_no > 1) { + line_delete(env->lines[env->line_no - 1], env->col_no - 1, env->line_no - 1); + env->col_no -= 1; + if (env->coffset > 0) env->coffset--; + } + } while (env->col_no > 1 && env->lines[env->line_no - 1]->text[env->col_no - 2].codepoint != ' '); + + redraw_text(); + set_modified(); + redraw_statusbar(); + place_cursor_actual(); + } +} + +/** + * Break the current line in two at the current cursor position. + */ +void insert_line_feed(void) { + if (env->col_no == env->lines[env->line_no - 1]->actual + 1) { + env->lines = add_line(env->lines, env->line_no); + } else { + env->lines = split_line(env->lines, env->line_no-1, env->col_no - 1); + } + env->col_no = 1; + env->line_no += 1; + add_indent(env->line_no-1,env->line_no-2); + if (env->line_no > env->offset + global_config.term_height - global_config.bottom_size - 1) { + env->offset += 1; + } + set_modified(); +} + +/** + * Yank lines between line start and line end (which may be in either order) + */ +void yank_lines(int start, int end) { + if (global_config.yanks) { + for (unsigned int i = 0; i < global_config.yank_count; ++i) { + free(global_config.yanks[i]); + } + free(global_config.yanks); + } + int lines_to_yank; + int start_point; + if (start <= end) { + lines_to_yank = end - start + 1; + start_point = start - 1; + } else { + lines_to_yank = start - end + 1; + start_point = end - 1; + } + global_config.yanks = malloc(sizeof(line_t *) * lines_to_yank); + global_config.yank_count = lines_to_yank; + global_config.yank_is_full_lines = 1; + for (int i = 0; i < lines_to_yank; ++i) { + global_config.yanks[i] = malloc(sizeof(line_t) + sizeof(char_t) * (env->lines[start_point+i]->available)); + global_config.yanks[i]->available = env->lines[start_point+i]->available; + global_config.yanks[i]->actual = env->lines[start_point+i]->actual; + global_config.yanks[i]->istate = 0; + memcpy(&global_config.yanks[i]->text, &env->lines[start_point+i]->text, sizeof(char_t) * (env->lines[start_point+i]->actual)); + + for (int j = 0; j < global_config.yanks[i]->actual; ++j) { + global_config.yanks[i]->text[j].flags = 0; + } + } +} + +/** + * Helper to yank part of a line into a new yank line. + */ +void yank_partial_line(int yank_no, int line_no, int start_off, int count) { + global_config.yanks[yank_no] = malloc(sizeof(line_t) + sizeof(char_t) * (count + 1)); + global_config.yanks[yank_no]->available = count + 1; /* ensure extra space */ + global_config.yanks[yank_no]->actual = count; + global_config.yanks[yank_no]->istate = 0; + memcpy(&global_config.yanks[yank_no]->text, &env->lines[line_no]->text[start_off], sizeof(char_t) * count); + for (int i = 0; i < count; ++i) { + global_config.yanks[yank_no]->text[i].flags = 0; + } +} + +/** + * Yank text... + */ +void yank_text(int start_line, int start_col, int end_line, int end_col) { + if (global_config.yanks) { + for (unsigned int i = 0; i < global_config.yank_count; ++i) { + free(global_config.yanks[i]); + } + free(global_config.yanks); + } + int lines_to_yank = end_line - start_line + 1; + int start_point = start_line - 1; + global_config.yanks = malloc(sizeof(line_t *) * lines_to_yank); + global_config.yank_count = lines_to_yank; + global_config.yank_is_full_lines = 0; + if (lines_to_yank == 1) { + yank_partial_line(0, start_point, start_col - 1, (end_col - start_col + 1)); + } else { + yank_partial_line(0, start_point, start_col - 1, (env->lines[start_point]->actual - start_col + 1)); + /* Yank middle lines */ + for (int i = 1; i < lines_to_yank - 1; ++i) { + global_config.yanks[i] = malloc(sizeof(line_t) + sizeof(char_t) * (env->lines[start_point+i]->available)); + global_config.yanks[i]->available = env->lines[start_point+i]->available; + global_config.yanks[i]->actual = env->lines[start_point+i]->actual; + global_config.yanks[i]->istate = 0; + memcpy(&global_config.yanks[i]->text, &env->lines[start_point+i]->text, sizeof(char_t) * (env->lines[start_point+i]->actual)); + + for (int j = 0; j < global_config.yanks[i]->actual; ++j) { + global_config.yanks[i]->text[j].flags = 0; + } + } + /* Yank end line */ + yank_partial_line(lines_to_yank-1, end_line - 1, 0, end_col); + } +} + +/** + * Handle shared escape keys (mostly navigation) + */ +int handle_escape(int * this_buf, int * timeout, int c) { + if (*timeout >= 1 && this_buf[*timeout-1] == '\033' && c == '\033') { + this_buf[*timeout] = c; + (*timeout)++; + return 1; + } + if (*timeout >= 1 && this_buf[*timeout-1] == '\033' && c != '[') { + *timeout = 0; + bim_unget(c); + return 1; + } + if (*timeout >= 1 && this_buf[*timeout-1] == '\033' && c == '[') { + *timeout = 1; + this_buf[*timeout] = c; + (*timeout)++; + return 0; + } + if (*timeout >= 2 && this_buf[0] == '\033' && this_buf[1] == '[' && + (isdigit(c) || c == ';')) { + this_buf[*timeout] = c; + (*timeout)++; + return 0; + } + if (*timeout >= 2 && this_buf[0] == '\033' && this_buf[1] == '[') { + switch (c) { + case 'M': + handle_mouse(); + break; + case 'A': // up + cursor_up(); + break; + case 'B': // down + cursor_down(); + break; + case 'C': // right + if (this_buf[*timeout-1] == '5') { + word_right(); + } else { + cursor_right(); + } + break; + case 'D': // left + if (this_buf[*timeout-1] == '5') { + word_left(); + } else { + cursor_left(); + } + break; + case 'H': // home + cursor_home(); + break; + case 'F': // end + cursor_end(); + break; + case 'I': + goto_line(env->line_no - (global_config.term_height - 6)); + break; + case 'G': + goto_line(env->line_no + global_config.term_height - 6); + break; + case 'Z': + /* Shift tab */ + if (env->mode == MODE_LINE_SELECTION) { + *timeout = 0; + return 'Z'; + } + break; + case '~': + switch (this_buf[*timeout-1]) { + case '1': + cursor_home(); + break; + case '3': + if (env->mode == MODE_INSERT || env->mode == MODE_REPLACE) { + if (env->col_no < env->lines[env->line_no - 1]->actual + 1) { + line_delete(env->lines[env->line_no - 1], env->col_no, env->line_no - 1); + redraw_line(env->line_no - env->offset - 1, env->line_no-1); + set_modified(); + redraw_statusbar(); + place_cursor_actual(); + } else if (env->line_no < env->line_count) { + merge_lines(env->lines, env->line_no); + redraw_text(); + set_modified(); + redraw_statusbar(); + place_cursor_actual(); + } + } + break; + case '4': + cursor_end(); + break; + case '5': + goto_line(env->line_no - (global_config.term_height - 6)); + break; + case '6': + goto_line(env->line_no + global_config.term_height - 6); + break; + } + break; + default: + render_error("Unrecognized escape sequence identifier: %c", c); + break; + } + *timeout = 0; + return 0; + } + + *timeout = 0; + return 0; +} + +/** + * Standard navigation shared by normal, line, and char selection. + */ +void handle_navigation(int c) { + switch (c) { + case ':': /* Switch to command mode */ + command_mode(); + break; + case '/': /* Switch to search mode */ + search_mode(1); + break; + case '?': /* Switch to search mode */ + search_mode(0); + break; + case 'n': /* Jump to next search result */ + search_next(); + break; + case 'N': /* Jump backwards to previous search result */ + search_prev(); + break; + case 'j': /* Move cursor down */ + cursor_down(); + break; + case 'k': /* Move cursor up */ + cursor_up(); + break; + case 'h': /* Move cursor left */ + cursor_left(); + break; + case 'l': /* Move cursor right*/ + cursor_right(); + break; + case ' ': /* Jump forward several lines */ + goto_line(env->line_no + global_config.term_height - 6); + break; + case '%': /* Jump to matching brace/bracket */ + if (env->mode == MODE_LINE_SELECTION || env->mode == MODE_CHAR_SELECTION) { + /* These modes need to recalculate syntax as find_matching_brace uses it to find appropriate match */ + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + } + find_matching_paren(); + redraw_statusbar(); + break; + case '{': /* Jump to previous blank line */ + env->col_no = 1; + if (env->line_no == 1) break; + do { + env->line_no--; + if (env->lines[env->line_no-1]->actual == 0) break; + } while (env->line_no > 1); + redraw_statusbar(); + break; + case '}': /* Jump to next blank line */ + env->col_no = 1; + if (env->line_no == env->line_count) break; + do { + env->line_no++; + if (env->lines[env->line_no-1]->actual == 0) break; + } while (env->line_no < env->line_count); + redraw_statusbar(); + break; + case '$': /* Move cursor to end of line */ + cursor_end(); + break; + case '^': + case '0': /* Move cursor to beginning of line */ + cursor_home(); + break; + } +} + +/** + * Macro for redrawing selected lines with appropriate highlighting. + */ +#define _redraw_line(line, force_start_line) \ + do { \ + if (!(force_start_line) && (line) == start_line) break; \ + if ((line) > env->line_count + 1) { \ + if ((line) - env->offset - 1 < global_config.term_height - global_config.bottom_size - 1) { \ + draw_excess_line((line) - env->offset - 1); \ + } \ + break; \ + } \ + if ((env->line_no < start_line && ((line) < env->line_no || (line) > start_line)) || \ + (env->line_no > start_line && ((line) > env->line_no || (line) < start_line)) || \ + (env->line_no == start_line && (line) != start_line)) { \ + recalculate_syntax(env->lines[(line)-1],(line)-1); \ + } else { \ + for (int j = 0; j < env->lines[(line)-1]->actual; ++j) { \ + env->lines[(line)-1]->text[j].flags = FLAG_SELECT; \ + } \ + } \ + if ((line) - env->offset + 1 > 1 && \ + (line) - env->offset - 1< global_config.term_height - global_config.bottom_size - 1) { \ + redraw_line((line) - env->offset - 1, (line)-1); \ + } \ + } while (0) + +/** + * Adjust indentation on selected lines. + */ +void adjust_indent(int start_line, int direction) { + int lines_to_cover = 0; + int start_point = 0; + if (start_line <= env->line_no) { + start_point = start_line - 1; + lines_to_cover = env->line_no - start_line + 1; + } else { + start_point = env->line_no - 1; + lines_to_cover = start_line - env->line_no + 1; + } + for (int i = 0; i < lines_to_cover; ++i) { + if ((direction == -1) && env->lines[start_point + i]->actual < 1) continue; + if (direction == -1) { + if (env->tabs) { + if (env->lines[start_point + i]->text[0].codepoint == '\t') { + line_delete(env->lines[start_point + i],1,start_point+i); + _redraw_line(start_point+i+1,1); + } + } else { + for (int j = 0; j < env->tabstop; ++j) { + if (env->lines[start_point + i]->text[0].codepoint == ' ') { + line_delete(env->lines[start_point + i],1,start_point+i); + } + } + _redraw_line(start_point+i+1,1); + } + } else if (direction == 1) { + if (env->tabs) { + char_t c; + c.codepoint = '\t'; + c.display_width = env->tabstop; + c.flags = FLAG_SELECT; + env->lines[start_point + i] = line_insert(env->lines[start_point + i], c, 0, start_point + i); + } else { + for (int j = 0; j < env->tabstop; ++j) { + char_t c; + c.codepoint = ' '; + c.display_width = 1; + c.flags = FLAG_SELECT; + env->lines[start_point + i] = line_insert(env->lines[start_point + i], c, 0, start_point + i); + } + } + _redraw_line(start_point+i+1,1); + } + } + if (env->col_no > env->lines[env->line_no-1]->actual) { + env->col_no = env->lines[env->line_no-1]->actual; + } + set_modified(); +} + +/** + * LINE SELECTION mode + * + * Equivalent to visual line in vim; selects lines of texts. + */ +void line_selection_mode(void) { + int start_line = env->line_no; + int prev_line = start_line; + + env->mode = MODE_LINE_SELECTION; + redraw_commandline(); + + int c; + int timeout = 0; + int this_buf[20]; + + for (int j = 0; j < env->lines[env->line_no-1]->actual; ++j) { + env->lines[env->line_no-1]->text[j].flags = FLAG_SELECT; + } + redraw_line(env->line_no - env->offset - 1, env->line_no-1); + + while ((c = bim_getch())) { + if (c == -1) { + if (timeout && this_buf[timeout-1] == '\033') { + goto _leave_select_line; + } + timeout = 0; + continue; + } else { + if (timeout == 0) { + switch (c) { + case '\033': + if (timeout == 0) { + this_buf[timeout] = c; + timeout++; + } + break; + case DELETE_KEY: + case BACKSPACE_KEY: + cursor_left(); + break; + case '\t': + if (env->readonly) goto _readonly; + adjust_indent(start_line, 1); + break; + case 'V': + goto _leave_select_line; + case 'y': + yank_lines(start_line, env->line_no); + goto _leave_select_line; + case 'D': + case 'd': + if (env->readonly) goto _readonly; + yank_lines(start_line, env->line_no); + if (start_line <= env->line_no) { + int lines_to_delete = env->line_no - start_line + 1; + for (int i = 0; i < lines_to_delete; ++i) { + remove_line(env->lines, start_line-1); + } + env->line_no = start_line; + } else { + int lines_to_delete = start_line - env->line_no + 1; + for (int i = 0; i < lines_to_delete; ++i) { + remove_line(env->lines, env->line_no-1); + } + } + if (env->line_no > env->line_count) { + env->line_no = env->line_count; + } + if (env->col_no > env->lines[env->line_no-1]->actual) { + env->col_no = env->lines[env->line_no-1]->actual; + } + set_modified(); + goto _leave_select_line; + default: + handle_navigation(c); + break; + } + } else { + switch (handle_escape(this_buf,&timeout,c)) { + case 1: + bim_unget(c); + goto _leave_select_line; + case 'Z': + /* Unindent */ + if (env->readonly) goto _readonly; + adjust_indent(start_line, -1); + break; + } + } + + /* Mark current line */ + _redraw_line(env->line_no,0); + + /* Properly mark everything in the span we just moved through */ + if (prev_line < env->line_no) { + for (int i = prev_line; i < env->line_no; ++i) { + _redraw_line(i,0); + } + prev_line = env->line_no; + } else if (prev_line > env->line_no) { + for (int i = env->line_no + 1; i <= prev_line; ++i) { + _redraw_line(i,0); + } + prev_line = env->line_no; + } + place_cursor_actual(); + continue; +_readonly: + render_error("Buffer is read-only"); + } + } + +_leave_select_line: + set_history_break(); + env->mode = MODE_NORMAL; + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + redraw_all(); +} + +/** + * Determine if a column + line number are within range of the + * current character selection specified by start_line, etc. + * + * Used to determine how syntax flags should be set when redrawing + * selected text in CHAR SELECTION mode. + */ +int point_in_range(int start_line, int end_line, int start_col, int end_col, int line, int col) { + if (start_line == end_line) { + if ( end_col < start_col) { + int tmp = end_col; + end_col = start_col; + start_col = tmp; + } + return (col >= start_col && col <= end_col); + } + + if (start_line > end_line) { + int tmp = end_line; + end_line = start_line; + start_line = tmp; + + tmp = end_col; + end_col = start_col; + start_col = tmp; + } + + if (line < start_line || line > end_line) return 0; + + if (line == start_line) { + return col >= start_col; + } + + if (line == end_line) { + return col <= end_col; + } + + return 1; +} + +#define _redraw_line_char(line, force_start_line) \ + do { \ + if (!(force_start_line) && (line) == start_line) break; \ + if ((line) > env->line_count + 1) { \ + if ((line) - env->offset - 1 < global_config.term_height - global_config.bottom_size - 1) { \ + draw_excess_line((line) - env->offset - 1); \ + } \ + break; \ + } \ + if ((env->line_no < start_line && ((line) < env->line_no || (line) > start_line)) || \ + (env->line_no > start_line && ((line) > env->line_no || (line) < start_line)) || \ + (env->line_no == start_line && (line) != start_line)) { \ + /* Line is completely outside selection */ \ + recalculate_syntax(env->lines[(line)-1],(line)-1); \ + } else { \ + if ((line) == start_line || (line) == env->line_no) { \ + recalculate_syntax(env->lines[(line)-1],(line)-1); \ + } \ + for (int j = 0; j < env->lines[(line)-1]->actual; ++j) { \ + if (point_in_range(start_line, env->line_no,start_col, env->col_no, (line), j+1)) { \ + env->lines[(line)-1]->text[j].flags = FLAG_SELECT; \ + } \ + } \ + } \ + if ((line) - env->offset + 1 > 1 && \ + (line) - env->offset - 1< global_config.term_height - global_config.bottom_size - 1) { \ + redraw_line((line) - env->offset - 1, (line)-1); \ + } \ + } while (0) + +/** + * CHAR SELECTION mode. + */ +void char_selection_mode(void) { + int start_line = env->line_no; + int start_col = env->col_no; + int prev_line = start_line; + + env->mode = MODE_CHAR_SELECTION; + redraw_commandline(); + + int c; + int timeout = 0; + int this_buf[20]; + + /* Select single character */ + env->lines[env->line_no-1]->text[env->col_no-1].flags = FLAG_SELECT; + redraw_line(env->line_no - env->offset - 1, env->line_no-1); + + while ((c = bim_getch())) { + if (c == -1) { + if (timeout && this_buf[timeout-1] == '\033') { + goto _leave_select_char; + } + timeout = 0; + continue; + } else { + if (timeout == 0) { + switch (c) { + case '\033': + if (timeout == 0) { + this_buf[timeout] = c; + timeout++; + } + break; + case DELETE_KEY: + case BACKSPACE_KEY: + cursor_left(); + break; + case 'v': + goto _leave_select_char; + case 'y': + { + int end_line = env->line_no; + int end_col = env->col_no; + if (start_line == end_line) { + if (start_col > end_col) { + int tmp = start_col; + start_col = end_col; + end_col = tmp; + } + } else if (start_line > end_line) { + int tmp = start_line; + start_line = end_line; + end_line = tmp; + tmp = start_col; + start_col = end_col; + end_col = tmp; + } + yank_text(start_line, start_col, end_line, end_col); + } + goto _leave_select_char; + case 'D': + case 'd': + if (env->readonly) goto _readonly; + { + int end_line = env->line_no; + int end_col = env->col_no; + if (start_line == end_line) { + if (start_col > end_col) { + int tmp = start_col; + start_col = end_col; + end_col = tmp; + } + yank_text(start_line, start_col, end_line, end_col); + for (int i = start_col; i <= end_col; ++i) { + line_delete(env->lines[start_line-1], start_col, start_line - 1); + } + env->col_no = start_col; + } else { + if (start_line > end_line) { + int tmp = start_line; + start_line = end_line; + end_line = tmp; + tmp = start_col; + start_col = end_col; + end_col = tmp; + } + /* Copy lines */ + yank_text(start_line, start_col, end_line, end_col); + /* Delete lines */ + for (int i = start_line+1; i < end_line; ++i) { + remove_line(env->lines, start_line); + } /* end_line is no longer valid; should be start_line+1*/ + /* Delete from start_col forward */ + int tmp = env->lines[start_line-1]->actual; + for (int i = start_col; i <= tmp; ++i) { + line_delete(env->lines[start_line-1], start_col, start_line - 1); + } + for (int i = 1; i <= end_col; ++i) { + line_delete(env->lines[start_line], 1, start_line); + } + /* Merge start and end lines */ + merge_lines(env->lines, start_line); + env->line_no = start_line; + env->col_no = start_col; + } + } + if (env->line_no > env->line_count) { + env->line_no = env->line_count; + } + set_modified(); + goto _leave_select_char; + default: + handle_navigation(c); + break; + } + } else { + switch (handle_escape(this_buf,&timeout,c)) { + case 1: + bim_unget(c); + goto _leave_select_char; + } + } + + /* Mark current line */ + _redraw_line_char(env->line_no,1); + + /* Properly mark everything in the span we just moved through */ + if (prev_line < env->line_no) { + for (int i = prev_line; i < env->line_no; ++i) { + _redraw_line_char(i,1); + } + prev_line = env->line_no; + } else if (prev_line > env->line_no) { + for (int i = env->line_no + 1; i <= prev_line; ++i) { + _redraw_line_char(i,1); + } + prev_line = env->line_no; + } + place_cursor_actual(); + continue; +_readonly: + render_error("Buffer is read-only"); + } + } + +_leave_select_char: + set_history_break(); + env->mode = MODE_NORMAL; + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + redraw_all(); +} + +/** + * INSERT mode + * + * Accept input into the text buffer. + */ +void insert_mode(void) { + int cin; + uint32_t c; + + /* Set mode line */ + env->mode = MODE_INSERT; + redraw_commandline(); + + /* Place the cursor in the text area */ + place_cursor_actual(); + + int timeout = 0; + int this_buf[20]; + uint32_t istate = 0; + int redraw = 0; + while ((cin = bim_getch_timeout((redraw ? 10 : 200)))) { + if (cin == -1) { + if (redraw) { + if (redraw & 2) { + redraw_text(); + } else { + redraw_line(env->line_no - env->offset - 1, env->line_no-1); + } + redraw_statusbar(); + place_cursor_actual(); + redraw = 0; + } + if (timeout && this_buf[timeout-1] == '\033') { + leave_insert(); + return; + } + timeout = 0; + continue; + } + if (!decode(&istate, &c, cin)) { + if (timeout == 0) { + switch (c) { + case '\033': + if (timeout == 0) { + this_buf[timeout] = c; + timeout++; + } + break; + case DELETE_KEY: + case BACKSPACE_KEY: + delete_at_cursor(); + break; + case ENTER_KEY: + insert_line_feed(); + redraw |= 2; + break; + case 22: /* ^V */ + /* Insert next byte raw */ + { + /* Indicate we're in literal mode */ + render_commandline_message("^V"); + /* Put the cursor back into the text field */ + place_cursor_actual(); + /* Get next character */ + while ((cin = bim_getch()) == -1); + /* Insert literal */ + insert_char(cin); + /* Redraw INSERT */ + redraw_commandline(); + /* Draw text */ + redraw |= 1; + } + break; + case 23: /* ^W */ + delete_word(); + break; + case '\t': + if (env->tabs) { + insert_char('\t'); + } else { + for (int i = 0; i < env->tabstop; ++i) { + insert_char(' '); + } + } + redraw |= 1; + break; + default: + insert_char(c); + redraw |= 1; + break; + } + } else { + if (handle_escape(this_buf,&timeout,c)) { + bim_unget(c); + leave_insert(); + return; + } + } + } else if (istate == UTF8_REJECT) { + istate = 0; + } + } +} + +/* + * REPLACE mode + * + * Like insert, but replaces characters. + */ +void replace_mode(void) { + int cin; + uint32_t c; + + /* Set mode line */ + env->mode = MODE_REPLACE; + redraw_commandline(); + + /* Place the cursor in the text area */ + place_cursor_actual(); + + int timeout = 0; + int this_buf[20]; + uint32_t istate = 0; + while ((cin = bim_getch())) { + if (cin == -1) { + if (timeout && this_buf[timeout-1] == '\033') { + leave_insert(); + return; + } + timeout = 0; + continue; + } + if (!decode(&istate, &c, cin)) { + if (timeout == 0) { + switch (c) { + case '\033': + if (timeout == 0) { + this_buf[timeout] = c; + timeout++; + } + break; + case DELETE_KEY: + case BACKSPACE_KEY: + if (env->line_no > 1 && env->col_no == 1) { + env->line_no--; + env->col_no = env->lines[env->line_no-1]->actual; + place_cursor_actual(); + } else { + cursor_left(); + } + break; + case ENTER_KEY: + insert_line_feed(); + redraw_text(); + set_modified(); + redraw_statusbar(); + place_cursor_actual(); + break; + default: + if (env->col_no <= env->lines[env->line_no - 1]->actual) { + replace_char(c); + env->col_no += 1; + } else { + insert_char(c); + redraw_line(env->line_no - env->offset - 1, env->line_no-1); + } + redraw_statusbar(); + place_cursor_actual(); + break; + } + } else { + if (handle_escape(this_buf,&timeout,c)) { + bim_unget(c); + leave_insert(); + return; + } + } + } else if (istate == UTF8_REJECT) { + istate = 0; + } + } +} + +/** + * NORMAL mode + * + * Default editor mode - just cursor navigation and keybinds + * to enter the other modes. + */ +void normal_mode(void) { + + while (1) { + place_cursor_actual(); + int c; + int timeout = 0; + int this_buf[20]; + while ((c = bim_getch())) { + if (c == -1) { + /* getch timed out, nothing to do in normal mode */ + continue; + } + if (timeout == 0) { + switch (c) { + case '\033': + if (timeout == 0) { + this_buf[timeout] = c; + timeout++; + } + break; + case DELETE_KEY: + case BACKSPACE_KEY: + if (env->line_no > 1 && env->col_no == 1) { + env->line_no--; + env->col_no = env->lines[env->line_no-1]->actual; + place_cursor_actual(); + } else { + cursor_left(); + } + break; + case 'V': /* Enter LINE SELECTION mode */ + line_selection_mode(); + break; + case 'v': /* Enter CHAR SELECTION mode */ + char_selection_mode(); + break; + case 'O': /* Append line before and enter INSERT mode */ + { + if (env->readonly) goto _readonly; + env->lines = add_line(env->lines, env->line_no-1); + env->col_no = 1; + add_indent(env->line_no-1,env->line_no); + redraw_text(); + set_modified(); + place_cursor_actual(); + goto _insert; + } + case 'o': /* Append line after and enter INSERT mode */ + { + if (env->readonly) goto _readonly; + env->lines = add_line(env->lines, env->line_no); + env->col_no = 1; + env->line_no += 1; + add_indent(env->line_no-1,env->line_no-2); + if (env->line_no > env->offset + global_config.term_height - global_config.bottom_size - 1) { + env->offset += 1; + } + redraw_text(); + set_modified(); + place_cursor_actual(); + goto _insert; + } + case 'a': /* Enter INSERT mode with cursor after current position */ + if (env->col_no < env->lines[env->line_no-1]->actual + 1) { + env->col_no += 1; + } + goto _insert; + case 'P': /* Paste before */ + case 'p': /* Paste after */ + if (env->readonly) goto _readonly; + if (global_config.yanks) { + if (!global_config.yank_is_full_lines) { + /* Handle P for paste before, p for past after */ + int target_column = (c == 'P' ? (env->col_no) : (env->col_no+1)); + if (target_column > env->lines[env->line_no-1]->actual + 1) { + target_column = env->lines[env->line_no-1]->actual + 1; + } + if (global_config.yank_count > 1) { + /* Spit the current line at the current position */ + env->lines = split_line(env->lines, env->line_no - 1, target_column - 1); /* Split after */ + } + /* Insert first line at current position */ + for (int i = 0; i < global_config.yanks[0]->actual; ++i) { + env->lines[env->line_no - 1] = line_insert(env->lines[env->line_no - 1], global_config.yanks[0]->text[i], target_column + i - 1, env->line_no - 1); + } + if (global_config.yank_count > 1) { + /* Insert full lines */ + for (unsigned int i = 1; i < global_config.yank_count - 1; ++i) { + env->lines = add_line(env->lines, env->line_no); + } + for (unsigned int i = 1; i < global_config.yank_count - 1; ++i) { + replace_line(env->lines, env->line_no + i - 1, global_config.yanks[i]); + } + /* Insert characters from last line into (what was) the next line */ + for (int i = 0; i < global_config.yanks[global_config.yank_count-1]->actual; ++i) { + env->lines[env->line_no + global_config.yank_count - 2] = line_insert(env->lines[env->line_no + global_config.yank_count - 2], global_config.yanks[global_config.yank_count-1]->text[i], i, env->line_no + global_config.yank_count - 2); + } + } + } else { + /* Insert full lines */ + for (unsigned int i = 0; i < global_config.yank_count; ++i) { + env->lines = add_line(env->lines, env->line_no - (c == 'P' ? 1 : 0)); + } + for (unsigned int i = 0; i < global_config.yank_count; ++i) { + replace_line(env->lines, env->line_no - (c == 'P' ? 1 : 0) + i, global_config.yanks[i]); + } + } + /* Recalculate whole document syntax */ + for (int i = 0; i < env->line_count; ++i) { + env->lines[i]->istate = 0; + } + for (int i = 0; i < env->line_count; ++i) { + recalculate_syntax(env->lines[i],i); + } + set_history_break(); + set_modified(); + redraw_all(); + } + break; + case 'u': /* Undo one block of history */ + undo_history(); + break; + case 18: /* ^R - Redo one block of history */ + redo_history(); + break; + case 12: /* ^L - Repaint the whole screen */ + redraw_all(); + break; + case 'i': /* Enter INSERT mode */ +_insert: + if (env->readonly) goto _readonly; + insert_mode(); + redraw_statusbar(); + redraw_commandline(); + timeout = 0; + break; + case 'R': /* Enter REPLACE mode */ + if (env->readonly) goto _readonly; + replace_mode(); + redraw_statusbar(); + redraw_commandline(); + timeout = 0; + break; +_readonly: + render_error("Buffer is read-only"); + break; + default: + handle_navigation(c); + break; + } + } else { + handle_escape(this_buf,&timeout,c); + } + place_cursor_actual(); + } + } + +} + +/** + * Show help text for -? + */ +static void show_usage(char * argv[]) { +#define _S "\033[3m" +#define _E "\033[0m\n" + printf( + "bim - Text editor\n" + "\n" + "usage: %s [options] [file]\n" + " %s [options] -- -\n" + "\n" + " -R " _S "open initial buffer read-only" _E + " -O " _S "set various options:" _E + " noscroll " _S "disable terminal scrolling" _E + " noaltscreen " _S "disable alternate screen buffer" _E + " nomouse " _S "disable mouse support" _E + " nounicode " _S "disable unicode display" _E + " nobright " _S "disable bright next" _E + " nohideshow " _S "disable togglging cursor visibility" _E + " nosyntax " _S "disable syntax highlighting on load" _E + " notitle " _S "disable title-setting escapes" _E + " history " _S "enable experimental undo/redo" _E + " -c,-C " _S "print file to stdout with syntax hilighting" _E + " " _S "-C includes line numbers, -c does not" _E + " -u " _S "override bimrc file" _E + " -? " _S "show this help text" _E + "\n", argv[0], argv[0]); +#undef _E +#undef _S +} + +/** + * Load bimrc configuration file. + * + * At the moment, this a simple key=value list. + */ +void load_bimrc(void) { + if (!global_config.bimrc_path) return; + + /* Default is ~/.bimrc */ + char * tmp = strdup(global_config.bimrc_path); + + if (!*tmp) { + free(tmp); + return; + } + + /* Parse ~ at the front of the path. */ + if (*tmp == '~') { + char path[1024] = {0}; + char * home = getenv("HOME"); + if (!home) { + /* $HOME is unset? */ + free(tmp); + return; + } + + /* New path is $HOME/.bimrc */ + snprintf(path, 1024, "%s%s", home, tmp+1); + free(tmp); + tmp = strdup(path); + } + + /* Try to open the file */ + FILE * bimrc = fopen(tmp, "r"); + + if (!bimrc) { + /* No bimrc, or bad permissions */ + free(tmp); + return; + } + + /* Parse through lines */ + char line[1024]; + while (!feof(bimrc)) { + char * l = fgets(line, 1023, bimrc); + + /* Ignore bad lines */ + if (!l) break; + if (!*l) continue; + if (*l == '\n') continue; + + /* Ignore comment lines */ + if (*l == '#') continue; + + /* Remove linefeed at the end */ + char *nl = strstr(l,"\n"); + if (nl) *nl = '\0'; + + /* Extract value from keypair, if available + * (I foresee options without values in the future) */ + char *value= strstr(l,"="); + if (value) { + *value = '\0'; + value++; + } + + /* theme=... */ + if (!strcmp(l,"theme") && value) { + /* Examine available themes for a match. */ + for (struct theme_def * d = themes; d->name; ++d) { + if (!strcmp(value, d->name)) { + d->load(); + break; + } + } + } + + /* enable history (experimental) */ + if (!strcmp(l,"history")) { + global_config.history_enabled = 1; + } + + /* padding= */ + if (!strcmp(l,"padding") && value) { + global_config.cursor_padding = atoi(value); + } + } + + fclose(bimrc); +} + +/** + * Set some default values when certain terminals are detected. + */ +void detect_weird_terminals(void) { + + char * term = getenv("TERM"); + if (term && !strcmp(term,"linux")) { + /* Linux VTs can't scroll. */ + global_config.can_scroll = 0; + } + if (term && !strcmp(term,"cons25")) { + /* Dragonfly BSD console */ + global_config.can_hideshow = 0; + global_config.can_altscreen = 0; + global_config.can_mouse = 0; + global_config.can_unicode = 0; + global_config.can_bright = 0; + } + if (term && !strcmp(term,"sortix")) { + /* sortix will spew title escapes to the screen, no good */ + global_config.can_title = 0; + } + if (term && strstr(term,"tmux") == term) { + global_config.can_scroll = 0; + global_config.can_bce = 0; + } + +} + +/** + * Run global initialization tasks + */ +void initialize(void) { + setlocale(LC_ALL, ""); + + detect_weird_terminals(); + load_colorscheme_ansi(); + load_bimrc(); + + buffers_avail = 4; + buffers = malloc(sizeof(buffer_t *) * buffers_avail); +} + +/** + * Initialize terminal for editor display. + */ +void init_terminal(void) { + set_alternate_screen(); + update_screen_size(); + get_initial_termios(); + set_unbuffered(); + mouse_enable(); + + signal(SIGWINCH, SIGWINCH_handler); + signal(SIGCONT, SIGCONT_handler); + signal(SIGTSTP, SIGTSTP_handler); +} + +int main(int argc, char * argv[]) { + int opt; + while ((opt = getopt(argc, argv, "?c:C:u:RO:-:")) != -1) { + switch (opt) { + case 'R': + global_config.initial_file_is_read_only = 1; + break; + case 'c': + case 'C': + /* Print file to stdout using our syntax highlighting and color theme */ + initialize(); + open_file(optarg); + for (int i = 0; i < env->line_count; ++i) { + if (opt == 'C') { + draw_line_number(i); + } + render_line(env->lines[i], 6 * (env->lines[i]->actual + 1), 0); + reset(); + fprintf(stdout, "\n"); + } + return 0; + case 'u': + global_config.bimrc_path = optarg; + break; + case 'O': + /* Set various display options */ + if (!strcmp(optarg,"noaltscreen")) global_config.can_altscreen = 0; + else if (!strcmp(optarg,"noscroll")) global_config.can_scroll = 0; + else if (!strcmp(optarg,"nomouse")) global_config.can_mouse = 0; + else if (!strcmp(optarg,"nounicode")) global_config.can_unicode = 0; + else if (!strcmp(optarg,"nobright")) global_config.can_bright = 0; + else if (!strcmp(optarg,"nohideshow")) global_config.can_hideshow = 0; + else if (!strcmp(optarg,"nosyntax")) global_config.hilight_on_open = 0; + else if (!strcmp(optarg,"nohistory")) global_config.history_enabled = 0; + else if (!strcmp(optarg,"notitle")) global_config.can_title = 0; + else if (!strcmp(optarg,"nobce")) global_config.can_bce = 0; + else { + fprintf(stderr, "%s: unrecognized -O option: %s\n", argv[0], optarg); + return 1; + } + break; + case '-': + if (!strcmp(optarg,"version")) { + fprintf(stderr, "bim %s %s\n", BIM_VERSION, BIM_COPYRIGHT); + fprintf(stderr, " Available syntax highlighters:"); + for (struct syntax_definition * s = syntaxes; s->name; ++s) { + fprintf(stderr, " %s", s->name); + } + fprintf(stderr, "\n"); + fprintf(stderr, " Available color themes:"); + for (struct theme_def * d = themes; d->name; ++d) { + fprintf(stderr, " %s", d->name); + } + fprintf(stderr, "\n"); + return 0; + } + break; + case '?': + show_usage(argv); + return 0; + } + } + + /* Set up terminal */ + initialize(); + init_terminal(); + + /* Open file */ + if (argc > optind) { + open_file(argv[optind]); + update_title(); + goto_line(0); + if (global_config.initial_file_is_read_only) { + env->readonly = 1; + } + } else { + env = buffer_new(); + update_title(); + setup_buffer(env); + } + + /* Draw the screen once */ + redraw_all(); + + /* Start accepting key commands */ + normal_mode(); + + return 0; +} diff --git a/userspace/extra/cat-img.c b/apps/cat-img.c similarity index 80% rename from userspace/extra/cat-img.c rename to apps/cat-img.c index 517c64f5..ccb1fadb 100644 --- a/userspace/extra/cat-img.c +++ b/apps/cat-img.c @@ -1,16 +1,17 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016 Kevin Lange + * Copyright (C) 2016-2018 K. Lange */ +#include #include #include #include #include #include -#include "lib/graphics.h" -#include "gui/terminal/lib/termemu.h" +#include +#include void get_cell_sizes(int * w, int * h) { struct winsize wsz; @@ -45,6 +46,7 @@ int usage(char * argv[]) { "\n" " -n \033[3mdon't print a new line after image\033[0m\n" " -s \033[3mscale to cell height (up or down)\033[0m\n" + " -w \033[3mscale to terminal width (up or down)\033[0m\n" " -? \033[3mshow this help text\033[0m\n" "\n", argv[0]); return 1; @@ -59,14 +61,18 @@ int main (int argc, char * argv[]) { int opt; int no_newline = 0; int scale_to_cell_height = 0; + int scale_to_term_width = 0; - while ((opt = getopt(argc, argv, "?ns")) != -1) { + while ((opt = getopt(argc, argv, "?nsw")) != -1) { switch (opt) { case '?': return usage(argv); case 'n': no_newline = 1; break; + case 'w': + scale_to_term_width = 1; + break; case 's': scale_to_cell_height = 1; break; @@ -84,11 +90,8 @@ int main (int argc, char * argv[]) { while (optind < argc) { sprite_t * image = calloc(sizeof(sprite_t),1); - if (load_sprite_png(image, argv[optind])) { - free(image); - optind++; - continue; - } + load_sprite(image, argv[optind]); + image->alpha = ALPHA_EMBEDDED; sprite_t * source = image; @@ -101,6 +104,17 @@ int main (int argc, char * argv[]) { sprite_free(image); } + if (scale_to_term_width) { + struct winsize w; + ioctl(0, TIOCGWINSZ, &w); + int new_height = (w.ws_xpixel * image->height) / image->width; + source = create_sprite(w.ws_xpixel, new_height, 1); + gfx_context_t * g = init_graphics_sprite(source); + draw_fill(g, 0x00000000); + draw_sprite_scaled(g, image, 0, 0, w.ws_xpixel, new_height); + sprite_free(image); + } + int width_in_cells = source->width / w; if (source->width % w) width_in_cells++; diff --git a/userspace/core/cat.c b/apps/cat.c similarity index 75% rename from userspace/core/cat.c rename to apps/cat.c index 1a73f19f..46571d7a 100644 --- a/userspace/core/cat.c +++ b/apps/cat.c @@ -1,9 +1,9 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* - * cat + * Copyright (C) 2013-2018 K. Lange + * + * cat - Concatenate files * * Concatenates files together to standard output. * In a supporting terminal, you can then pipe @@ -14,6 +14,8 @@ #include #include #include +#include +#include #define CHUNK_SIZE 4096 @@ -35,8 +37,8 @@ int main(int argc, char ** argv) { for (int i = 1; i < argc; ++i) { int fd = open(argv[i], O_RDONLY); - if (fd == -1) { - fprintf(stderr, "%s: %s: no such file or directory\n", argv[0], argv[i]); + if (fd < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno)); ret = 1; continue; } @@ -59,8 +61,3 @@ int main(int argc, char ** argv) { return ret; } -/* - * vim:tabstop=4 - * vim:noexpandtab - * vim:shiftwidth=4 - */ diff --git a/apps/chmod.c b/apps/chmod.c new file mode 100644 index 00000000..128bd99c --- /dev/null +++ b/apps/chmod.c @@ -0,0 +1,135 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * chmod - change file permissions + * + * Note: This implementation is likely non-compliant, though it does + * attempt to look similar to the standard POSIX syntax, + * supporting both octal mode setings and +/-rwx flavors. + */ +#include +#include +#include +#include + +enum mode_set { + MODE_SET, + MODE_ADD, + MODE_REMOVE, +}; + +static int calc(int mode, int users) { + int out = 0; + if (users & 1) { + out |= (mode << 6); + } + if (users & 2) { + out |= (mode << 3); + } + if (users & 4) { + out |= (mode << 0); + } + return out; +} + +int main(int argc, char * argv[]) { + if (argc < 3) { + fprintf(stderr, "usage: %s OCTAL-MODE FILE...\n", argv[0]); + return 1; + } + + /* Parse mode */ + int mode = 0; + enum mode_set mode_set = MODE_SET; + char * c = argv[1]; + int user_modes = 0; + int all_users = 7; + + while (*c) { + switch (*c) { + case '0': + c++; /* 0 */ + while (*c >= '0' || *c <= '7') { + mode *= 8; + mode += (*c - '0'); + c++; + } + break; + case 'u': + all_users = 0; + user_modes |= 1; + c++; + break; + case 'g': + all_users = 0; + user_modes |= 2; + c++; + break; + case 'o': + all_users = 0; + user_modes |= 4; + c++; + break; + case 'a': + all_users = 7; + user_modes = 7; + c++; + break; + case '-': + mode_set = MODE_REMOVE; + c++; + break; + case '+': + mode_set = MODE_ADD; + c++; + break; + case '=': + mode_set = MODE_SET; + c++; + break; + case 'r': + mode |= calc(S_IROTH, user_modes | all_users); + c++; + break; + case 'w': + mode |= calc(S_IWOTH, user_modes | all_users); + c++; + break; + case 'x': + mode |= calc(S_IXOTH, user_modes | all_users); + c++; + break; + } + } + + int i = 2; + while (i < argc) { + int actual_mode = 0; + struct stat _stat; + if (stat(argv[i], &_stat) < 0) { + fprintf(stderr, "%s: %s: error with stat\n", argv[0], argv[i]); + } + + switch (mode_set) { + case MODE_SET: + actual_mode = mode; + break; + case MODE_ADD: + actual_mode = _stat.st_mode | mode; + break; + case MODE_REMOVE: + actual_mode = _stat.st_mode &= ~(mode); + break; + } + + if (chmod(argv[i], actual_mode) < 0) { + fprintf(stderr, "%s: %s: error with chmod\n", argv[0], argv[i]); + return 1; + } + i++; + } + + return 0; +} diff --git a/apps/clear.c b/apps/clear.c new file mode 100644 index 00000000..af9d6a93 --- /dev/null +++ b/apps/clear.c @@ -0,0 +1,19 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013 K. Lange + * + * clear - Clear the terminal + * + * Sends an escape code to clear the screen. Ideally, this should + * come from a database of terminal escape codes (eg. terminfo), + * but we don't have one of those yet, so just send a code that + * makes sense for a lot of terminals. + */ +#include + +int main(int argc, char ** argv) { + printf("\033[H\033[2J"); + fflush(stdout); + return 0; +} diff --git a/userspace/gui/compositor/compositor.c b/apps/compositor.c similarity index 73% rename from userspace/gui/compositor/compositor.c rename to apps/compositor.c index 634e22f1..9f7ebea1 100644 --- a/userspace/gui/compositor/compositor.c +++ b/apps/compositor.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2017 Kevin Lange + * Copyright (C) 2013-2018 K. Lange * * Yutani - The ToaruOS Compositor. * @@ -29,47 +29,44 @@ #include #include #include +#include +#include +#include +/* auto-dep: export-dynamic */ -#include - -#include "lib/graphics.h" -#include "lib/pthread.h" -#include "lib/mouse.h" -#include "lib/kbd.h" -#include "lib/pex.h" -#include "lib/yutani.h" -#include "lib/hashmap.h" -#include "lib/list.h" -#include "lib/spinlock.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#define _DEBUG_YUTANI #ifdef _DEBUG_YUTANI -#include "lib/trace.h" +#include #define TRACE_APP_NAME "yutani" #else #define TRACE(msg,...) #endif -#include "yutani_int.h" +/* Early definitions */ +static void mark_window(yutani_globals_t * yg, yutani_server_window_t * window); +static void window_actually_close(yutani_globals_t * yg, yutani_server_window_t * w); +static void notify_subscribers(yutani_globals_t * yg); -#define YUTANI_DEBUG_WINDOW_BOUNDS 1 -#define YUTANI_DEBUG_WINDOW_SHAPES 1 -#define YUTANI_RESIZE_RIGHT 0 -#define YUTANI_INCOMING_MOUSE_SCALE * 3 - -#define MOUSE_WIDTH 64 -#define MOUSE_HEIGHT 64 - -#define UNTILE_SENSITIVITY (MOUSE_SCALE * 5) - -struct { - int nested; - int nest_width; - int nest_height; -} yutani_options = { - .nested = 0, - .nest_width = 640, - .nest_height = 480, -}; +static int (*renderer_alloc)(yutani_globals_t * yg) = NULL; +static int (*renderer_init)(yutani_globals_t * yg) = NULL; +static int (*renderer_add_clip)(yutani_globals_t * yg, double x, double y, double w, double h) = NULL; +static int (*renderer_set_clip)(yutani_globals_t * yg) = NULL; +static int (*renderer_push_state)(yutani_globals_t * yg) = NULL; +static int (*renderer_pop_state)(yutani_globals_t * yg) = NULL; +static int (*renderer_destroy)(yutani_globals_t * yg) = NULL; +static int (*renderer_blit_window)(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y); +static int (*renderer_blit_screen)(yutani_globals_t * yg) = NULL; /** * Print usage information. @@ -95,7 +92,7 @@ static int usage(char * argv[]) { */ static int parse_args(int argc, char * argv[], int * out) { static struct option long_opts[] = { - {"nest", no_argument, 0, 'n'}, + {"nested", no_argument, 0, 'n'}, {"geometry", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {0,0,0,0} @@ -134,11 +131,36 @@ static int parse_args(int argc, char * argv[], int * out) { return 0; } -int32_t min(int32_t a, int32_t b) { +static void try_load_extensions(yutani_globals_t * yg) { + if (renderer_init) { + /* Already have a renderer extension loaded */ + return; + } + + /* Try to load cairo */ + void * cairo = dlopen("libtoaru_ext_cairo_renderer.so", 0); + if (cairo) { + renderer_alloc = dlsym(cairo, "renderer_alloc"); + renderer_init = dlsym(cairo, "renderer_init"); + renderer_add_clip = dlsym(cairo, "renderer_add_clip"); + renderer_set_clip = dlsym(cairo, "renderer_set_clip"); + renderer_push_state = dlsym(cairo, "renderer_push_state"); + renderer_pop_state = dlsym(cairo, "renderer_pop_state"); + renderer_destroy = dlsym(cairo, "renderer_destroy"); + renderer_blit_window = dlsym(cairo, "renderer_blit_window"); + renderer_blit_screen = dlsym(cairo, "renderer_blit_screen"); + } + + /* On success, these are now set */ + if (renderer_alloc) renderer_alloc(yg); + if (renderer_init) renderer_init(yg); +} + +static int32_t min(int32_t a, int32_t b) { return (a < b) ? a : b; } -int32_t max(int32_t a, int32_t b) { +static int32_t max(int32_t a, int32_t b) { return (a > b) ? a : b; } @@ -152,12 +174,12 @@ static int next_wid(void) { return _next++; } -static uint32_t yutani_current_time(yutani_globals_t * yg) { +uint32_t yutani_current_time(yutani_globals_t * yg) { struct timeval t; gettimeofday(&t, NULL); - uint32_t sec_diff = t.tv_sec - yg->start_time; - uint32_t usec_diff = t.tv_usec - yg->start_subtime; + time_t sec_diff = t.tv_sec - yg->start_time; + suseconds_t usec_diff = t.tv_usec - yg->start_subtime; if (t.tv_usec < yg->start_subtime) { sec_diff -= 1; @@ -167,7 +189,7 @@ static uint32_t yutani_current_time(yutani_globals_t * yg) { return (uint32_t)(sec_diff * 1000 + usec_diff / 1000); } -static uint32_t yutani_time_since(yutani_globals_t * yg, uint32_t start_time) { +uint32_t yutani_time_since(yutani_globals_t * yg, uint32_t start_time) { uint32_t now = yutani_current_time(yg); uint32_t diff = now - start_time; /* Milliseconds */ @@ -178,8 +200,12 @@ static uint32_t yutani_time_since(yutani_globals_t * yg, uint32_t start_time) { /** * Translate and transform coordinate from screen-relative to window-relative. */ -static void device_to_window(yutani_server_window_t * window, int32_t x, int32_t y, int32_t * out_x, int32_t * out_y) { - if (!window) return; +void yutani_device_to_window(yutani_server_window_t * window, int32_t x, int32_t y, int32_t * out_x, int32_t * out_y) { + if (!window) { + *out_x = 0; + *out_y = 0; + return; + } *out_x = x - window->x; *out_y = y - window->y; @@ -201,7 +227,7 @@ static void device_to_window(yutani_server_window_t * window, int32_t x, int32_t /** * Translate and transform coordinate from window-relative to screen-relative. */ -static void window_to_device(yutani_server_window_t * window, int32_t x, int32_t y, int32_t * out_x, int32_t * out_y) { +void yutani_window_to_device(yutani_server_window_t * window, int32_t x, int32_t y, int32_t * out_x, int32_t * out_y) { if (!window->rotation) { *out_x = window->x + x; @@ -251,7 +277,6 @@ static void reorder_window(yutani_globals_t * yg, yutani_server_window_t * windo return; } - int z = window->z; spin_lock(&yg->redraw_lock); unorder_window(yg, window); spin_unlock(&yg->redraw_lock); @@ -316,16 +341,16 @@ static void set_focused_window(yutani_globals_t * yg, yutani_server_window_t * w if (yg->focused_window) { /* Send focus change to old focused window */ - yutani_msg_t * response = yutani_msg_build_window_focus_change(yg->focused_window->wid, 0); + yutani_msg_buildx_window_focus_change_alloc(response); + yutani_msg_buildx_window_focus_change(response, yg->focused_window->wid, 0); pex_send(yg->server, yg->focused_window->owner, response->size, (char *)response); - free(response); } yg->focused_window = w; if (w) { /* Send focus change to new focused window */ - yutani_msg_t * response = yutani_msg_build_window_focus_change(w->wid, 1); + yutani_msg_buildx_window_focus_change_alloc(response); + yutani_msg_buildx_window_focus_change(response, w->wid, 1); pex_send(yg->server, w->owner, response->size, (char *)response); - free(response); make_top(yg, w); mark_window(yg, w); } else { @@ -487,100 +512,15 @@ static void server_window_resize_finish(yutani_globals_t * yg, yutani_server_win mark_window(yg, win); } -#define FONT_PATH "/usr/share/fonts/" -#define FONT(a,b) {a, FONT_PATH b} - -struct font_def { - char * identifier; - char * path; -}; - -static struct font_def fonts[] = { - FONT("sans-serif", "DejaVuSans.ttf"), - FONT("sans-serif.bold", "DejaVuSans-Bold.ttf"), - FONT("sans-serif.italic", "DejaVuSans-Oblique.ttf"), - FONT("sans-serif.bolditalic", "DejaVuSans-BoldOblique.ttf"), - FONT("monospace", "DejaVuSansMono.ttf"), - FONT("monospace.bold", "DejaVuSansMono-Bold.ttf"), - FONT("monospace.italic", "DejaVuSansMono-Oblique.ttf"), - FONT("monospace.bolditalic", "DejaVuSansMono-BoldOblique.ttf"), - {NULL, NULL} -}; - -/** - * Preload a font into the font cache. - * - * TODO This should probably be moved out of the compositor, - * perhaps into a generic resource cache daemon. This - * is mostly kept this way for legacy reasons - the old - * compositor did it, but it was also using some of the - * fonts for internal rendering. We don't draw any text. - */ -static char * precache_shmfont(char * ident, char * name) { - FILE * f = fopen(name, "r"); - size_t s = 0; - fseek(f, 0, SEEK_END); - s = ftell(f); - fseek(f, 0, SEEK_SET); - - size_t shm_size = s; - char * font = (char *)syscall_shm_obtain(ident, &shm_size); - assert((shm_size >= s) && "shm_obtain returned too little memory to load a font into!"); - - fread(font, s, 1, f); - - fclose(f); - return font; -} - -/** - * Load all of the fonts into the cache. - */ -static void load_fonts(yutani_globals_t * yg) { - int i = 0; - while (fonts[i].identifier) { - char tmp[100]; - snprintf(tmp, 100, "sys.%s.fonts.%s", yg->server_ident, fonts[i].identifier); - TRACE("Loading font %s -> %s", fonts[i].path, tmp); - precache_shmfont(tmp, fonts[i].path); - ++i; - } -} - /** * Add a clip region from a rectangle. */ static void yutani_add_clip(yutani_globals_t * yg, double x, double y, double w, double h) { - cairo_rectangle(yg->framebuffer_ctx, x, y, w, h); - if (yg->width > 2490) { - x = 0; - w = yg->width; + if (renderer_add_clip) { + renderer_add_clip(yg,x,y,w,h); + } else { + gfx_add_clip(yg->backend_ctx, (int)x, (int)y, (int)w, (int)h); } - cairo_rectangle(yg->real_ctx, x, y, w, h); -} - -/** - * Save cairo states for the framebuffers to the stack. - */ -static void save_cairo_states(yutani_globals_t * yg) { - cairo_save(yg->framebuffer_ctx); - cairo_save(yg->real_ctx); -} - -/** - * Pop previous framebuffer cairo states. - */ -static void restore_cairo_states(yutani_globals_t * yg) { - cairo_restore(yg->framebuffer_ctx); - cairo_restore(yg->real_ctx); -} - -/** - * Apply the clips we built earlier. - */ -static void yutani_set_clip(yutani_globals_t * yg) { - cairo_clip(yg->framebuffer_ctx); - cairo_clip(yg->real_ctx); } /** @@ -601,9 +541,6 @@ static void mark_screen(yutani_globals_t * yg, int32_t x, int32_t y, int32_t wid /** * Draw the cursor sprite. - * - * TODO This should probably use Cairo's PNG functionality, or something - * else other than our own rendering tools... */ static void draw_cursor(yutani_globals_t * yg, int x, int y, int cursor) { sprite_t * sprite = &yg->mouse_sprite; @@ -626,6 +563,8 @@ static void draw_cursor(yutani_globals_t * yg, int x, int y, int cursor) { case SCALE_UP_RIGHT: sprite = &yg->mouse_sprite_resize_db; break; + default: + break; } } else if (yg->mouse_state == YUTANI_MOUSE_STATE_MOVING) { sprite = &yg->mouse_sprite_drag; @@ -642,6 +581,14 @@ static void draw_cursor(yutani_globals_t * yg, int x, int y, int cursor) { mark_screen(yg, x / MOUSE_SCALE - MOUSE_OFFSET_X, y / MOUSE_SCALE - MOUSE_OFFSET_Y, MOUSE_WIDTH, MOUSE_HEIGHT); previous = sprite; } + + if (yg->vbox_pointer > 0) { + if (write(yg->vbox_pointer, sprite->bitmap, 48*48*4) > 0) { + /* if that was successful, we don't need to draw the cursor */ + return; + } + } + draw_sprite(yg->backend_ctx, sprite, x / MOUSE_SCALE - MOUSE_OFFSET_X, y / MOUSE_SCALE - MOUSE_OFFSET_Y); } @@ -654,10 +601,10 @@ static void draw_cursor(yutani_globals_t * yg, int x, int y, int cursor) { * do have one debug method that indicates the top window in a box * around the cursor, but it is relatively slow. */ -yutani_server_window_t * check_top_at(yutani_globals_t * yg, yutani_server_window_t * w, uint16_t x, uint16_t y){ +static yutani_server_window_t * check_top_at(yutani_globals_t * yg, yutani_server_window_t * w, uint16_t x, uint16_t y){ if (!w) return NULL; int32_t _x = -1, _y = -1; - device_to_window(w, x, y, &_x, &_y); + yutani_device_to_window(w, x, y, &_x, &_y); if (_x < 0 || _x >= w->width || _y < 0 || _y >= w->height) return NULL; uint32_t c = ((uint32_t *)w->buffer)[(w->width * _y + _x)]; uint8_t a = _ALP(c); @@ -675,7 +622,7 @@ yutani_server_window_t * check_top_at(yutani_globals_t * yg, yutani_server_windo * at the cursor coordinates, and it is not particularly fast, so don't use it * anywhere that needs to hit a lot of coordinates. */ -yutani_server_window_t * top_at(yutani_globals_t * yg, uint16_t x, uint16_t y) { +static yutani_server_window_t * top_at(yutani_globals_t * yg, uint16_t x, uint16_t y) { if (check_top_at(yg, yg->top_z, x, y)) return yg->top_z; foreachr(node, yg->mid_zs) { yutani_server_window_t * w = node->value; @@ -703,12 +650,12 @@ static void set_focused_at(yutani_globals_t * yg, int x, int y) { * In the future, these single-item "stacks" will be replaced with dedicated stacks * so we can have multiple background windows and multiple panels / always-top windows. */ -static int window_is_top(yutani_globals_t * yg, yutani_server_window_t * window) { +int yutani_window_is_top(yutani_globals_t * yg, yutani_server_window_t * window) { /* For now, just use simple z-order */ return window->z == YUTANI_ZORDER_TOP; } -static int window_is_bottom(yutani_globals_t * yg, yutani_server_window_t * window) { +int yutani_window_is_bottom(yutani_globals_t * yg, yutani_server_window_t * window) { /* For now, just use simple z-order */ return window->z == YUTANI_ZORDER_BOTTOM; } @@ -718,7 +665,7 @@ static int window_is_bottom(yutani_globals_t * yg, yutani_server_window_t * wind * * Makes a pretty rainbow pattern. */ -static uint32_t color_for_wid(yutani_wid_t wid) { +uint32_t yutani_color_for_wid(yutani_wid_t wid) { static uint32_t colors[] = { 0xFF19aeff, 0xFFff4141, @@ -743,60 +690,22 @@ static uint32_t color_for_wid(yutani_wid_t wid) { * Blit a window to the framebuffer. * * Applies transformations (rotation, animations) and then renders - * the window with Cairo. + * the window through alpha blitting. */ -static int yutani_blit_window(yutani_globals_t * yg, cairo_t * ctx, yutani_server_window_t * window, int x, int y) { - - /* Obtain the previously initialized cairo contexts */ - cairo_t * cr = ctx; - - /* Window stride is always 4 bytes per pixel... */ - int stride = window->width * 4; - - /* Initialize a cairo surface object for this window */ - cairo_surface_t * surf = cairo_image_surface_create_for_data( - window->buffer, CAIRO_FORMAT_ARGB32, window->width, window->height, stride); - - /* Save cairo context */ - cairo_save(cr); - - /* - * Offset the rendering context appropriately for the position of the window - * based on the modifier paramters - */ - cairo_translate(cr, x, y); - - /* Top and bottom windows can not be rotated. */ - if (!window_is_top(yg, window) && !window_is_bottom(yg, window)) { - /* Calcuate radians from degrees */ - - /* XXX Window rotation is disabled until damage rects can take it into account */ - if (window->rotation != 0) { - double r = M_PI * (((double)window->rotation) / 180.0); - - /* Rotate the render context about the center of the window */ - cairo_translate(cr, (int)( window->width / 2), (int)( (int)window->height / 2)); - cairo_rotate(cr, r); - cairo_translate(cr, (int)(-window->width / 2), (int)(-window->height / 2)); - - /* Prefer faster filter when rendering rotated windows */ - cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST); - } - - if (window == yg->resizing_window) { - double x_scale = (double)yg->resizing_w / (double)yg->resizing_window->width; - double y_scale = (double)yg->resizing_h / (double)yg->resizing_window->height; - if (x_scale < 0.00001) { - x_scale = 0.00001; - } - if (y_scale < 0.00001) { - y_scale = 0.00001; - } - cairo_translate(cr, (int)yg->resizing_offset_x, (int)yg->resizing_offset_y); - cairo_scale(cr, x_scale, y_scale); - } +static int yutani_blit_window(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y) { + if (renderer_blit_window) { + return renderer_blit_window(yg,window,x,y); } + + sprite_t _win_sprite; + _win_sprite.width = window->width; + _win_sprite.height = window->height; + _win_sprite.bitmap = (uint32_t *)window->buffer; + _win_sprite.masks = NULL; + _win_sprite.blank = 0; + _win_sprite.alpha = ALPHA_EMBEDDED; + if (window->anim_mode) { int frame = yutani_time_since(yg, window->anim_start); if (frame >= yutani_animation_lengths[window->anim_mode]) { @@ -821,18 +730,13 @@ static int yutani_blit_window(yutani_globals_t * yg, cairo_t * ctx, yutani_serve int t_x = (window->width * (1.0 - x)) / 2; int t_y = (window->height * (1.0 - x)) / 2; - if (!window_is_top(yg, window) && !window_is_bottom(yg, window) && - !(window->server_flags & YUTANI_WINDOW_FLAG_ALT_ANIMATION)) { - cairo_translate(cr, t_x, t_y); - cairo_scale(cr, x, x); - } + double opacity = time_diff * (double)(window->opacity) / 255.0; - cairo_set_source_surface(cr, surf, 0, 0); - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST); - if (window->opacity != 255) { - cairo_paint_with_alpha(cr, time_diff * (double)(window->opacity) / 255.0); + if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window) && + !(window->server_flags & YUTANI_WINDOW_FLAG_ALT_ANIMATION)) { + draw_sprite_scaled_alpha(yg->backend_ctx, &_win_sprite, window->x + t_x, window->y + t_y, window->width * x, window->height * x, opacity); } else { - cairo_paint_with_alpha(cr, time_diff); + draw_sprite_alpha(yg->backend_ctx, &_win_sprite, window->x, window->y, opacity); } } break; @@ -843,62 +747,86 @@ static int yutani_blit_window(yutani_globals_t * yg, cairo_t * ctx, yutani_serve } } else { draw_window: - /* Paint window */ - cairo_set_source_surface(cr, surf, 0, 0); if (window->opacity != 255) { - cairo_paint_with_alpha(cr, (float)(window->opacity)/255.0); + double opacity = (double)(window->opacity) / 255.0; + if (window == yg->resizing_window) { + draw_sprite_scaled_alpha(yg->backend_ctx, &_win_sprite, window->x + (int)yg->resizing_offset_x, window->y + (int)yg->resizing_offset_y, yg->resizing_w, yg->resizing_h, opacity); + } else { + if (window->rotation) { + draw_sprite_rotate(yg->backend_ctx, &_win_sprite, window->x + window->width / 2, window->y + window->height / 2, (double)window->rotation * M_PI / 180.0, opacity); + } else { + draw_sprite_alpha(yg->backend_ctx, &_win_sprite, window->x, window->y, opacity); + } + } } else { - cairo_paint(cr); + if (window == yg->resizing_window) { + draw_sprite_scaled(yg->backend_ctx, &_win_sprite, window->x + (int)yg->resizing_offset_x, window->y + (int)yg->resizing_offset_y, yg->resizing_w, yg->resizing_h); + } else { + if (window->rotation) { + draw_sprite_rotate(yg->backend_ctx, &_win_sprite, window->x + window->width / 2, window->y + window->height / 2, (double)window->rotation * M_PI / 180.0, 1.0); + } else { + draw_sprite(yg->backend_ctx, &_win_sprite, window->x, window->y); + } + } + } + } +draw_finish: + + return 0; +} + +/** + * VirtualBox Seamless desktop driver. + * + * Sends rectangles describing all the non-background windows + * to the VirtualBox Guest Additions driver for use with the + * seamless desktop mode. + */ +static void yutani_post_vbox_rects(yutani_globals_t * yg) { + if (yg->vbox_rects <= 0) return; + + char tmp[4096]; + uint32_t * count = (uint32_t *)tmp; + *count = 0; + int32_t * magic = (int32_t *)tmp; + magic++; + + /* Add top window if it exists */ + if (yg->top_z) { + *magic = yg->top_z->x; magic++; + *magic = yg->top_z->y; magic++; + *magic = yg->top_z->x + yg->top_z->width; magic++; + *magic = yg->top_z->y + yg->top_z->height; magic++; + (*count)++; + } + + /* Add regular windows */ + foreach (node, yg->mid_zs) { + yutani_server_window_t * w = node->value; + if (w) { + *magic = w->x; magic++; + *magic = w->y; magic++; + *magic = w->x + w->width; magic++; + *magic = w->y + w->height; magic++; + (*count)++; + if (*count == 254) break; } } -draw_finish: - - /* Clean up */ - cairo_surface_destroy(surf); - - - /* Restore context stack */ - cairo_restore(cr); - -#if YUTANI_DEBUG_WINDOW_BOUNDS /* - * If window bound debugging is enabled, we also draw a box - * representing the rectangular (possibly rotated) boundary - * for a window texture. + * If there were no windows, show the whole desktop + * so we can see, eg., the login screen. */ - if (yg->debug_bounds) { - cairo_save(cr); - - int32_t t_x, t_y; - int32_t s_x, s_y; - int32_t r_x, r_y; - int32_t q_x, q_y; - - window_to_device(window, 0, 0, &t_x, &t_y); - window_to_device(window, window->width, window->height, &s_x, &s_y); - window_to_device(window, 0, window->height, &r_x, &r_y); - window_to_device(window, window->width, 0, &q_x, &q_y); - - uint32_t x = color_for_wid(window->wid); - cairo_set_source_rgba(cr, - _RED(x) / 255.0, - _GRE(x) / 255.0, - _BLU(x) / 255.0, - 0.7 - ); - - cairo_move_to(cr, t_x, t_y); - cairo_line_to(cr, r_x, r_y); - cairo_line_to(cr, s_x, s_y); - cairo_line_to(cr, q_x, q_y); - cairo_fill(cr); - - cairo_restore(cr); + if (*count == 0) { + *count = 1; + *magic = 0; magic++; + *magic = 0; magic++; + *magic = yg->width; magic++; + *magic = yg->height; magic++; } -#endif - return 0; + /* Post rectangle data to driver */ + write(yg->vbox_rects, tmp, sizeof(tmp)); } /** @@ -906,48 +834,57 @@ draw_finish: * * This is called for rendering and for screenshots. */ -static void yutani_blit_windows(yutani_globals_t * yg, cairo_t * ctx) { - if (yg->bottom_z) yutani_blit_window(yg, ctx, yg->bottom_z, yg->bottom_z->x, yg->bottom_z->y); +static void yutani_blit_windows(yutani_globals_t * yg) { + if (yg->bottom_z) yutani_blit_window(yg, yg->bottom_z, yg->bottom_z->x, yg->bottom_z->y); foreach (node, yg->mid_zs) { yutani_server_window_t * w = node->value; - if (w) yutani_blit_window(yg, ctx, w, w->x, w->y); + if (w) yutani_blit_window(yg, w, w->x, w->y); } - if (yg->top_z) yutani_blit_window(yg, ctx, yg->top_z, yg->top_z->x, yg->top_z->y); + if (yg->top_z) yutani_blit_window(yg, yg->top_z, yg->top_z->x, yg->top_z->y); } /** * Take a screenshot */ static void yutani_screenshot(yutani_globals_t * yg) { - int target_width; - int target_height; - void * target_data; + int task = yg->screenshot_frame; + yg->screenshot_frame = 0; - switch (yg->screenshot_frame) { - case YUTANI_SCREENSHOT_FULL: - target_width = yg->width; - target_height = yg->height; - target_data = yg->backend_framebuffer; - break; - case YUTANI_SCREENSHOT_WINDOW: - if (!yg->focused_window) goto screenshot_done; - target_width = yg->focused_window->width; - target_height = yg->focused_window->height; - target_data = yg->focused_window->buffer; - break; - default: - /* ??? */ - goto screenshot_done; + /* raw screenshots */ + FILE * f = fopen("/tmp/screenshot.rgba", "w"); + if (!f) { + TRACE("Error opening output file for screenshot."); + return; } - cairo_surface_t * s = cairo_image_surface_create_for_data(target_data, CAIRO_FORMAT_ARGB32, target_width, target_height, target_width * 4); + uint32_t * buffer = NULL; + int width, height; - cairo_surface_write_to_png(s, "/tmp/screenshot.png"); + if (task == YUTANI_SCREENSHOT_FULL) { + buffer = (void *)yg->backend_ctx->backbuffer; + width = yg->width; + height = yg->height; + } else if (task == YUTANI_SCREENSHOT_WINDOW) { + yutani_server_window_t * window = yg->focused_window; + buffer = (void *)window->buffer; + width = window->width; + height = window->height; + } - cairo_surface_destroy(s); - -screenshot_done: - yg->screenshot_frame = 0; + if (buffer) { + for (int y = 0; y mouse_x; int tmp_mouse_y = yg->mouse_y; + if (yg->resize_on_next) { + spin_lock(&yg->redraw_lock); + TRACE("Resizing display."); + + if (!yutani_options.nested) { + reinit_graphics_fullscreen(yg->backend_ctx); + } else { + reinit_graphics_yutani(yg->backend_ctx, yg->host_window); + yutani_window_resize_done(yg->host_context, yg->host_window); + } + TRACE("graphics context resized..."); + yg->width = yg->backend_ctx->width; + yg->height = yg->backend_ctx->height; + yg->backend_framebuffer = yg->backend_ctx->backbuffer; + + if (renderer_destroy) renderer_destroy(yg); + if (renderer_init) renderer_init(yg); + + TRACE("Marking..."); + yg->resize_on_next = 0; + mark_screen(yg, 0, 0, yg->width, yg->height); + + TRACE("Sending welcome messages..."); + yutani_msg_buildx_welcome_alloc(response); + yutani_msg_buildx_welcome(response, yg->width, yg->height); + pex_broadcast(yg->server, response->size, (char *)response); + TRACE("Done."); + + spin_unlock(&yg->redraw_lock); + } + + if (renderer_push_state) renderer_push_state(yg); + /* If the mouse has moved, that counts as two damage regions */ if ((yg->last_mouse_x != tmp_mouse_x) || (yg->last_mouse_y != tmp_mouse_y)) { has_updates = 2; @@ -998,7 +966,11 @@ static void redraw_windows(yutani_globals_t * yg) { /* Render */ if (has_updates) { - yutani_set_clip(yg); + if (!yg->bottom_z || yg->bottom_z->anim_mode) { + draw_fill(yg->backend_ctx, rgb(110,110,110)); + } + + if (renderer_set_clip) renderer_set_clip(yg); yg->windows_to_remove = list_create(); @@ -1008,7 +980,10 @@ static void redraw_windows(yutani_globals_t * yg) { * we also need to render windows in stacking order... */ spin_lock(&yg->redraw_lock); - yutani_blit_windows(yg, yg->framebuffer_ctx); + yutani_blit_windows(yg); + + /* Send VirtualBox rects */ + yutani_post_vbox_rects(yg); #if YUTANI_DEBUG_WINDOW_SHAPES #define WINDOW_SHAPE_VIEWER_SIZE 20 @@ -1024,14 +999,18 @@ static void redraw_windows(yutani_globals_t * yg) { for (int y = _ly; y < _hy; ++y) { for (int x = _lx; x < _hx; ++x) { yutani_server_window_t * w = top_at(yg, x, y); - if (w) { GFX(yg->backend_ctx, x, y) = color_for_wid(w->wid); } + if (w) { GFX(yg->backend_ctx, x, y) = yutani_color_for_wid(w->wid); } } } } #endif if (yutani_options.nested) { - flip(yg->backend_ctx); + if (renderer_blit_screen) { + renderer_blit_screen(yg); + } else { + flip(yg->backend_ctx); + } /* * We should be able to flip only the places we need to flip, but * instead we're going to flip the whole thing. @@ -1061,18 +1040,22 @@ static void redraw_windows(yutani_globals_t * yg) { * Flip the updated areas. This minimizes writes to video memory, * which is very important on real hardware where these writes are slow. */ - cairo_set_operator(yg->real_ctx, CAIRO_OPERATOR_SOURCE); - cairo_translate(yg->real_ctx, 0, 0); - cairo_set_source_surface(yg->real_ctx, yg->framebuffer_surface, 0, 0); - cairo_paint(yg->real_ctx); + if (renderer_blit_screen) { + renderer_blit_screen(yg); + } else { + flip(yg->backend_ctx); + } } + + if (!renderer_add_clip) gfx_clear_clip(yg->backend_ctx); + spin_unlock(&yg->redraw_lock); /* * If any windows were marked for removal, * then remove them. */ - while (yg->windows_to_remove->head) { + while (yg->windows_to_remove->tail) { node_t * node = list_pop(yg->windows_to_remove); window_actually_close(yg, node->value); @@ -1083,67 +1066,25 @@ static void redraw_windows(yutani_globals_t * yg) { } + if (renderer_pop_state) renderer_pop_state(yg); + if (yg->screenshot_frame) { yutani_screenshot(yg); } - /* Restore the cairo contexts to reset clip regions */ - restore_cairo_states(yg); - - if (yg->resize_on_next) { - spin_lock(&yg->redraw_lock); - - cairo_destroy(yg->framebuffer_ctx); - cairo_destroy(yg->real_ctx); - cairo_surface_destroy(yg->framebuffer_surface); - cairo_surface_destroy(yg->real_surface); - - if (!yutani_options.nested) { - reinit_graphics_fullscreen(yg->backend_ctx); - yg->stride = framebuffer_stride(); - } else { - reinit_graphics_yutani(yg->backend_ctx, yg->host_window); - yg->stride = yg->backend_ctx->width * 4; - yutani_window_resize_done(yg->host_context, yg->host_window); - } - yg->width = yg->backend_ctx->width; - yg->height = yg->backend_ctx->height; - yg->backend_framebuffer = yg->backend_ctx->backbuffer; - - int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, yg->width); - yg->framebuffer_surface = cairo_image_surface_create_for_data( - yg->backend_framebuffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride); - yg->real_surface = cairo_image_surface_create_for_data( - yg->backend_ctx->buffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, yg->stride); - - yg->framebuffer_ctx = cairo_create(yg->framebuffer_surface); - yg->real_ctx = cairo_create(yg->real_surface); - - yg->resize_on_next = 0; - mark_screen(yg, 0, 0, yg->width, yg->height); - - yutani_msg_t * response = yutani_msg_build_welcome(yg->width, yg->height); - pex_broadcast(yg->server, response->size, (char *)response); - free(response); - - spin_unlock(&yg->redraw_lock); + if (yg->reload_renderer) { + yg->reload_renderer = 0; + /* Otherwise we won't draw the cursor... */ + gfx_no_clip(yg->backend_ctx); + try_load_extensions(yg); } } /** - * Initialize cairo contexts and surfaces for the framebuffers. + * Initialize clipping regions. */ -void yutani_cairo_init(yutani_globals_t * yg) { - - int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, yg->width); - yg->framebuffer_surface = cairo_image_surface_create_for_data( - yg->backend_framebuffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride); - yg->real_surface = cairo_image_surface_create_for_data( - yg->backend_ctx->buffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, yg->stride); - - yg->framebuffer_ctx = cairo_create(yg->framebuffer_surface); - yg->real_ctx = cairo_create(yg->real_surface); +void yutani_clip_init(yutani_globals_t * yg) { yg->update_list = list_create(); yg->update_list_lock = 0; @@ -1155,12 +1096,12 @@ void yutani_cairo_init(yutani_globals_t * yg) { * Calls the redraw functions in a loop, with some * additional yielding and sleeping. */ -void * redraw(void * in) { +static void * redraw(void * in) { syscall_system_function(11,(char *[]){"compositor","render thread",NULL}); yutani_globals_t * yg = in; - while (1) { + while (yg->server) { /* * Perform whatever redraw work is required. */ @@ -1176,6 +1117,8 @@ void * redraw(void * in) { */ usleep(16666); } + + return NULL; } /** @@ -1215,10 +1158,10 @@ static void mark_window_relative(yutani_globals_t * yg, yutani_server_window_t * int32_t ur_x, ur_y; int32_t lr_x, lr_y; - window_to_device(window, x, y, &ul_x, &ul_y); - window_to_device(window, x, y + height, &ll_x, &ll_y); - window_to_device(window, x + width, y, &ur_x, &ur_y); - window_to_device(window, x + width, y + height, &lr_x, &lr_y); + yutani_window_to_device(window, x, y, &ul_x, &ul_y); + yutani_window_to_device(window, x, y + height, &ll_x, &ll_y); + yutani_window_to_device(window, x + width, y, &ur_x, &ur_y); + yutani_window_to_device(window, x + width, y + height, &lr_x, &lr_y); /* Calculate bounds */ @@ -1327,9 +1270,9 @@ static uint32_t ad_flags(yutani_globals_t * yg, yutani_server_window_t * win) { */ static void yutani_query_result(yutani_globals_t * yg, uint32_t dest, yutani_server_window_t * win) { if (win && win->client_length) { - yutani_msg_t * response = yutani_msg_build_window_advertise(win->wid, ad_flags(yg, win), win->client_offsets, win->client_length, win->client_strings); + yutani_msg_buildx_window_advertise_alloc(response, win->client_length); + yutani_msg_buildx_window_advertise(response, win->wid, ad_flags(yg, win), win->client_offsets, win->client_length, win->client_strings); pex_send(yg->server, dest, response->size, (char *)response); - free(response); } } @@ -1337,7 +1280,8 @@ static void yutani_query_result(yutani_globals_t * yg, uint32_t dest, yutani_ser * Send a notice to all subscribed clients that windows have updated. */ static void notify_subscribers(yutani_globals_t * yg) { - yutani_msg_t * response = yutani_msg_build_notify(); + yutani_msg_buildx_notify_alloc(response); + yutani_msg_buildx_notify(response); list_t * remove = NULL; foreach(node, yg->window_subscribers) { uint32_t subscriber = (uint32_t)node->value; @@ -1358,7 +1302,6 @@ static void notify_subscribers(yutani_globals_t * yg) { } free(remove); } - free(response); } static void window_move(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y) { @@ -1367,7 +1310,8 @@ static void window_move(yutani_globals_t * yg, yutani_server_window_t * window, window->y = y; mark_window(yg, window); - yutani_msg_t * response = yutani_msg_build_window_move(window->wid, x, y); + yutani_msg_buildx_window_move_alloc(response); + yutani_msg_buildx_window_move(response, window->wid, x, y); pex_send(yg->server, window->owner, response->size, (char *)response); } @@ -1390,6 +1334,8 @@ static void window_tile(yutani_globals_t * yg, yutani_server_window_t * window, if (!window->tiled) { window->untiled_width = window->width; window->untiled_height = window->height; + window->untiled_left = window->x; + window->untiled_top = window->y; window->tiled = 1; } @@ -1406,10 +1352,20 @@ static void window_tile(yutani_globals_t * yg, yutani_server_window_t * window, h = (yg->height - panel_h) - h * y; } - yutani_msg_t * response = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_OFFER, window->wid, w, h, 0); + yutani_msg_buildx_window_resize_alloc(response); + yutani_msg_buildx_window_resize(response, YUTANI_MSG_RESIZE_OFFER, window->wid, w, h, 0, YUTANI_RESIZE_TILED); + pex_send(yg->server, window->owner, response->size, (char *)response); +} + +/** + * Take a previously tiled window and "untile" it, eg. restore its original size. + */ +static void window_untile(yutani_globals_t * yg, yutani_server_window_t * window) { + window->tiled = 0; + + yutani_msg_buildx_window_resize_alloc(response); + yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_OFFER, window->wid, window->untiled_width, window->untiled_height, 0, 0); pex_send(yg->server, window->owner, response->size, (char *)response); - free(response); - return; } /** @@ -1422,8 +1378,9 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event yutani_server_window_t * focused = get_focused(yg); memcpy(&yg->kbd_state, &ke->state, sizeof(key_event_state_t)); if (focused) { +#if 1 if ((ke->event.action == KEY_ACTION_DOWN) && - (ke->event.modifiers & KEY_MOD_LEFT_CTRL) && + (ke->event.modifiers & KEY_MOD_LEFT_SUPER) && (ke->event.modifiers & KEY_MOD_LEFT_SHIFT) && (ke->event.keycode == 'z')) { mark_window(yg,focused); @@ -1432,7 +1389,7 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event return; } if ((ke->event.action == KEY_ACTION_DOWN) && - (ke->event.modifiers & KEY_MOD_LEFT_CTRL) && + (ke->event.modifiers & KEY_MOD_LEFT_SUPER) && (ke->event.modifiers & KEY_MOD_LEFT_SHIFT) && (ke->event.keycode == 'x')) { mark_window(yg,focused); @@ -1441,7 +1398,7 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event return; } if ((ke->event.action == KEY_ACTION_DOWN) && - (ke->event.modifiers & KEY_MOD_LEFT_CTRL) && + (ke->event.modifiers & KEY_MOD_LEFT_SUPER) && (ke->event.modifiers & KEY_MOD_LEFT_SHIFT) && (ke->event.keycode == 'c')) { mark_window(yg,focused); @@ -1449,11 +1406,17 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event mark_window(yg,focused); return; } +#endif if ((ke->event.action == KEY_ACTION_DOWN) && (ke->event.modifiers & KEY_MOD_LEFT_ALT) && (ke->event.keycode == KEY_F10)) { if (focused->z != YUTANI_ZORDER_BOTTOM && focused->z != YUTANI_ZORDER_TOP) { - window_tile(yg, focused, 1, 1, 0, 0); + if (focused->tiled) { + window_untile(yg, focused); + window_move(yg, focused, focused->untiled_left, focused->untiled_top); + } else { + window_tile(yg, focused, 1, 1, 0, 0); + } return; } } @@ -1461,24 +1424,24 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event (ke->event.modifiers & KEY_MOD_LEFT_ALT) && (ke->event.keycode == KEY_F4)) { if (focused->z != YUTANI_ZORDER_BOTTOM && focused->z != YUTANI_ZORDER_TOP) { - yutani_msg_t * response = yutani_msg_build_session_end(); + yutani_msg_buildx_window_close_alloc(response); + yutani_msg_buildx_window_close(response, focused->wid); pex_send(yg->server, focused->owner, response->size, (char *)response); - free(response); return; } } #if YUTANI_DEBUG_WINDOW_SHAPES if ((ke->event.action == KEY_ACTION_DOWN) && - (ke->event.modifiers & KEY_MOD_LEFT_CTRL) && + (ke->event.modifiers & KEY_MOD_LEFT_SUPER) && (ke->event.modifiers & KEY_MOD_LEFT_SHIFT) && - (ke->event.keycode == 'v')) { + (ke->event.keycode == 'n')) { yg->debug_shapes = (1-yg->debug_shapes); return; } #endif #if YUTANI_DEBUG_WINDOW_BOUNDS if ((ke->event.action == KEY_ACTION_DOWN) && - (ke->event.modifiers & KEY_MOD_LEFT_CTRL) && + (ke->event.modifiers & KEY_MOD_LEFT_SUPER) && (ke->event.modifiers & KEY_MOD_LEFT_SHIFT) && (ke->event.keycode == 'b')) { yg->debug_bounds = (1-yg->debug_bounds); @@ -1563,9 +1526,9 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event if (hashmap_has(yg->key_binds, (void*)key_code)) { struct key_bind * bind = hashmap_get(yg->key_binds, (void*)key_code); - yutani_msg_t * response = yutani_msg_build_key_event(focused ? focused->wid : -1, &ke->event, &ke->state); + yutani_msg_buildx_key_event_alloc(response); + yutani_msg_buildx_key_event(response,focused ? focused->wid : UINT32_MAX, &ke->event, &ke->state); pex_send(yg->server, bind->owner, response->size, (char *)response); - free(response); if (bind->response == YUTANI_BIND_STEAL) { /* If this keybinding was registered as "steal", we'll stop here. */ @@ -1576,9 +1539,9 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event /* Finally, send the key to the focused client. */ if (focused) { - yutani_msg_t * response = yutani_msg_build_key_event(focused->wid, &ke->event, &ke->state); + yutani_msg_buildx_key_event_alloc(response); + yutani_msg_buildx_key_event(response,focused->wid, &ke->event, &ke->state); pex_send(yg->server, focused->owner, response->size, (char *)response); - free(response); } } @@ -1662,7 +1625,7 @@ static void mouse_start_rotate(yutani_globals_t * yg) { yg->mouse_init_y = yg->mouse_y; int32_t x_diff = yg->mouse_x / MOUSE_SCALE - (yg->mouse_window->x + yg->mouse_window->width / 2); int32_t y_diff = yg->mouse_y / MOUSE_SCALE - (yg->mouse_window->y + yg->mouse_window->height / 2); - int new_r = atan2(x_diff, y_diff) * 180.0 / (-M_PI); + int new_r = __builtin_atan2(x_diff, y_diff) * 180.0 / (-M_PI); yg->mouse_init_r = yg->mouse_window->rotation - new_r; make_top(yg, yg->mouse_window); } @@ -1694,7 +1657,7 @@ static void mouse_start_resize(yutani_globals_t * yg, yutani_scale_direction_t d if (direction == SCALE_AUTO) { /* Determine the best direction to scale in based on simple 9-cell system. */ int32_t x, y; - device_to_window(yg->resizing_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); + yutani_device_to_window(yg->resizing_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); int h_d = 0; int v_d = 0; @@ -1742,8 +1705,8 @@ static void handle_mouse_event(yutani_globals_t * yg, struct yutani_msg_mouse_ev if (yg->mouse_x < 0) yg->mouse_x = 0; if (yg->mouse_y < 0) yg->mouse_y = 0; - if (yg->mouse_x > (yg->width) * MOUSE_SCALE) yg->mouse_x = (yg->width) * MOUSE_SCALE; - if (yg->mouse_y > (yg->height) * MOUSE_SCALE) yg->mouse_y = (yg->height) * MOUSE_SCALE; + if (yg->mouse_x > (int)(yg->width) * MOUSE_SCALE) yg->mouse_x = (yg->width) * MOUSE_SCALE; + if (yg->mouse_y > (int)(yg->height) * MOUSE_SCALE) yg->mouse_y = (yg->height) * MOUSE_SCALE; switch (yg->mouse_state) { case YUTANI_MOUSE_STATE_NORMAL: @@ -1766,44 +1729,41 @@ static void handle_mouse_event(yutani_globals_t * yg, struct yutani_msg_mouse_ev yg->mouse_moved = 0; yg->mouse_drag_button = YUTANI_MOUSE_BUTTON_LEFT; if (yg->mouse_window) { - device_to_window(yg->mouse_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &yg->mouse_click_x, &yg->mouse_click_y); - yutani_msg_t * response = yutani_msg_build_window_mouse_event(yg->mouse_window->wid, yg->mouse_click_x, yg->mouse_click_y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_DOWN); + yutani_device_to_window(yg->mouse_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &yg->mouse_click_x, &yg->mouse_click_y); + yutani_msg_buildx_window_mouse_event_alloc(response); + yutani_msg_buildx_window_mouse_event(response,yg->mouse_window->wid, yg->mouse_click_x, yg->mouse_click_y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_DOWN); yg->mouse_click_x_orig = yg->mouse_click_x; yg->mouse_click_y_orig = yg->mouse_click_y; pex_send(yg->server, yg->mouse_window->owner, response->size, (char *)response); - free(response); } } else { yg->mouse_window = get_focused(yg); yutani_server_window_t * tmp_window = top_at(yg, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE); - if (yg->mouse_window) { + if (yg->mouse_window && !(me->event.buttons & YUTANI_MOUSE_BUTTON_RIGHT)) { int32_t x, y; - device_to_window(yg->mouse_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); - yutani_msg_t * response = yutani_msg_build_window_mouse_event(yg->mouse_window->wid, x, y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_MOVE); + yutani_device_to_window(yg->mouse_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); + yutani_msg_buildx_window_mouse_event_alloc(response); + yutani_msg_buildx_window_mouse_event(response,yg->mouse_window->wid, x, y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_MOVE); pex_send(yg->server, yg->mouse_window->owner, response->size, (char *)response); - free(response); } if (tmp_window) { int32_t x, y; - yutani_msg_t * response; + yutani_msg_buildx_window_mouse_event_alloc(response); if (tmp_window != yg->old_hover_window) { - device_to_window(tmp_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); - response = yutani_msg_build_window_mouse_event(tmp_window->wid, x, y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_ENTER); + yutani_device_to_window(tmp_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); + yutani_msg_buildx_window_mouse_event(response, tmp_window->wid, x, y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_ENTER); pex_send(yg->server, tmp_window->owner, response->size, (char *)response); - free(response); if (yg->old_hover_window) { - device_to_window(yg->old_hover_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); - response = yutani_msg_build_window_mouse_event(yg->old_hover_window->wid, x, y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_LEAVE); + yutani_device_to_window(yg->old_hover_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); + yutani_msg_buildx_window_mouse_event(response, yg->old_hover_window->wid, x, y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_LEAVE); pex_send(yg->server, yg->old_hover_window->owner, response->size, (char *)response); - free(response); } yg->old_hover_window = tmp_window; } - if (tmp_window != yg->mouse_window) { - device_to_window(tmp_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); - response = yutani_msg_build_window_mouse_event(tmp_window->wid, x, y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_MOVE); + if (tmp_window != yg->mouse_window || (me->event.buttons & YUTANI_MOUSE_BUTTON_RIGHT)) { + yutani_device_to_window(tmp_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &x, &y); + yutani_msg_buildx_window_mouse_event(response, tmp_window->wid, x, y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_MOVE); pex_send(yg->server, tmp_window->owner, response->size, (char *)response); - free(response); } } } @@ -1818,25 +1778,33 @@ static void handle_mouse_event(yutani_globals_t * yg, struct yutani_msg_mouse_ev yg->mouse_state = YUTANI_MOUSE_STATE_NORMAL; mark_screen(yg, yg->mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X, yg->mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y, MOUSE_WIDTH, MOUSE_HEIGHT); } else { - if (yg->mouse_y / MOUSE_SCALE < 2) { - window_tile(yg, yg->mouse_window, 1, 1, 0, 0); - yg->mouse_window = NULL; - yg->mouse_state = YUTANI_MOUSE_STATE_NORMAL; + if (yg->mouse_y / MOUSE_SCALE < 10) { + if (!yg->mouse_window->tiled) { + window_tile(yg, yg->mouse_window, 1, 1, 0, 0); + } + break; + } + if (yg->mouse_x / MOUSE_SCALE < 10) { + if (!yg->mouse_window->tiled) { + window_tile(yg, yg->mouse_window, 2, 1, 0, 0); + } + break; + } else if (yg->mouse_x / MOUSE_SCALE >= ((int)yg->width - 10)) { + if (!yg->mouse_window->tiled) { + window_tile(yg, yg->mouse_window, 2, 1, 1, 0); + } break; } if (yg->mouse_window->tiled) { if ((abs(yg->mouse_x - yg->mouse_init_x) > UNTILE_SENSITIVITY) || (abs(yg->mouse_y - yg->mouse_init_y) > UNTILE_SENSITIVITY)) { - /* Untile it */ - yg->mouse_window->tiled = 0; + /* Untile it */ + window_untile(yg,yg->mouse_window); /* Position the window such that it's representative of where it was, percentage-wise, in the untiled window */ float percent_x = (float)(yg->mouse_x / MOUSE_SCALE - yg->mouse_window->x) / (float)yg->mouse_window->width; float percent_y = (float)(yg->mouse_y / MOUSE_SCALE - yg->mouse_window->y) / (float)yg->mouse_window->height; window_move(yg, yg->mouse_window, yg->mouse_x / MOUSE_SCALE - yg->mouse_window->untiled_width * percent_x, yg->mouse_y / MOUSE_SCALE - yg->mouse_window->untiled_height * percent_y); - yutani_msg_t * response = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_OFFER, yg->mouse_window->wid, yg->mouse_window->untiled_width, yg->mouse_window->untiled_height, 0); - pex_send(yg->server, yg->mouse_window->owner, response->size, (char *)response); - free(response); /* reset init_x / init_y */ yg->mouse_init_x = yg->mouse_x; yg->mouse_init_y = yg->mouse_y; @@ -1877,15 +1845,15 @@ static void handle_mouse_event(yutani_globals_t * yg, struct yutani_msg_mouse_ev int32_t old_x = yg->mouse_click_x_orig; int32_t old_y = yg->mouse_click_y_orig; if (yg->mouse_window) { - device_to_window(yg->mouse_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &yg->mouse_click_x, &yg->mouse_click_y); + yutani_device_to_window(yg->mouse_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &yg->mouse_click_x, &yg->mouse_click_y); if (!yg->mouse_moved) { - yutani_msg_t * response = yutani_msg_build_window_mouse_event(yg->mouse_window->wid, yg->mouse_click_x, yg->mouse_click_y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_CLICK); + yutani_msg_buildx_window_mouse_event_alloc(response); + yutani_msg_buildx_window_mouse_event(response,yg->mouse_window->wid, yg->mouse_click_x, yg->mouse_click_y, -1, -1, me->event.buttons, YUTANI_MOUSE_EVENT_CLICK); pex_send(yg->server, yg->mouse_window->owner, response->size, (char *)response); - free(response); } else { - yutani_msg_t * response = yutani_msg_build_window_mouse_event(yg->mouse_window->wid, yg->mouse_click_x, yg->mouse_click_y, old_x, old_y, me->event.buttons, YUTANI_MOUSE_EVENT_RAISE); + yutani_msg_buildx_window_mouse_event_alloc(response); + yutani_msg_buildx_window_mouse_event(response,yg->mouse_window->wid, yg->mouse_click_x, yg->mouse_click_y, old_x, old_y, me->event.buttons, YUTANI_MOUSE_EVENT_RAISE); pex_send(yg->server, yg->mouse_window->owner, response->size, (char *)response); - free(response); } } } else { @@ -1894,11 +1862,11 @@ static void handle_mouse_event(yutani_globals_t * yg, struct yutani_msg_mouse_ev int32_t old_x = yg->mouse_click_x; int32_t old_y = yg->mouse_click_y; if (yg->mouse_window) { - device_to_window(yg->mouse_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &yg->mouse_click_x, &yg->mouse_click_y); + yutani_device_to_window(yg->mouse_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &yg->mouse_click_x, &yg->mouse_click_y); if (old_x != yg->mouse_click_x || old_y != yg->mouse_click_y) { - yutani_msg_t * response = yutani_msg_build_window_mouse_event(yg->mouse_window->wid, yg->mouse_click_x, yg->mouse_click_y, old_x, old_y, me->event.buttons, YUTANI_MOUSE_EVENT_DRAG); + yutani_msg_buildx_window_mouse_event_alloc(response); + yutani_msg_buildx_window_mouse_event(response,yg->mouse_window->wid, yg->mouse_click_x, yg->mouse_click_y, old_x, old_y, me->event.buttons, YUTANI_MOUSE_EVENT_DRAG); pex_send(yg->server, yg->mouse_window->owner, response->size, (char *)response); - free(response); } } } @@ -1910,8 +1878,8 @@ static void handle_mouse_event(yutani_globals_t * yg, struct yutani_msg_mouse_ev int32_t relative_x, relative_y; int32_t relative_init_x, relative_init_y; - device_to_window(yg->resizing_window, yg->mouse_init_x / MOUSE_SCALE, yg->mouse_init_y / MOUSE_SCALE, &relative_init_x, &relative_init_y); - device_to_window(yg->resizing_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &relative_x, &relative_y); + yutani_device_to_window(yg->resizing_window, yg->mouse_init_x / MOUSE_SCALE, yg->mouse_init_y / MOUSE_SCALE, &relative_init_x, &relative_init_y); + yutani_device_to_window(yg->resizing_window, yg->mouse_x / MOUSE_SCALE, yg->mouse_y / MOUSE_SCALE, &relative_x, &relative_y); int width_diff = (relative_x - relative_init_x); int height_diff = (relative_y - relative_init_y); @@ -1975,17 +1943,17 @@ static void handle_mouse_event(yutani_globals_t * yg, struct yutani_msg_mouse_ev /* If the window is rotated, we need to move the center to be where the new center should be, but x/y are based on the unrotated upper left corner. */ /* The center always moves by one-half the resize dimensions */ int32_t center_x, center_y; - window_to_device(yg->resizing_window, yg->resizing_offset_x + yg->resizing_w / 2, yg->resizing_offset_y + yg->resizing_h / 2, ¢er_x, ¢er_y); + yutani_window_to_device(yg->resizing_window, yg->resizing_offset_x + yg->resizing_w / 2, yg->resizing_offset_y + yg->resizing_h / 2, ¢er_x, ¢er_y); x = center_x - yg->resizing_w / 2; y = center_y - yg->resizing_h / 2; } else { - window_to_device(yg->resizing_window, yg->resizing_offset_x, yg->resizing_offset_y, &x, &y); + yutani_window_to_device(yg->resizing_window, yg->resizing_offset_x, yg->resizing_offset_y, &x, &y); } TRACE("resize complete, now %d x %d", yg->resizing_w, yg->resizing_h); window_move(yg, yg->resizing_window, x,y); - yutani_msg_t * response = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_OFFER, yg->resizing_window->wid, yg->resizing_w, yg->resizing_h, 0); + yutani_msg_buildx_window_resize_alloc(response); + yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_OFFER, yg->resizing_window->wid, yg->resizing_w, yg->resizing_h, 0, yg->resizing_window->tiled); pex_send(yg->server, yg->resizing_window->owner, response->size, (char *)response); - free(response); yg->resizing_window = NULL; yg->mouse_window = NULL; yg->mouse_state = YUTANI_MOUSE_STATE_NORMAL; @@ -2023,12 +1991,15 @@ int main(int argc, char * argv[]) { yutani_window_move(yg->host_context, yg->host_window, 50, 50); yutani_window_advertise_icon(yg->host_context, yg->host_window, "Compositor", "compositor"); yg->backend_ctx = init_graphics_yutani_double_buffer(yg->host_window); - yg->stride = yg->backend_ctx->width * 4; } else { + char * d = getenv("DISPLAY"); + if (d && *d) { + fprintf(stderr, "DISPLAY is already set but not running nested. This is probably wrong.\n"); + return 1; + } _static_yg = yg; signal(SIGWINEVENT, yutani_display_resize_handle); yg->backend_ctx = init_graphics_fullscreen_double_buffer(); - yg->stride = framebuffer_stride(); } if (!yg->backend_ctx) { @@ -2047,14 +2018,14 @@ int main(int argc, char * argv[]) { yg->width = yg->backend_ctx->width; yg->height = yg->backend_ctx->height; - draw_fill(yg->backend_ctx, rgb(0,0,0)); + draw_fill(yg->backend_ctx, rgb(110,110,110)); flip(yg->backend_ctx); yg->backend_framebuffer = yg->backend_ctx->backbuffer; if (yutani_options.nested) { char * name = malloc(sizeof(char) * 64); - snprintf(name, 64, "compositor-nest-%d", getpid()); + sprintf(name, "compositor-nest-%d", getpid()); yg->server_ident = name; } else { /* XXX check if this already exists? */ @@ -2063,20 +2034,73 @@ int main(int argc, char * argv[]) { setenv("DISPLAY", yg->server_ident, 1); FILE * server = pex_bind(yg->server_ident); + TRACE("pex bound? %d", server); yg->server = server; TRACE("Loading fonts..."); - load_fonts(yg); + { + sprite_t _font_data[6]; + + load_sprite(&_font_data[0], "/usr/share/sdf_thin.bmp"); + load_sprite(&_font_data[1], "/usr/share/sdf_bold.bmp"); + load_sprite(&_font_data[2], "/usr/share/sdf_mono.bmp"); + load_sprite(&_font_data[3], "/usr/share/sdf_mono_bold.bmp"); + load_sprite(&_font_data[4], "/usr/share/sdf_mono_oblique.bmp"); + load_sprite(&_font_data[5], "/usr/share/sdf_mono_bold_oblique.bmp"); + + TRACE(" Data loaded..."); + + size_t font_data_size = sizeof(unsigned int) * (1 + 6 * 3); + for (int i = 0; i < 6; ++i) { + font_data_size += 4 * _font_data[i].width * _font_data[i].height; + } + + TRACE(" Size calculated: %d", font_data_size); + + char tmp[100]; + sprintf(tmp, "sys.%s.fonts", yg->server_ident); + size_t s = font_data_size; + char * font = (char *)syscall_shm_obtain(tmp, &s); + assert((s >= font_data_size) && "Font server failure."); + + uint32_t * data = (uint32_t *)font; + data[0] = 6; + + data[1] = _font_data[0].width; + data[2] = _font_data[0].height; + data[3] = (6 * 3 + 1) * sizeof(unsigned int); + memcpy(&font[data[3]], _font_data[0].bitmap, _font_data[0].width * _font_data[0].height * 4); + free(_font_data[0].bitmap); + + for (int i = 1; i < 6; ++i) { + TRACE(" Loaded %d font(s)... %d %d %d", i, data[(i - 1) * 3 + 2], data[(i - 1) * 3 + 1], data[(i - 1) * 3 + 3]); + data[i * 3 + 1] = _font_data[i].width; + data[i * 3 + 2] = _font_data[i].height; + data[i * 3 + 3] = data[(i - 1) * 3 + 3] + data[(i - 1) * 3 + 2] * data[(i - 1) * 3 + 1] * 4; + memcpy(&font[data[i * 3 + 3]], _font_data[i].bitmap, _font_data[i].width * _font_data[i].height * 4); + free(_font_data[i].bitmap); + } + + TRACE("Done loading fonts."); + } + + TRACE("Loading sprites..."); +#define MOUSE_DIR "/usr/share/cursor/" + load_sprite(&yg->mouse_sprite, MOUSE_DIR "mouse.bmp"); + yg->mouse_sprite.alpha = ALPHA_EMBEDDED; + load_sprite(&yg->mouse_sprite_drag, MOUSE_DIR "drag.bmp"); + yg->mouse_sprite_drag.alpha = ALPHA_EMBEDDED; + load_sprite(&yg->mouse_sprite_resize_v, MOUSE_DIR "resize-vertical.bmp"); + yg->mouse_sprite_resize_v.alpha = ALPHA_EMBEDDED; + load_sprite(&yg->mouse_sprite_resize_h, MOUSE_DIR "resize-horizontal.bmp"); + yg->mouse_sprite_resize_h.alpha = ALPHA_EMBEDDED; + load_sprite(&yg->mouse_sprite_resize_da, MOUSE_DIR "resize-uldr.bmp"); + yg->mouse_sprite_resize_da.alpha = ALPHA_EMBEDDED; + load_sprite(&yg->mouse_sprite_resize_db, MOUSE_DIR "resize-dlur.bmp"); + yg->mouse_sprite_resize_db.alpha = ALPHA_EMBEDDED; TRACE("Done."); - load_sprite_png(&yg->mouse_sprite, "/usr/share/cursor/normal.png"); - - load_sprite_png(&yg->mouse_sprite_drag, "/usr/share/cursor/drag.png"); - load_sprite_png(&yg->mouse_sprite_resize_v, "/usr/share/cursor/resize-vertical.png"); - load_sprite_png(&yg->mouse_sprite_resize_h, "/usr/share/cursor/resize-horizontal.png"); - load_sprite_png(&yg->mouse_sprite_resize_da, "/usr/share/cursor/resize-uldr.png"); - load_sprite_png(&yg->mouse_sprite_resize_db, "/usr/share/cursor/resize-dlur.png"); - + TRACE("Initializing variables..."); yg->last_mouse_x = 0; yg->last_mouse_y = 0; yg->mouse_x = yg->width * MOUSE_SCALE / 2; @@ -2091,11 +2115,16 @@ int main(int argc, char * argv[]) { yg->window_subscribers = list_create(); yg->last_mouse_buttons = 0; + TRACE("Done."); - yutani_cairo_init(yg); + /* Try to load Cairo backend */ + try_load_extensions(yg); + + yutani_clip_init(yg); pthread_t render_thread; + TRACE("Starting render thread."); pthread_create(&render_thread, NULL, redraw, yg); if (!fork()) { @@ -2103,12 +2132,17 @@ int main(int argc, char * argv[]) { TRACE("Starting alternate startup app: %s", argv[argx]); execvp(argv[argx], &argv[argx]); } else { - char * args[] = {"/bin/glogin", NULL}; + TRACE("Starting application"); + char * args[] = {"/bin/session", NULL}; execvp(args[0], args); + TRACE("Failed to start app?"); } } - int fds[4], mfd, kfd, amfd; + int fds[4]; + int mfd = -1; + int kfd = -1; + int amfd = -1; int vmmouse = 0; mouse_device_packet_t packet; key_event_t event; @@ -2122,10 +2156,12 @@ int main(int argc, char * argv[]) { mfd = open("/dev/mouse", O_RDONLY); kfd = open("/dev/kbd", O_RDONLY); amfd = open("/dev/absmouse", O_RDONLY); - if (amfd == -1) { + if (amfd < 0) { amfd = open("/dev/vmmouse", O_RDONLY); vmmouse = 1; } + yg->vbox_rects = open("/dev/vboxrects", O_WRONLY); + yg->vbox_pointer = open("/dev/vboxpointer", O_WRONLY); fds[1] = mfd; fds[2] = kfd; @@ -2134,7 +2170,7 @@ int main(int argc, char * argv[]) { while (1) { if (yutani_options.nested) { - int index = syscall_fswait(2, fds); + int index = fswait(2, fds); if (index == 1) { yutani_msg_t * m = yutani_poll(yg->host_context); @@ -2143,9 +2179,9 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_KEY_EVENT: { struct yutani_msg_key_event * ke = (void*)m->data; - yutani_msg_t * m_ = yutani_msg_build_key_event(0, &ke->event, &ke->state); + yutani_msg_buildx_key_event_alloc(m_); + yutani_msg_buildx_key_event(m_, 0, &ke->event, &ke->state); handle_key_event(yg, (struct yutani_msg_key_event *)m_->data); - free(m_); } break; case YUTANI_MSG_WINDOW_MOUSE_EVENT: @@ -2159,9 +2195,9 @@ int main(int argc, char * argv[]) { yg->last_mouse_buttons = packet.buttons; - yutani_msg_t * m_ = yutani_msg_build_mouse_event(0, &packet, YUTANI_MOUSE_EVENT_TYPE_ABSOLUTE); + yutani_msg_buildx_mouse_event_alloc(m_); + yutani_msg_buildx_mouse_event(m_, 0, &packet, YUTANI_MOUSE_EVENT_TYPE_ABSOLUTE); handle_mouse_event(yg, (struct yutani_msg_mouse_event *)m_->data); - free(m_); } break; case YUTANI_MSG_RESIZE_OFFER: @@ -2172,12 +2208,14 @@ int main(int argc, char * argv[]) { yg->resize_on_next = 1; } break; + case YUTANI_MSG_WINDOW_CLOSE: case YUTANI_MSG_SESSION_END: { TRACE("Host session ended. Should exit."); - yutani_msg_t * response = yutani_msg_build_session_end(); + yutani_msg_buildx_session_end_alloc(response); + yutani_msg_buildx_session_end(response); pex_broadcast(server, response->size, (char *)response); - free(response); + yg->server = NULL; kill(render_thread.id, SIGINT); exit(0); } @@ -2190,25 +2228,25 @@ int main(int argc, char * argv[]) { continue; } } else { - int index = syscall_fswait(amfd == -1 ? 3 : 4, fds); + int index = fswait(amfd == -1 ? 3 : 4, fds); if (index == 2) { - char buf[1]; + unsigned char buf[1]; int r = read(kfd, buf, 1); if (r > 0) { kbd_scancode(&state, buf[0], &event); - yutani_msg_t * m = yutani_msg_build_key_event(0, &event, &state); + yutani_msg_buildx_key_event_alloc(m); + yutani_msg_buildx_key_event(m,0, &event, &state); handle_key_event(yg, (struct yutani_msg_key_event *)m->data); - free(m); } continue; } else if (index == 1) { int r = read(mfd, (char *)&packet, sizeof(mouse_device_packet_t)); if (r > 0) { yg->last_mouse_buttons = packet.buttons; - yutani_msg_t * m = yutani_msg_build_mouse_event(0, &packet, YUTANI_MOUSE_EVENT_TYPE_RELATIVE); + yutani_msg_buildx_mouse_event_alloc(m); + yutani_msg_buildx_mouse_event(m,0, &packet, YUTANI_MOUSE_EVENT_TYPE_RELATIVE); handle_mouse_event(yg, (struct yutani_msg_mouse_event *)m->data); - free(m); } continue; } else if (index == 3) { @@ -2219,9 +2257,9 @@ int main(int argc, char * argv[]) { } else { yg->last_mouse_buttons = packet.buttons; } - yutani_msg_t * m = yutani_msg_build_mouse_event(0, &packet, YUTANI_MOUSE_EVENT_TYPE_ABSOLUTE); + yutani_msg_buildx_mouse_event_alloc(m); + yutani_msg_buildx_mouse_event(m,0, &packet, YUTANI_MOUSE_EVENT_TYPE_ABSOLUTE); handle_mouse_event(yg, (struct yutani_msg_mouse_event *)m->data); - free(m); } continue; } @@ -2248,6 +2286,13 @@ int main(int argc, char * argv[]) { free(client_list); } + if (hashmap_is_empty(yg->clients_to_windows)) { + TRACE("Last compositor client disconnected, exiting."); + yg->server = NULL; + kill(render_thread.id, SIGINT); + exit(0); + } + free(p); continue; } @@ -2268,9 +2313,9 @@ int main(int argc, char * argv[]) { client_list = list_create(); hashmap_set(yg->clients_to_windows, (void *)p->source, client_list); } - yutani_msg_t * response = yutani_msg_build_welcome(yg->width, yg->height); + yutani_msg_buildx_welcome_alloc(response); + yutani_msg_buildx_welcome(response,yg->width, yg->height); pex_send(server, p->source, response->size, (char *)response); - free(response); } break; case YUTANI_MSG_WINDOW_NEW: @@ -2279,9 +2324,9 @@ int main(int argc, char * argv[]) { struct yutani_msg_window_new_flags * wn = (void *)m->data; TRACE("Client %08x requested a new window (%dx%d).", p->source, wn->width, wn->height); yutani_server_window_t * w = server_window_create(yg, wn->width, wn->height, p->source, m->type != YUTANI_MSG_WINDOW_NEW ? wn->flags : 0); - yutani_msg_t * response = yutani_msg_build_window_init(w->wid, w->width, w->height, w->bufid); + yutani_msg_buildx_window_init_alloc(response); + yutani_msg_buildx_window_init(response,w->wid, w->width, w->height, w->bufid); pex_send(server, p->source, response->size, (char *)response); - free(response); if (!(w->server_flags & YUTANI_WINDOW_FLAG_NO_STEAL_FOCUS)) { set_focused_window(yg, w); @@ -2325,7 +2370,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_MOVE: { struct yutani_msg_window_move * wm = (void *)m->data; - TRACE("%08x wanted to move window %d to %d, %d", p->source, wm->wid, (int)wm->x, (int)wm->y); + //TRACE("%08x wanted to move window %d to %d, %d", p->source, wm->wid, (int)wm->x, (int)wm->y); if (wm->x > (int)yg->width + 100 || wm->x < -(int)yg->width || wm->y > (int)yg->height + 100 || wm->y < -(int)yg->height) { TRACE("Refusing to move window to these coordinates."); break; @@ -2362,9 +2407,9 @@ int main(int argc, char * argv[]) { struct yutani_msg_window_resize * wr = (void *)m->data; yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid); if (w) { - yutani_msg_t * response = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_OFFER, w->wid, wr->width, wr->height, 0); + yutani_msg_buildx_window_resize_alloc(response); + yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_OFFER, w->wid, wr->width, wr->height, 0, w->tiled); pex_send(server, p->source, response->size, (char *)response); - free(response); } } break; @@ -2373,9 +2418,9 @@ int main(int argc, char * argv[]) { struct yutani_msg_window_resize * wr = (void *)m->data; yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid); if (w) { - yutani_msg_t * response = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_OFFER, w->wid, wr->width, wr->height, 0); + yutani_msg_buildx_window_resize_alloc(response); + yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_OFFER, w->wid, wr->width, wr->height, 0, w->tiled); pex_send(server, p->source, response->size, (char *)response); - free(response); } } break; @@ -2385,9 +2430,9 @@ int main(int argc, char * argv[]) { yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid); if (w) { uint32_t newbufid = server_window_resize(yg, w, wr->width, wr->height); - yutani_msg_t * response = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_BUFID, w->wid, wr->width, wr->height, newbufid); + yutani_msg_buildx_window_resize_alloc(response); + yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_BUFID, w->wid, wr->width, wr->height, newbufid, 0); pex_send(server, p->source, response->size, (char *)response); - free(response); } } break; @@ -2407,9 +2452,9 @@ int main(int argc, char * argv[]) { yutani_query_result(yg, p->source, node->value); } yutani_query_result(yg, p->source, yg->top_z); - yutani_msg_t * response = yutani_msg_build_window_advertise(0, 0, NULL, 0, NULL); + yutani_msg_buildx_window_advertise_alloc(response, 0); + yutani_msg_buildx_window_advertise(response,0, 0, NULL, 0, NULL); pex_send(server, p->source, response->size, (char *)response); - free(response); } break; case YUTANI_MSG_SUBSCRIBE: @@ -2452,9 +2497,9 @@ int main(int argc, char * argv[]) { break; case YUTANI_MSG_SESSION_END: { - yutani_msg_t * response = yutani_msg_build_session_end(); + yutani_msg_buildx_session_end_alloc(response); + yutani_msg_buildx_session_end(response); pex_broadcast(server, response->size, (char *)response); - free(response); } break; case YUTANI_MSG_WINDOW_FOCUS: @@ -2499,7 +2544,7 @@ int main(int argc, char * argv[]) { if (w) { if (yg->focused_window == w) { int32_t x, y; - window_to_device(w, wa->x, wa->y, &x, &y); + yutani_window_to_device(w, wa->x, wa->y, &x, &y); struct yutani_msg_mouse_event me; me.event.x_difference = x; @@ -2545,6 +2590,56 @@ int main(int argc, char * argv[]) { } } break; + case YUTANI_MSG_SPECIAL_REQUEST: + { + struct yutani_msg_special_request * sr = (void *)m->data; + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)sr->wid); + switch (sr->request) { + case YUTANI_SPECIAL_REQUEST_MAXIMIZE: + if (w) { + if (w->tiled) { + window_untile(yg,w); + window_move(yg,w,w->untiled_left,w->untiled_top); + } else { + window_tile(yg, w, 1, 1, 0, 0); + } + } + break; + case YUTANI_SPECIAL_REQUEST_PLEASE_CLOSE: + if (w) { + yutani_msg_buildx_window_close_alloc(response); + yutani_msg_buildx_window_close(response, w->wid); + pex_send(yg->server, w->owner, response->size, (char *)response); + } + break; + case YUTANI_SPECIAL_REQUEST_CLIPBOARD: + { + yutani_msg_buildx_clipboard_alloc(response, yg->clipboard_size); + yutani_msg_buildx_clipboard(response, yg->clipboard); + pex_send(server, p->source, response->size, (char *)response); + } + break; + case YUTANI_SPECIAL_REQUEST_RELOAD: + { + yg->reload_renderer = 1; + } + break; + default: + TRACE("Unknown special request type: 0x%x", sr->request); + break; + } + + } + break; + case YUTANI_MSG_CLIPBOARD: + { + struct yutani_msg_clipboard * cb = (void *)m->data; + yg->clipboard_size = min(cb->size, 511); + memcpy(yg->clipboard, cb->content, yg->clipboard_size); + yg->clipboard[yg->clipboard_size] = '\0'; + TRACE("Copied text to clipbard (size=%d)", yg->clipboard_size); + } + break; default: { TRACE("Unknown type: 0x%8x", m->type); diff --git a/userspace/core/cp.c b/apps/cp.c similarity index 62% rename from userspace/core/cp.c rename to apps/cp.c index b48fea0b..91aacbf0 100644 --- a/userspace/core/cp.c +++ b/apps/cp.c @@ -1,15 +1,21 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange + * Copyright (C) 2013 K. Lange * Copyright (C) 2013 Tyler Bindon - */ -/* - * cp + * + * cp - Copy files + * + * This is an incomplete implementation of `cp`. A more complete + * version of recursive directory copying can be found in the + * `migrate` sources, and should probably be imported here. */ #include #include -#include #include +#include +#include +#include #define CHUNK_SIZE 4096 @@ -23,11 +29,14 @@ int main(int argc, char ** argv) { } fd = fopen(argv[1], "r"); if (!fd) { - fprintf(stderr, "%s: %s: no such file or directory\n", argv[0], argv[1]); + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], strerror(errno)); return 1; } struct stat statbuf; + stat(argv[1], &statbuf); + int initial_mode = statbuf.st_mode; + stat(argv[2], &statbuf); if (S_ISDIR(statbuf.st_mode)) { char *filename = strrchr(argv[1], '/'); @@ -44,6 +53,11 @@ int main(int argc, char ** argv) { fout = fopen( argv[2], "w" ); } + if (!fout) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[2], strerror(errno)); + return 1; + } + size_t length; fseek(fd, 0, SEEK_END); @@ -64,11 +78,10 @@ int main(int argc, char ** argv) { fclose(fd); fclose(fout); + if (chmod(argv[2], initial_mode) < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[2], strerror(errno)); + } + return 0; } -/* - * vim:tabstop=4 - * vim:noexpandtab - * vim:shiftwidth=4 - */ diff --git a/apps/cursor-off.c b/apps/cursor-off.c new file mode 100644 index 00000000..9580995c --- /dev/null +++ b/apps/cursor-off.c @@ -0,0 +1,19 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016-2018 K. Lange + * + * cursor-off - Disables the VGA text mode cursor. + * + * This is an old tool that calls a special system call + * to change the VGA text-mode cursor position. The VGA + * terminal renders its own cursor in software, so we + * try to move the hardware cursor off screen so it doesn't + * interfere with the rest of the terminal and look weird. + */ +#include + +int main(int argc, char * argv[]) { + int x[] = {0xFF,0xFF}; + return syscall_system_function(13, (char **)x); +} diff --git a/apps/date.c b/apps/date.c new file mode 100644 index 00000000..cbe39955 --- /dev/null +++ b/apps/date.c @@ -0,0 +1,59 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * date - Print the current date and time. + * + * TODO: The traditional POSIX version of this tool is supposed + * to accept a format *and* allow you to set the time. + * We currently lack system calls for setting the time, + * but when we add those this should probably be updated. + * + * At the very least, improving this to print the "correct" + * default format would be good. + */ +#include +#include +#include +#include + +static void show_usage(int argc, char * argv[]) { + printf( + "%s - print the time and day\n" + "\n" + "usage: %s [-?] +FORMAT\n" + "\n" + " Note: This implementation is not currently capable of\n" + " setting the system time.\n" + "\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0], argv[0]); +} + +int main(int argc, char * argv[]) { + char * format = "%a %b %d %T %Y"; + struct tm * timeinfo; + struct timeval now; + char buf[BUFSIZ] = {0}; + int opt; + + while ((opt = getopt(argc,argv,"?")) != -1) { + switch (opt) { + case '?': + show_usage(argc,argv); + return 1; + } + } + + if (optind < argc && *argv[optind] == '+') { + format = &argv[optind][1]; + } + + gettimeofday(&now, NULL); //time(NULL); + timeinfo = localtime((time_t *)&now.tv_sec); + + strftime(buf,BUFSIZ,format,timeinfo); + puts(buf); + return 0; +} diff --git a/apps/drawlines.c b/apps/drawlines.c new file mode 100644 index 00000000..f63cda16 --- /dev/null +++ b/apps/drawlines.c @@ -0,0 +1,134 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * drawlines - Draw random lines into a GUI window + * + * The original compositor demo application, this dates all the + * way back to the original pre-Yutani compositor. Opens a very + * basic window (no decorations) and randomly fills it with + * colorful lines in a separate thread from the listener. + * + * There's no good reason for this to use threads - it should use + * `fswait2` to apply timeouts - but it demonstrates threading + * so we'll leave it that way for now. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int left, top, width, height; + +static yutani_t * yctx; +static yutani_window_t * wina; +static gfx_context_t * ctx; +static int should_exit = 0; +static int thick = 0; + +void * draw_thread(void * garbage) { + (void)garbage; + while (!should_exit) { + if (thick) { + draw_line_aa(ctx, rand() % width, rand() % width, rand() % height, rand() % height, rgb(rand() % 255,rand() % 255,rand() % 255), (float)thick); + } else { + draw_line(ctx, rand() % width, rand() % width, rand() % height, rand() % height, rgb(rand() % 255,rand() % 255,rand() % 255)); + } + yutani_flip(yctx, wina); + usleep(16666); + } + pthread_exit(0); + return NULL; +} + +static void show_usage(char * argv[]) { + printf( + "drawlines - graphical demo, draws lines randomly\n" + "\n" + "usage: %s [-t thickness]\n" + "\n" + " -t \033[3mdraw with anti-aliasing and the specified thickness\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); +} + + +int main (int argc, char ** argv) { + left = 100; + top = 100; + width = 500; + height = 500; + + srand(time(NULL)); + + int c; + while ((c = getopt(argc, argv, "t:?")) != -1) { + switch (c) { + case 't': + thick = atoi(optarg); + break; + case '?': + show_usage(argv); + return 0; + } + } + + yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } + + wina = yutani_window_create(yctx, width, height); + yutani_window_move(yctx, wina, left, top); + yutani_window_advertise_icon(yctx, wina, "drawlines", "drawlines"); + + ctx = init_graphics_yutani(wina); + draw_fill(ctx, rgb(0,0,0)); + + pthread_t thread; + pthread_create(&thread, NULL, draw_thread, NULL); + + while (!should_exit) { + yutani_msg_t * m = yutani_poll(yctx); + if (m) { + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { + should_exit = 1; + sched_yield(); + } + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { + yutani_window_drag_start(yctx, wina); + } + } + break; + case YUTANI_MSG_WINDOW_CLOSE: + case YUTANI_MSG_SESSION_END: + should_exit = 1; + break; + default: + break; + } + } + free(m); + } + + yutani_close(yctx, wina); + + return 0; +} diff --git a/apps/echo.c b/apps/echo.c new file mode 100644 index 00000000..436dcfe9 --- /dev/null +++ b/apps/echo.c @@ -0,0 +1,124 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * echo - Print arguments to stdout. + * + * Prints arguments to stdout, possibly interpreting escape + * sequences in the arguments. + */ +#include +#include +#include +#include + +void show_usage(char * argv[]) { + printf( + "echo - print arguments\n" + "\n" + "usage: %s [-ne] ARG...\n" + "\n" + " -n \033[3mdo not output a new line at the end\033[0m\n" + " -e \033[3mprocess escape sequences\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); +} + +int main(int argc, char ** argv) { + int use_newline = 1; + int process_escapes = 0; + + int opt; + while ((opt = getopt(argc, argv, "enh?")) != -1) { + switch (opt) { + case '?': + case 'h': + show_usage(argv); + return 1; + case 'n': + use_newline = 0; + break; + case 'e': + process_escapes = 1; + break; + } + } + + for (int i = optind; i < argc; ++i) { + if (process_escapes) { + char * c = argv[i]; + while (*c) { + if (*c == '\\') { + c++; + switch (*c) { + case '\\': + putchar('\\'); + break; + case 'a': + putchar('\a'); + break; + case 'b': + putchar('\b'); + break; + case 'c': + return 0; + case 'e': + putchar('\033'); + break; + case 'f': + putchar('\f'); + break; + case 'n': + putchar('\n'); + break; + case 't': + putchar('\t'); + break; + case 'v': + putchar('\v'); + break; + case '0': + { + int i = 0; + if (!isdigit(*(c+1)) || *(c+1) > '7') { + break; + } + c++; + i = *c - '0'; + if (isdigit(*(c+1)) && *(c+1) <= '7') { + c++; + i = (i << 3) | (*c - '0'); + if (isdigit(*(c+1)) && *(c+1) <= '7') { + c++; + i = (i << 3) | (*c - '0'); + } + } + putchar(i); + } + break; + default: + putchar('\\'); + putchar(*c); + break; + } + } else { + putchar(*c); + } + c++; + } + } else { + printf("%s",argv[i]); + } + if (i != argc - 1) { + printf(" "); + } + } + + if (use_newline) { + printf("\n"); + } + + fflush(stdout); + return 0; +} diff --git a/apps/env.c b/apps/env.c new file mode 100644 index 00000000..bc3c4d0a --- /dev/null +++ b/apps/env.c @@ -0,0 +1,49 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * env - Print or set environment + */ +#include +#include +#include +#include +#include + +extern int _environ_size; + +int main(int argc, char ** argv) { + int start = 1; + + if (start < argc && !strcmp(argv[start],"-i")) { + for (int i = 0; i < _environ_size; ++i) { + environ[i] = NULL; + } + start++; + } + + for (; start < argc; ++start) { + if (!strchr(argv[start],'=')) { + break; + } else { + putenv(argv[start]); + } + } + + if (start < argc) { + /* Execute command */ + if (execvp(argv[start], &argv[start])) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[start], strerror(errno)); + } + } else { + char ** env = environ; + + while (*env) { + printf("%s\n", *env); + env++; + } + } + + return 0; +} diff --git a/apps/false.c b/apps/false.c new file mode 100644 index 00000000..321c97fc --- /dev/null +++ b/apps/false.c @@ -0,0 +1,10 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * false - returns a failure status code. + */ +int main() { + return 1; +} diff --git a/userspace/net/fetch.c b/apps/fetch.c similarity index 65% rename from userspace/net/fetch.c rename to apps/fetch.c index ac4a2607..765d3fef 100644 --- a/userspace/net/fetch.c +++ b/apps/fetch.c @@ -1,7 +1,7 @@ -/* vim: ts=4 sw=4 noexpandtab +/* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Kevin Lange + * Copyright (C) 2015-2018 K. Lange * * fetch - Retreive documents from HTTP servers. * @@ -15,7 +15,7 @@ #include #include -#include "lib/http_parser.h" +#include #define SIZE 512 #define BOUNDARY "------ToaruOSFetchUploadBoundary" @@ -34,7 +34,6 @@ struct { const char * upload_file; char * password; int show_progress; - int next_is_content_length; size_t content_length; size_t size; struct timeval start; @@ -70,10 +69,10 @@ void parse_url(char * d, struct http_req * r) { void print_progress(void) { struct timeval now; gettimeofday(&now, NULL); - fprintf(stderr,"\033[G%6dkB",fetch_options.size/1024); + fprintf(stderr,"\033[G%6dkB",(int)fetch_options.size/1024); if (fetch_options.content_length) { int percent = (fetch_options.size * BAR_WIDTH) / (fetch_options.content_length); - fprintf(stderr," / %6dkB [%.*s%.*s]", fetch_options.content_length/1024, percent,bar_perc,BAR_WIDTH-percent,bar_spac); + fprintf(stderr," / %6dkB [%.*s%.*s]", (int)fetch_options.content_length/1024, percent,bar_perc,BAR_WIDTH-percent,bar_spac); } double timediff = (double)(now.tv_sec - fetch_options.start.tv_sec) + (double)(now.tv_usec - fetch_options.start.tv_usec)/1000000.0; @@ -98,45 +97,23 @@ void print_progress(void) { fflush(stderr); } -int callback_header_field (http_parser *p, const char *buf, size_t len) { - if (fetch_options.show_headers) { - fprintf(stderr, "Header field: %.*s\n", len, buf); - } - if (!strncmp(buf,"Content-Length",len)) { - fetch_options.next_is_content_length = 1; - } else { - fetch_options.next_is_content_length = 0; - } - return 0; -} - -int callback_header_value (http_parser *p, const char *buf, size_t len) { - if (fetch_options.show_headers) { - fprintf(stderr, "Header value: %.*s\n", len, buf); - } - if (fetch_options.next_is_content_length) { - char tmp[len+1]; - memcpy(tmp,buf,len); - tmp[len] = '\0'; - fetch_options.content_length = atoi(tmp); - } - return 0; -} - -int callback_body (http_parser *p, const char *buf, size_t len) { - fwrite(buf, 1, len, fetch_options.out); - fetch_options.size += len; - if (fetch_options.show_progress) { - print_progress(); - } - if (fetch_options.machine_readable && fetch_options.content_length) { - fprintf(stdout,"%d %d\n",fetch_options.size, fetch_options.content_length); - } - return 0; -} - int usage(char * argv[]) { - fprintf(stderr, "Usage: %s [-h] [-c cookie] [-o file] url\n", argv[0]); + fprintf(stderr, + "fetch - download files over HTTP\n" + "\n" + "usage: %s [-hOvmp?] [-c cookie] [-o file] [-u file] [-s speed] URL\n" + "\n" + " -h \033[3mshow headers\033[0m\n" + " -O \033[3msave the file based on the filename in the URL\033[0m\n" + " -v \033[3mshow progress\033[0m\n" + " -m \033[3mmachine readable output\033[0m\n" + " -p \033[3mprompt for password\033[0m\n" + " -c ... \033[3mset cookies\033[0m\n" + " -o ... \033[3msave to the specified file\033[0m\n" + " -u ... \033[3mupload the specified file\033[0m\n" + " -s ... \033[3mspecify the speed for uploading slowly\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); return 1; } @@ -155,6 +132,111 @@ int collect_password(char * password) { password[strlen(password)-1] = '\0'; tcsetattr(fileno(stdin), TCSAFLUSH, &old); fprintf(stdout, "\n"); + + return 0; +} + +void read_http_line(char * buf, FILE * f) { + memset(buf, 0x00, 256); + + fgets(buf, 255, f); + char * _r = strchr(buf, '\r'); + if (_r) { + *_r = '\0'; + } + if (!_r) { + _r = strchr(buf, '\n'); /* that's not right, but, whatever */ + if (_r) { + *_r = '\0'; + } + } +} + +void bad_response(void) { + fprintf(stderr, "Bad response.\n"); + exit(1); +} + +int http_fetch(FILE * f) { + hashmap_t * headers = hashmap_create(10); + + /* Parse response */ + { + char buf[256]; + read_http_line(buf, f); + + char * elements[3]; + + elements[0] = buf; + elements[1] = strchr(elements[0], ' '); + if (!elements[1]) bad_response(); + *elements[1] = '\0'; + elements[1]++; + + elements[2] = strchr(elements[1], ' '); + if (!elements[2]) bad_response(); + *elements[2] = '\0'; + elements[2]++; + + if (strcmp(elements[1], "200")) { + fprintf(stderr, "Bad response code: %s\n", elements[1]); + return 1; + } + } + + /* Parse headers */ + while (1) { + char buf[256]; + read_http_line(buf, f); + + if (!*buf) { + break; + } + + /* Split */ + char * name = buf; + char * value = strstr(buf, ": "); + if (!value) bad_response(); + *value = '\0'; + value += 2; + + hashmap_set(headers, name, strdup(value)); + } + + if (fetch_options.show_headers) { + list_t * hash_keys = hashmap_keys(headers); + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + fprintf(stderr, "[%s] = %s\n", key, (char*)hashmap_get(headers, key)); + } + list_free(hash_keys); + free(hash_keys); + } + + /* determine how many bytes we should read now */ + if (!hashmap_has(headers, "Content-Length")) { + fprintf(stderr, "Don't know how much to read.\n"); + return 1; + } + + int bytes_to_read = atoi(hashmap_get(headers, "Content-Length")); + fetch_options.content_length = bytes_to_read; + + while (bytes_to_read > 0) { + char buf[1024]; + size_t r = fread(buf, 1, bytes_to_read < 1024 ? bytes_to_read : 1024, f); + fwrite(buf, 1, r, fetch_options.out); + fetch_options.size += r; + if (fetch_options.show_progress) { + print_progress(); + } + if (fetch_options.machine_readable && fetch_options.content_length) { + fprintf(stdout,"%d %d\n",(int)fetch_options.size, (int)fetch_options.content_length); + } + bytes_to_read -= r; + } + + return 0; } int main(int argc, char * argv[]) { @@ -216,7 +298,7 @@ int main(int argc, char * argv[]) { fetch_options.out = stdout; if (fetch_options.output_file) { - fetch_options.out = fopen(fetch_options.output_file, "w"); + fetch_options.out = fopen(fetch_options.output_file, "w+"); } FILE * f = fopen(file,"r+"); @@ -268,7 +350,7 @@ int main(int argc, char * argv[]) { "Accept: */*\r\n" "Content-Length: %d\r\n" "Content-Type: multipart/form-data; boundary=" BOUNDARY "%08x\r\n" - "\r\n", my_req.path, my_req.domain, out_size, boundary_fuzz); + "\r\n", my_req.path, my_req.domain, (int)out_size, boundary_fuzz); fprintf(f,"%s",tmp); fprintf(f, @@ -309,22 +391,7 @@ int main(int argc, char * argv[]) { "\r\n", my_req.path, my_req.domain); } - http_parser_settings settings; - memset(&settings, 0, sizeof(settings)); - settings.on_header_field = callback_header_field; - settings.on_header_value = callback_header_value; - settings.on_body = callback_body; - - http_parser parser; - http_parser_init(&parser, HTTP_RESPONSE); - - gettimeofday(&fetch_options.start, NULL); - while (!feof(f)) { - char buf[10240]; - memset(buf, 0, sizeof(buf)); - size_t r = fread(buf, 1, 10240, f); - http_parser_execute(&parser, &settings, buf, r); - } + http_fetch(f); fflush(fetch_options.out); diff --git a/apps/fgrep.c b/apps/fgrep.c new file mode 100644 index 00000000..cfb8c6cc --- /dev/null +++ b/apps/fgrep.c @@ -0,0 +1,45 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014-2018 K. Lange + * + * fgrep - dump grep + * + * Locates strings in files and prints the lines containing them, + * with extra color identification if stdout is a tty. + */ +#include +#include +#include +#include + +#define LINE_SIZE 4096 + +int main(int argc, char ** argv) { + if (argc < 2) { + fprintf(stderr, "usage: %s thing-to-grep-for\n", argv[0]); + return 1; + } + + char * needle = argv[1]; + char buf[LINE_SIZE]; + int ret = 1; + int is_tty = isatty(STDOUT_FILENO); + + while (fgets(buf, LINE_SIZE, stdin)) { + char * found = strstr(buf, needle); + if (found) { + if (is_tty) { + *found = '\0'; + found += strlen(needle); + fprintf(stdout, "%s\033[1;31m%s\033[0m%s", buf, needle, found); + } else { + fprintf(stdout, "%s", buf); + } + ret = 0; + } + } + + return ret; +} + diff --git a/apps/file-browser.c b/apps/file-browser.c new file mode 100644 index 00000000..98b36ec3 --- /dev/null +++ b/apps/file-browser.c @@ -0,0 +1,510 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * file-browser - Show directory listings. + * + * This is a basic graphical file navigator. It's based somewhat + * on the original Python implementation. There's still a lot + * of work to do here presentation-wise. + */ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define APPLICATION_TITLE "File Browser" + +static yutani_t * yctx; +static yutani_window_t * main_window; +static gfx_context_t * ctx; + +#define SCROLL_AMOUNT 20 +static int application_running = 1; +static int show_hidden = 1; +static int scroll_offset = 0; +static int available_height = 0; + +static struct menu_bar menu_bar = {0}; +static struct menu_bar_entries menu_entries[] = { + {"File", "file"}, + {"Go", "go"}, + {"Help", "help"}, + {NULL, NULL}, +}; + +static void _menu_action_exit(struct MenuEntry * entry) { + application_running = 0; +} + +struct File { + char name[256]; + char icon[256]; + char date[256]; + int type; +}; + +static gfx_context_t * contents = NULL; +static sprite_t * contents_sprite = NULL; +static char * last_directory = NULL; +static int hilighted_offset = -1; +static struct File ** file_pointers = NULL; +static ssize_t file_pointers_len = 0; + +static int _close_enough(struct yutani_msg_window_mouse_event * me) { + if (me->command == YUTANI_MOUSE_EVENT_RAISE && sqrt(pow(me->new_x - me->old_x, 2) + pow(me->new_y - me->old_y, 2)) < 10) { + return 1; + } + return 0; +} + +static void clear_offset(int offset) { + draw_rectangle(contents, 0, offset * 24, contents->width, 24, rgb(255,255,255)); +} + +static void draw_file(struct File * f, int offset) { + sprite_t * icon = icon_get_16(f->icon); + draw_sprite(contents, icon, 2, offset * 24 + 2); + if (offset == hilighted_offset) { + draw_sprite_alpha_paint(contents, icon, 2, offset * 24 + 2, 0.5, rgb(72,167,255)); + draw_sdf_string(contents, 30, offset * 24, f->name, 16, rgb(72,167,255), SDF_FONT_THIN); + } else { + draw_sdf_string(contents, 30, offset * 24, f->name, 16, rgb(0,0,0), SDF_FONT_THIN); + } +} + +static struct File * get_file_at_offset(int offset) { + if (offset >= 0 && offset < file_pointers_len) { + return file_pointers[offset]; + } + return NULL; +} + +static void redraw_files(void) { + for (int i = 0; i < file_pointers_len; ++i) { + draw_file(file_pointers[i], i); + } +} + +static void load_directory(const char * path) { + if (file_pointers) { + for (int i = 0; i < file_pointers_len; ++i) { + free(file_pointers[i]); + } + free(file_pointers); + } + + DIR * dirp = opendir(path); + + if (!dirp) { + /* Failed to open directory. Throw up a warning? */ + file_pointers = NULL; + file_pointers_len = 0; + return; + } + + if (last_directory) { + free(last_directory); + } + + last_directory = strdup(path); + + /* Get the current time */ +#if 0 + struct tm * timeinfo; + struct timeval now; + gettimeofday(&now, NULL); //time(NULL); + timeinfo = localtime((time_t *)&now.tv_sec); + int this_year = timeinfo->tm_year; +#endif + + list_t * file_list = list_create(); + + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (ent->d_name[0] == '.' && + (ent->d_name[1] == '\0' || + (ent->d_name[1] == '.' && + ent->d_name[2] == '\0'))) { + /* skip . and .. */ + ent = readdir(dirp); + continue; + } + if (show_hidden || (ent->d_name[0] != '.')) { + + struct File * f = malloc(sizeof(struct File)); + sprintf(f->name, "%s", ent->d_name); /* snprintf? copy min()? */ + + struct stat statbuf; + //struct stat statbufl; + //char * link; + + char tmp[strlen(path)+strlen(ent->d_name)+2]; + sprintf(tmp, "%s/%s", path, ent->d_name); + lstat(tmp, &statbuf); +#if 0 + if (S_ISLNK(statbuf.st_mode)) { + stat(tmp, &statbufl); + f->link = malloc(4096); + readlink(tmp, f->link, 4096); + } +#endif + + if (S_ISDIR(statbuf.st_mode)) { + sprintf(f->icon, "folder"); + f->type = 1; + } else { + sprintf(f->icon, "file"); + f->type = 0; + } + + list_insert(file_list, f); + } + ent = readdir(dirp); + } + closedir(dirp); + + /* create a an array to hold the files */ + file_pointers = malloc(sizeof(struct File *) * file_list->length); + file_pointers_len = file_list->length; + int i = 0; + foreach (node, file_list) { + file_pointers[i] = node->value; + i++; + } + + list_free(file_list); + free(file_list); + + /* Sort files */ + int comparator(const void * c1, const void * c2) { + const struct File * f1 = *(const struct File **)(c1); + const struct File * f2 = *(const struct File **)(c2); + if (f1->type == 1 && f2->type == 0) return -1; + if (f1->type == 0 && f2->type == 1) return 1; + return strcmp(f1->name, f2->name); + } + qsort(file_pointers, file_pointers_len, sizeof(struct File *), comparator); + + scroll_offset = 0; +} + +static void reinitialize_contents(void) { + if (contents) { + free(contents); + } + + if (contents_sprite) { + sprite_free(contents_sprite); + } + + /* Calculate height for current directory */ + int calculated_height = file_pointers_len * 24; + + struct decor_bounds bounds; + decor_get_bounds(main_window, &bounds); + + contents_sprite = create_sprite(main_window->width - bounds.width, calculated_height, ALPHA_EMBEDDED); + contents = init_graphics_sprite(contents_sprite); + + draw_fill(contents, rgb(255,255,255)); + + /* Draw file entries */ + redraw_files(); +} + +static void redraw_window(void) { + draw_fill(ctx, rgb(255,255,255)); + + render_decorations(main_window, ctx, APPLICATION_TITLE); + + struct decor_bounds bounds; + decor_get_bounds(main_window, &bounds); + + menu_bar.x = bounds.left_width; + menu_bar.y = bounds.top_height; + menu_bar.width = ctx->width - bounds.width; + menu_bar.window = main_window; + menu_bar_render(&menu_bar, ctx); + + gfx_clear_clip(ctx); + gfx_add_clip(ctx, bounds.left_width, bounds.top_height + MENU_BAR_HEIGHT, ctx->width - bounds.width, available_height); + draw_sprite(ctx, contents_sprite, bounds.left_width, bounds.top_height + MENU_BAR_HEIGHT - scroll_offset); + gfx_clear_clip(ctx); + gfx_add_clip(ctx, 0, 0, ctx->width, ctx->height); + + + flip(ctx); + yutani_flip(yctx, main_window); +} + +static void resize_finish(int w, int h) { + int width_changed = (main_window->width != (unsigned int)w); + + yutani_window_resize_accept(yctx, main_window, w, h); + reinit_graphics_yutani(ctx, main_window); + + struct decor_bounds bounds; + decor_get_bounds(main_window, &bounds); + + available_height = ctx->height - MENU_BAR_HEIGHT - bounds.height; + + if (width_changed) { + reinitialize_contents(); + } + + if (available_height > contents->height) { + scroll_offset = 0; + } else { + if (scroll_offset > contents->height - available_height) { + scroll_offset = contents->height - available_height; + } + } + + redraw_window(); + yutani_window_resize_done(yctx, main_window); + + yutani_flip(yctx, main_window); +} + +/* TODO */ +#if 0 +static void _menu_action_input_path(struct MenuEntry * entry) { + +} +#endif + +static void _menu_action_navigate(struct MenuEntry * entry) { + /* go to entry->action */ + struct MenuEntry_Normal * _entry = (void*)entry; + load_directory(_entry->action); + reinitialize_contents(); + redraw_window(); +} + +static void _menu_action_up(struct MenuEntry * entry) { + /* go up */ + char tmp[1024]; + sprintf(tmp, "%s/..", last_directory); + load_directory(tmp); + reinitialize_contents(); + redraw_window(); +} + +static void _menu_action_help(struct MenuEntry * entry) { + /* show help documentation */ + system("help-browser file-browser.trt &"); + redraw_window(); +} + +static void _menu_action_about(struct MenuEntry * entry) { + /* Show About dialog */ + char about_cmd[1024] = "\0"; + strcat(about_cmd, "about \"About File Browser\" /usr/share/icons/48/folder.bmp \"ToaruOS File Browser\" \"(C) 2018 K. Lange\n-\nPart of ToaruOS, which is free software\nreleased under the NCSA/University of Illinois\nlicense.\n-\n%https://toaruos.org\n%https://gitlab.com/toaruos\" "); + char coords[100]; + sprintf(coords, "%d %d &", (int)main_window->x + (int)main_window->width / 2, (int)main_window->y + (int)main_window->height / 2); + strcat(about_cmd, coords); + system(about_cmd); + redraw_window(); +} + +int main(int argc, char * argv[]) { + + yctx = yutani_init(); + init_decorations(); + main_window = yutani_window_create(yctx, 800, 600); + yutani_window_move(yctx, main_window, yctx->display_width / 2 - main_window->width / 2, yctx->display_height / 2 - main_window->height / 2); + ctx = init_graphics_yutani_double_buffer(main_window); + + struct decor_bounds bounds; + decor_get_bounds(main_window, &bounds); + + yutani_window_advertise_icon(yctx, main_window, APPLICATION_TITLE, "folder"); + + menu_bar.entries = menu_entries; + menu_bar.redraw_callback = redraw_window; + + menu_bar.set = menu_set_create(); + + struct MenuList * m = menu_create(); /* File */ + menu_insert(m, menu_create_normal("exit",NULL,"Exit", _menu_action_exit)); + menu_set_insert(menu_bar.set, "file", m); + + m = menu_create(); /* Go */ + /* TODO implement input dialog for Path... */ +#if 0 + menu_insert(m, menu_create_normal("open",NULL,"Path...", _menu_action_input_path)); + menu_insert(m, menu_create_separator()); +#endif + menu_insert(m, menu_create_normal("home",getenv("HOME"),"Home",_menu_action_navigate)); + menu_insert(m, menu_create_normal(NULL,"/","File System",_menu_action_navigate)); + menu_insert(m, menu_create_normal("up",NULL,"Up",_menu_action_up)); + menu_set_insert(menu_bar.set, "go", m); + + m = menu_create(); + menu_insert(m, menu_create_normal("help",NULL,"Contents",_menu_action_help)); + menu_insert(m, menu_create_separator()); + menu_insert(m, menu_create_normal("star",NULL,"About " APPLICATION_TITLE,_menu_action_about)); + menu_set_insert(menu_bar.set, "help", m); + + available_height = ctx->height - MENU_BAR_HEIGHT - bounds.height; + load_directory("/usr/share"); + reinitialize_contents(); + redraw_window(); + + while (application_running) { + yutani_msg_t * m = yutani_poll(yctx); + while (m) { + if (menu_process_event(yctx, m)) { + redraw_window(); + } + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { + _menu_action_exit(NULL); + } + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * wf = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + if (win == main_window) { + win->focused = wf->focused; + redraw_window(); + } + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + if (wr->wid == main_window->wid) { + resize_finish(wr->width, wr->height); + } + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid); + struct decor_bounds bounds; + decor_get_bounds(win, &bounds); + + if (win == main_window) { + int result = decor_handle_event(yctx, m); + switch (result) { + case DECOR_CLOSE: + _menu_action_exit(NULL); + break; + case DECOR_RIGHT: + /* right click in decoration, show appropriate menu */ + decor_show_default_menu(main_window, main_window->x + me->new_x, main_window->y + me->new_y); + break; + default: + /* Other actions */ + break; + } + + /* Menu bar */ + menu_bar_mouse_event(yctx, main_window, &menu_bar, me, me->new_x, me->new_y); + + if (me->new_y > (int)(bounds.top_height + MENU_BAR_HEIGHT) && + me->new_y < (int)(main_window->height - bounds.bottom_height) && + me->new_x > (int)(bounds.left_width) && + me->new_x < (int)(main_window->width - bounds.right_width)) { + if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { + /* Scroll up */ + scroll_offset -= SCROLL_AMOUNT; + if (scroll_offset < 0) { + scroll_offset = 0; + } + redraw_window(); + } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { + if (available_height > contents->height) { + scroll_offset = 0; + } else { + scroll_offset += SCROLL_AMOUNT; + if (scroll_offset > contents->height - available_height) { + scroll_offset = contents->height - available_height; + } + } + redraw_window(); + } + + /* Get offset into contents */ + int y_into = me->new_y - bounds.top_height - MENU_BAR_HEIGHT + scroll_offset; + int offset = y_into / 24; + if (offset != hilighted_offset) { + int old_offset = hilighted_offset; + hilighted_offset = offset; + if (old_offset != -1) { + clear_offset(old_offset); + struct File * f = get_file_at_offset(old_offset); + if (f) { + clear_offset(old_offset); + draw_file(f, old_offset); + } + } + struct File * f = get_file_at_offset(hilighted_offset); + if (f) { + clear_offset(hilighted_offset); + draw_file(f, hilighted_offset); + } + redraw_window(); + } + + if (me->command == YUTANI_MOUSE_EVENT_CLICK || _close_enough(me)) { + struct File * f = get_file_at_offset(hilighted_offset); + if (f && f->type == 1) { + char tmp[1024]; + sprintf(tmp,"%s/%s", last_directory, f->name); + load_directory(tmp); + reinitialize_contents(); + redraw_window(); + } + } + + } else { + int old_offset = hilighted_offset; + hilighted_offset = -1; + if (old_offset != -1) { + clear_offset(old_offset); + struct File * f = get_file_at_offset(old_offset); + if (f) { + clear_offset(old_offset); + draw_file(f, old_offset); + } + redraw_window(); + } + } + + } + } + break; + case YUTANI_MSG_WINDOW_CLOSE: + case YUTANI_MSG_SESSION_END: + _menu_action_exit(NULL); + break; + default: + break; + } + free(m); + m = yutani_poll_async(yctx); + } + } +} diff --git a/apps/font-server.c b/apps/font-server.c new file mode 100644 index 00000000..6101f2a1 --- /dev/null +++ b/apps/font-server.c @@ -0,0 +1,97 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * font-server - Provides shared-memory fonts. + * + * This is an implementation of the shared memory font server + * from Yutani in mainline ToaruOS. In theory, with the fonts + * installed, this could be used to provide fonts for legacy + * mainline applications in ToaruOS-NIH, but this is untested. + */ +#include +#include +#include +#include +#include + +#if 0 +#include +#define TRACE_APP_NAME "font-server" +#else +#define TRACE(...) +#endif + +#define FONT_PATH "/usr/share/fonts/" +#define FONT(a,b) {a, FONT_PATH b} + +struct font_def { + char * identifier; + char * path; +}; + +static struct font_def fonts[] = { + FONT("sans-serif", "DejaVuSans.ttf"), + FONT("sans-serif.bold", "DejaVuSans-Bold.ttf"), + FONT("sans-serif.italic", "DejaVuSans-Oblique.ttf"), + FONT("sans-serif.bolditalic", "DejaVuSans-BoldOblique.ttf"), + FONT("monospace", "DejaVuSansMono.ttf"), + FONT("monospace.bold", "DejaVuSansMono-Bold.ttf"), + FONT("monospace.italic", "DejaVuSansMono-Oblique.ttf"), + FONT("monospace.bolditalic", "DejaVuSansMono-BoldOblique.ttf"), + {NULL, NULL} +}; + +/** + * Preload a font into the font cache. + */ +static char * precache_shmfont(char * ident, char * name) { + FILE * f = fopen(name, "r"); + if (!f) return NULL; + size_t s = 0; + fseek(f, 0, SEEK_END); + s = ftell(f); + fseek(f, 0, SEEK_SET); + + size_t shm_size = s; + char * font = (char *)syscall_shm_obtain(ident, &shm_size); + assert((shm_size >= s) && "shm_obtain returned too little memory to load a font into!"); + + fread(font, s, 1, f); + + fclose(f); + return font; +} + +/** + * Load all of the fonts into the cache. + */ +static void load_fonts(char * server) { + int i = 0; + while (fonts[i].identifier) { + char tmp[100]; + sprintf(tmp, "sys.%s.fonts.%s", server, fonts[i].identifier); + TRACE("Loading font %s -> %s", fonts[i].path, tmp); + if (!precache_shmfont(tmp, fonts[i].path)) { + TRACE(" ... failed."); + } + ++i; + } +} + +int main(int argc, char * argv[]) { + + /* Daemonize */ + if (!fork()) { + load_fonts("fonts"); + + while (1) { + usleep(100000); + } + + return 0; + } + + return 0; +} diff --git a/userspace/core/free.c b/apps/free.c similarity index 63% rename from userspace/core/free.c rename to apps/free.c index c417cf25..763772c5 100644 --- a/userspace/core/free.c +++ b/apps/free.c @@ -1,12 +1,13 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Kevin Lange + * Copyright (C) 2015-2018 K. Lange * * free - Show free / used / total RAM */ #include -#include +#include +#include void show_usage(int argc, char * argv[]) { printf( @@ -27,23 +28,21 @@ int main(int argc, char * argv[]) { int use_kilobytes = 0; int show_total = 0; - if (argc > 1) { - int index, c; - while ((c = getopt(argc, argv, "ktu?")) != -1) { - switch (c) { - case 'u': - show_used = 1; - break; - case 't': - show_total = 1; - break; - case 'k': - use_kilobytes = 1; - break; - case '?': - show_usage(argc, argv); - return 0; - } + int c; + while ((c = getopt(argc, argv, "utk?")) != -1) { + switch (c) { + case 'u': + show_used = 1; + break; + case 't': + show_total = 1; + break; + case 'k': + use_kilobytes = 1; + break; + case '?': + show_usage(argc, argv); + return 0; } } @@ -53,7 +52,24 @@ int main(int argc, char * argv[]) { if (!f) return 1; int total, free, used; - fscanf(f, "MemTotal: %d kB\nMemFree: %d kB\n", &total, &free); + char buf[1024] = {0}; + fgets(buf, 1024, f); + char * a, * b; + + a = strchr(buf, ' '); + a++; + b = strchr(a, '\n'); + *b = '\0'; + total = atoi(a); + + fgets(buf, 1024, f); + a = strchr(buf, ' '); + a++; + b = strchr(a, '\n'); + *b = '\0'; + free = atoi(a); + + //fscanf(f, "MemTotal: %d kB\nMemFree: %d kB\n", &total, &free); used = total - free; if (!use_kilobytes) { diff --git a/apps/getty.c b/apps/getty.c new file mode 100644 index 00000000..65adbe1d --- /dev/null +++ b/apps/getty.c @@ -0,0 +1,96 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * getty - Manage a TTY. + * + * Wraps a serial port (or other dumb connection) with a pty + * and manages a login for it. + */ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + int fd_master, fd_slave, fd_serial; + char * file = "/dev/ttyS0"; + char * user = NULL; + + if (getuid() != 0) { + fprintf(stderr, "%s: only root can do that\n", argv[0]); + return 1; + } + + int opt; + while ((opt = getopt(argc, argv, "a:")) != -1) { + switch (opt) { + case 'a': + user = optarg; + break; + } + } + + if (optind < argc) { + file = argv[optind]; + } + + openpty(&fd_master, &fd_slave, NULL, NULL, NULL); + fd_serial = open(file, O_RDWR); + + pid_t child = fork(); + + if (!child) { + dup2(fd_slave, 0); + dup2(fd_slave, 1); + dup2(fd_slave, 2); + + system("ttysize -q"); + + char * tokens[] = {"/bin/login",NULL,NULL,NULL}; + + if (user) { + tokens[1] = "-f"; + tokens[2] = user; + } + + execvp(tokens[0], tokens); + exit(1); + } else { + + int fds[2] = {fd_serial, fd_master}; + + while (1) { + int index = fswait2(2,fds,200); + char buf[1024]; + int r; + switch (index) { + case 0: /* fd_serial */ + r = read(fd_serial, buf, 1); + write(fd_master, buf, 1); + break; + case 1: /* fd_master */ + r = read(fd_master, buf, 1024); + write(fd_serial, buf, r); + break; + default: /* timeout */ + { + int result = waitpid(child, NULL, WNOHANG); + if (result > 0) { + /* Child login shell has returned (session ended) */ + return 0; + } + } + break; + } + + } + + } + + return 0; +} diff --git a/apps/glogin-provider.c b/apps/glogin-provider.c new file mode 100644 index 00000000..c55acfa3 --- /dev/null +++ b/apps/glogin-provider.c @@ -0,0 +1,589 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2015 K. Lange + */ +/* + * glogin + * + * Graphical Login screen + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#define TRACE_APP_NAME "glogin-provider" + +static sprite_t logo; + +static gfx_context_t * ctx; + +static uint16_t win_width; +static uint16_t win_height; + +static int uid = 0; + +#define USERNAME_BOX 1 +#define PASSWORD_BOX 2 + +static int LOGO_FINAL_OFFSET = 100; +static int BOX_WIDTH = 272; +static int BOX_HEIGHT = 104; +static int BOX_ROUNDNESS = 8; +static int CENTER_BOX_X=1; +static int CENTER_BOX_Y=1; +static int BOX_LEFT=-1; +static int BOX_RIGHT=-1; +static int BOX_TOP=-1; +static int BOX_BOTTOM=-1; +static int BOX_COLOR_R=0; +static int BOX_COLOR_G=0; +static int BOX_COLOR_B=0; +static int BOX_COLOR_A=127; +static char * WALLPAPER = "/usr/share/wallpaper.bmp"; +static char * LOGO = "/usr/share/logo_login.bmp"; + +#define TEXTBOX_INTERIOR_LEFT 4 +#define EXTRA_TEXT_OFFSET 15 + +int center_x(int x) { + return (win_width - x) / 2; +} + +int center_y(int y) { + return (win_height - y) / 2; +} + +#define INPUT_SIZE 1024 +int buffer_put(char * input_buffer, char c) { + int input_collected = strlen(input_buffer); + if (c == 8) { + /* Backspace */ + if (input_collected > 0) { + input_collected--; + input_buffer[input_collected] = '\0'; + } + return 0; + } + if (c < 10 || (c > 10 && c < 32) || c > 126) { + return 0; + } + input_buffer[input_collected] = c; + input_collected++; + input_buffer[input_collected] = '\0'; + if (input_collected == INPUT_SIZE - 1) { + return 1; + } + return 0; +} + +struct text_box { + int x; + int y; + unsigned int width; + unsigned int height; + + uint32_t text_color; + + struct login_container * parent; + + int is_focused:1; + int is_password:1; + + unsigned int cursor; + char * buffer; + + char * placeholder; +}; + +struct login_container { + int x; + int y; + unsigned int width; + unsigned int height; + + struct text_box * username_box; + struct text_box * password_box; + + int show_error:1; +}; + +void draw_text_box(gfx_context_t * ctx, struct text_box * tb) { + int x = tb->parent->x + tb->x; + int y = tb->parent->y + tb->y; + + int text_offset = 15; + if (tb->is_focused) { + draw_rounded_rectangle(ctx, 1 + x, 1 + y, tb->width - 2, tb->height - 2, 4, rgb(8,193,236)); + draw_rounded_rectangle(ctx, 2 + x, 2 + y, tb->width - 4, tb->height - 4, 4, rgb(244,244,244)); + } else { + draw_rounded_rectangle(ctx, 1 + x, 1 + y, tb->width - 2, tb->height - 2, 4, rgb(158,169,177)); + } + /* Line width 2? */ + char * text = tb->buffer; + char password_circles[512]; + uint32_t color = tb->text_color; + + if (strlen(tb->buffer) == 0 && !tb->is_focused) { + text = tb->placeholder; + color = rgba(0,0,0,127); + } else if (tb->is_password) { + strcpy(password_circles, ""); + for (unsigned int i = 0; i < strlen(tb->buffer); ++i) { + strcat(password_circles, "\007"); + } + text = password_circles; + } + + draw_sdf_string(ctx, x + TEXTBOX_INTERIOR_LEFT, y + text_offset - 12, text, 15, color, SDF_FONT_THIN); + + if (tb->is_focused) { + int width = draw_sdf_string_width(text, 15, SDF_FONT_THIN) + 2; + draw_line(ctx, x + TEXTBOX_INTERIOR_LEFT + width, x + TEXTBOX_INTERIOR_LEFT + width, y + 2, y + text_offset + 1, tb->text_color); + } + +} + +void draw_login_container(gfx_context_t * ctx, struct login_container * lc) { + + + /* Draw rounded rectangle */ + draw_rounded_rectangle(ctx, lc->x, lc->y, lc->width, lc->height, BOX_ROUNDNESS, rgba(BOX_COLOR_R,BOX_COLOR_G,BOX_COLOR_B,BOX_COLOR_A)); + + /* Draw labels */ + if (lc->show_error) { + char * error_message = "Incorrect username or password."; + + //set_font_size(11); + //draw_string(ctx, lc->x + (lc->width - draw_string_width(error_message)) / 2, lc->y + 6 + EXTRA_TEXT_OFFSET, rgb(240, 20, 20), error_message); + draw_sdf_string(ctx, lc->x + (lc->width - draw_sdf_string_width(error_message, 14, SDF_FONT_THIN)) / 2, lc->y + 6 + EXTRA_TEXT_OFFSET - 14, error_message, 14, rgb(240,20,20), SDF_FONT_THIN); + } + + draw_text_box(ctx, lc->username_box); + draw_text_box(ctx, lc->password_box); + +} + +/** + * Get hostname information updated with the current time. + * + * @param hostname + */ +static void get_updated_hostname_with_time_info(char hostname[]) { + // get hostname + char _hostname[256]; + gethostname(_hostname, 255); + + // get current time + struct tm * timeinfo; + struct timeval now; + gettimeofday(&now, NULL); //time(NULL); + timeinfo = localtime((time_t *)&now.tv_sec); + + // format the hostname info + char _date[256]; + strftime(_date, 256, "%a %B %d %Y", timeinfo); + sprintf(hostname, "%s // %s", _hostname, _date); +} + +static void draw_sdf_string_shadow(gfx_context_t * ctx, char * string, int font_size, int left, int top, uint32_t text_color, uint32_t shadow_color, int blur, int font) { + int w = draw_sdf_string_width(string, font_size, font); + sprite_t * _tmp_s = create_sprite(w + blur * 2, font_size + blur * 2, ALPHA_EMBEDDED); + gfx_context_t * _tmp = init_graphics_sprite(_tmp_s); + draw_fill(_tmp, rgba(0,0,0,0)); + draw_sdf_string(_tmp, blur, blur, string, font_size, shadow_color, font); + blur_context_box(_tmp, blur); + free(_tmp); + draw_sprite(ctx, _tmp_s, left - blur, top - blur); + sprite_free(_tmp_s); + draw_sdf_string(ctx, left, top, string, 14, text_color, font); +} + +int main (int argc, char ** argv) { + if (getuid() != 0) { + return 1; + } + + fprintf(stdout, "Hello\n"); + + yutani_t * y = yutani_init(); + + if (!y) { + fprintf(stderr, "[glogin] Connection to server failed.\n"); + return 1; + } + + /* Load config */ + { + confreader_t * conf = confreader_load("/etc/glogin.conf"); + + LOGO_FINAL_OFFSET = confreader_intd(conf, "style", "logo_padding", LOGO_FINAL_OFFSET); + BOX_WIDTH = confreader_intd(conf, "style", "box_width", BOX_WIDTH); + BOX_HEIGHT = confreader_intd(conf, "style", "box_height", BOX_HEIGHT); + BOX_ROUNDNESS = confreader_intd(conf, "style", "box_roundness", BOX_ROUNDNESS); + CENTER_BOX_X = confreader_intd(conf, "style", "center_box_x", CENTER_BOX_X); + CENTER_BOX_Y = confreader_intd(conf, "style", "center_box_y", CENTER_BOX_Y); + BOX_LEFT = confreader_intd(conf, "style", "box_left", BOX_LEFT); + BOX_RIGHT = confreader_intd(conf, "style", "box_right", BOX_RIGHT); + BOX_TOP = confreader_intd(conf, "style", "box_top", BOX_TOP); + BOX_BOTTOM = confreader_intd(conf, "style", "box_bottom", BOX_BOTTOM); + BOX_COLOR_R = confreader_intd(conf, "style", "box_color_r", BOX_COLOR_R); + BOX_COLOR_G = confreader_intd(conf, "style", "box_color_g", BOX_COLOR_G); + BOX_COLOR_B = confreader_intd(conf, "style", "box_color_b", BOX_COLOR_B); + BOX_COLOR_A = confreader_intd(conf, "style", "box_color_a", BOX_COLOR_A); + + WALLPAPER = confreader_getd(conf, "image", "wallpaper", WALLPAPER); + LOGO = confreader_getd(conf, "image", "logo", LOGO); + + confreader_free(conf); + + TRACE("Loading complete"); + } + + TRACE("Loading logo..."); + load_sprite(&logo, LOGO); + logo.alpha = ALPHA_EMBEDDED; + TRACE("... done."); + + /* Generate surface for background */ + sprite_t * bg_sprite; + + int width = y->display_width; + int height = y->display_height; + int skip_animation = 0; + + /* Do something with a window */ + TRACE("Connecting to window server..."); + yutani_window_t * wina = yutani_window_create(y, width, height); + assert(wina); + yutani_set_stack(y, wina, 0); + ctx = init_graphics_yutani_double_buffer(wina); + draw_fill(ctx, rgba(0,0,0,255)); + yutani_flip(y, wina); + TRACE("... done."); + + +redo_everything: + win_width = width; + win_height = height; + +#if 0 + cairo_surface_t * cs = cairo_image_surface_create_for_data((void*)ctx->backbuffer, CAIRO_FORMAT_ARGB32, ctx->width, ctx->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, ctx->width)); + cairo_t * cr = cairo_create(cs); +#endif + + + TRACE("Loading wallpaper..."); + { + sprite_t * wallpaper = malloc(sizeof(sprite_t)); + load_sprite(wallpaper, WALLPAPER); + + float x = (float)width / (float)wallpaper->width; + float y = (float)height / (float)wallpaper->height; + + int nh = (int)(x * (float)wallpaper->height); + int nw = (int)(y * (float)wallpaper->width);; + + bg_sprite = create_sprite(width, height, ALPHA_OPAQUE); + gfx_context_t * bg = init_graphics_sprite(bg_sprite); + + if (nw > width) { + draw_sprite_scaled(bg, wallpaper, (width - nw) / 2, 0, nw, height); + } else { + draw_sprite_scaled(bg, wallpaper, 0, (height - nh) / 2, width, nh); + } + + /* Three box blurs = good enough approximation of a guassian, but faster*/ + blur_context_box(bg, 20); + blur_context_box(bg, 20); + blur_context_box(bg, 20); + + free(bg); + free(wallpaper); + } + TRACE("... done."); + + while (1) { + + yutani_set_stack(y, wina, 0); + yutani_focus_window(y, wina->wid); + + draw_fill(ctx, rgb(0,0,0)); + draw_sprite(ctx, bg_sprite, center_x(width), center_y(height)); + flip(ctx); + yutani_flip(y, wina); + + char * foo = malloc(sizeof(uint32_t) * width * height); + memcpy(foo, ctx->backbuffer, sizeof(uint32_t) * width * height); + + TRACE("Begin animation."); + if (!skip_animation) { + struct timeval start; + gettimeofday(&start, NULL); + + while (1) { + uint32_t tick; + struct timeval t; + gettimeofday(&t, NULL); + + uint32_t sec_diff = t.tv_sec - start.tv_sec; + uint32_t usec_diff = t.tv_usec - start.tv_usec; + + if (t.tv_usec < start.tv_usec) { + sec_diff -= 1; + usec_diff = (1000000 + t.tv_usec) - start.tv_usec; + } + + tick = (uint32_t)(sec_diff * 1000 + usec_diff / 1000); + int i = (float)LOGO_FINAL_OFFSET * (float)tick / 700.0f; + if (i >= LOGO_FINAL_OFFSET) break; + + memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height); + draw_sprite(ctx, &logo, center_x(logo.width), center_y(logo.height) - i); + flip(ctx); + yutani_flip_region(y, wina, center_x(logo.width), center_y(logo.height) - i, logo.width, logo.height + 5); + usleep(10000); + } + } + TRACE("End animation."); + skip_animation = 0; + + char username[INPUT_SIZE] = {0}; + char password[INPUT_SIZE] = {0}; + char hostname[512]; + + // we do it here to calculate the final string position + get_updated_hostname_with_time_info(hostname); + + char kernel_v[512]; + + { + struct utsname u; + uname(&u); + char * os_name_ = "ToaruOS"; + snprintf(kernel_v, 512, "%s %s", os_name_, u.release); + } + + uid = 0; + + int box_x, box_y; + + if (CENTER_BOX_X) { + box_x = center_x(BOX_WIDTH); + } else if (BOX_LEFT == -1) { + box_x = win_width - BOX_RIGHT - BOX_WIDTH; + } else { + box_x = BOX_LEFT; + } + if (CENTER_BOX_Y) { + box_y = center_y(0) + 8; + } else if (BOX_TOP == -1) { + box_y = win_width - BOX_BOTTOM - BOX_HEIGHT; + } else { + box_y = BOX_TOP; + } + + int focus = 0; + + //set_font_size(11); + int hostname_label_left = width - 10 - draw_sdf_string_width(hostname, 14, SDF_FONT_BOLD); + int kernel_v_label_left = 10; + + struct text_box username_box = { (BOX_WIDTH - 170) / 2, 30, 170, 20, rgb(0,0,0), NULL, 0, 0, 0, username, "Username" }; + struct text_box password_box = { (BOX_WIDTH - 170) / 2, 58, 170, 20, rgb(0,0,0), NULL, 0, 1, 0, password, "Password" }; + + struct login_container lc = { box_x, box_y, BOX_WIDTH, BOX_HEIGHT, &username_box, &password_box, 0 }; + + username_box.parent = &lc; + password_box.parent = &lc; + + while (1) { + focus = 0; + memset(username, 0x0, INPUT_SIZE); + memset(password, 0x0, INPUT_SIZE); + + while (1) { + + // update time info + get_updated_hostname_with_time_info(hostname); + + memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height); + draw_sprite(ctx, &logo, center_x(logo.width), center_y(logo.height) - LOGO_FINAL_OFFSET); + + draw_sdf_string_shadow(ctx, hostname, 14, hostname_label_left, height - 22, rgb(255,255,255), rgb(0,0,0), 4, SDF_FONT_BOLD); + draw_sdf_string_shadow(ctx, kernel_v, 14, kernel_v_label_left, height - 22, rgb(255,255,255), rgb(0,0,0), 4, SDF_FONT_BOLD); + + if (focus == USERNAME_BOX) { + username_box.is_focused = 1; + password_box.is_focused = 0; + } else if (focus == PASSWORD_BOX) { + username_box.is_focused = 0; + password_box.is_focused = 1; + } else { + username_box.is_focused = 0; + password_box.is_focused = 0; + } + + draw_login_container(ctx, &lc); + + flip(ctx); + yutani_flip(y, wina); + + struct yutani_msg_key_event kbd; + struct yutani_msg_window_mouse_event mou; + int msg_type = 0; +collect_events: + do { + yutani_msg_t * msg = yutani_poll(y); + switch (msg->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)msg->data; + if (ke->event.action == KEY_ACTION_DOWN) { + memcpy(&kbd, ke, sizeof(struct yutani_msg_key_event)); + msg_type = 1; + } + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)msg->data; + memcpy(&mou, me, sizeof(struct yutani_msg_mouse_event)); + msg_type = 2; + } + break; + case YUTANI_MSG_WELCOME: + { + struct yutani_msg_welcome * mw = (void*)msg->data; + yutani_window_resize(y, wina, mw->display_width, mw->display_height); + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)msg->data; + width = wr->width; + height = wr->height; + yutani_window_resize_accept(y, wina, width, height); + reinit_graphics_yutani(ctx, wina); + yutani_window_resize_done(y, wina); + + sprite_free(bg_sprite); + //cairo_destroy(cr); + //cairo_surface_destroy(cs); + + skip_animation = 1; + goto redo_everything; + } + break; + } + free(msg); + } while (!msg_type); + + if (msg_type == 1) { + + if (kbd.event.keycode == '\n') { + if (focus == USERNAME_BOX) { + focus = PASSWORD_BOX; + continue; + } else if (focus == PASSWORD_BOX) { + break; + } else { + focus = USERNAME_BOX; + continue; + } + } + + if (kbd.event.keycode == '\t') { + if (focus == USERNAME_BOX) { + focus = PASSWORD_BOX; + } else { + focus = USERNAME_BOX; + } + continue; + } + + if (kbd.event.key) { + + if (!focus) { + focus = USERNAME_BOX; + } + + if (focus == USERNAME_BOX) { + buffer_put(username, kbd.event.key); + } else if (focus == PASSWORD_BOX) { + buffer_put(password, kbd.event.key); + } + + } + + } else if (msg_type == 2) { + + if ((mou.command == YUTANI_MOUSE_EVENT_DOWN + && mou.buttons & YUTANI_MOUSE_BUTTON_LEFT) + || (mou.command == YUTANI_MOUSE_EVENT_CLICK)) { + /* Determine if we were inside of a text box */ + + if (mou.new_x >= (int)lc.x + (int)username_box.x && + mou.new_x <= (int)lc.x + (int)username_box.x + (int)username_box.width && + mou.new_y >= (int)lc.y + (int)username_box.y && + mou.new_y <= (int)lc.y + (int)username_box.y + (int)username_box.height) { + /* Ensure this box is focused. */ + focus = USERNAME_BOX; + continue; + } else if ( + (int)mou.new_x >= (int)lc.x + (int)password_box.x && + (int)mou.new_x <= (int)lc.x + (int)password_box.x + (int)password_box.width && + (int)mou.new_y >= (int)lc.y + (int)password_box.y && + (int)mou.new_y <= (int)lc.y + (int)password_box.y + (int)password_box.height) { + /* Ensure this box is focused. */ + focus = PASSWORD_BOX; + continue; + } else { + focus = 0; + continue; + } + + } else { + goto collect_events; + } + } + + } + + fprintf(stdout, "USER %s\n", username); + fprintf(stdout, "PASS %s\n", password); + fprintf(stdout, "AUTH\n"); + + char tmp[1024]; + fgets(tmp, 1024, stdin); + if (!strcmp(tmp,"FAIL\n")) { + lc.show_error = 1; + continue; + } else if (!strcmp(tmp,"SUCC\n")) { + fprintf(stderr,"Success!\n"); + goto _success; + } + } + } + +_success: + yutani_close(y, wina); + + + return 0; +} diff --git a/userspace/gui/core/glogin.c b/apps/glogin.c similarity index 89% rename from userspace/gui/core/glogin.c rename to apps/glogin.c index e0ddf47e..e58c28c9 100644 --- a/userspace/gui/core/glogin.c +++ b/apps/glogin.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2015 Kevin Lange + * Copyright (C) 2013-2015 K. Lange * * Graphical login daemon. * @@ -17,17 +17,20 @@ #include -#include "lib/toaru_auth.h" - -#include "lib/trace.h" +#include +#include +#include #define TRACE_APP_NAME "glogin" -#undef TRACE -#define TRACE(msg,...) - int main (int argc, char ** argv) { + if (getuid() != 0) { + return 1; + } /* Ensure a somewhat sane environment going in */ + TRACE("Graphical login starting."); + yutani_init(); + setenv("USER", "root", 1); setenv("HOME", "/", 1); setenv("SHELL", "/bin/sh", 1); @@ -52,7 +55,7 @@ int main (int argc, char ** argv) { close(com_pipe[0]); close(rep_pipe[1]); TRACE("In client..."); - char * args[] = {"/bin/login.py", NULL}; + char * args[] = {"/bin/glogin-provider", NULL}; execvp(args[0], args); TRACE("Exec failure?"); exit(1); @@ -67,7 +70,6 @@ int main (int argc, char ** argv) { while (!feof(com)) { char buf[1024]; /* line length? */ char * cmd = fgets(buf, sizeof(buf), com); - TRACE("cmd = %p", cmd); size_t r = strlen(cmd); if (cmd && r) { if (cmd[r-1] == '\n') { @@ -119,12 +121,13 @@ int main (int argc, char ** argv) { if (!_session_pid) { setuid(uid); toaru_auth_set_vars(); - char * args[] = {"/bin/gsession", NULL}; + char * args[] = {"/bin/session", NULL}; execvp(args[0], args); exit(1); } waitpid(_session_pid, NULL, 0); + TRACE("Session ended."); } return 0; diff --git a/userspace/gui/core/gsudo.c b/apps/gsudo.c similarity index 69% rename from userspace/gui/core/gsudo.c rename to apps/gsudo.c index d454ea3b..530ede2a 100644 --- a/userspace/gui/core/gsudo.c +++ b/apps/gsudo.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2017 Kevin Lange + * Copyright (C) 2014-2017 K. Lange * * gsudo - graphical implementation of sudo * @@ -11,16 +11,18 @@ #include #include -#include #include #include #include #include -#include "lib/toaru_auth.h" -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/shmemfonts.h" +#include +#include +#include +#include + +#define FONT_SIZE_MAIN 20 +#define FONT_SIZE_PASSWD 25 uint32_t child = 0; @@ -40,7 +42,6 @@ int main(int argc, char ** argv) { int error = 0; yutani_t * yctx = yutani_init(); - init_shmemfonts(); int left = (yctx->display_width - width) / 2; int top = (yctx->display_height - height) / 2; @@ -50,7 +51,6 @@ int main(int argc, char ** argv) { gfx_context_t * ctx = init_graphics_yutani_double_buffer(window); - while (1) { char * username = getenv("USER"); char * password = calloc(sizeof(char) * 1024,1); @@ -67,27 +67,23 @@ int main(int argc, char ** argv) { char prompt_message[512]; sprintf(prompt_message, "Enter password for '%s'", username); - set_font_size(13); - draw_string(ctx, (width - draw_string_width(prompt_message)) / 2, 20, rgb(255, 255, 255), prompt_message); + draw_sdf_string(ctx, (width - draw_sdf_string_width(prompt_message, FONT_SIZE_MAIN, SDF_FONT_THIN)) / 2, 20, prompt_message, FONT_SIZE_MAIN, rgb(255, 255, 255), SDF_FONT_THIN); sprintf(prompt_message, "requested by %s", argv[1]); - set_font_size(13); - draw_string(ctx, (width - draw_string_width(prompt_message)) / 2, 190, rgb(255, 255, 255), prompt_message); + draw_sdf_string(ctx, (width - draw_sdf_string_width(prompt_message, FONT_SIZE_MAIN, SDF_FONT_THIN)) / 2, 150, prompt_message, FONT_SIZE_MAIN, rgb(255, 255, 255), SDF_FONT_THIN); if (error) { sprintf(prompt_message, "Try again. %d failures.", fails); - set_font_size(13); - draw_string(ctx, (width - draw_string_width(prompt_message)) / 2, 35, rgb(255, 0, 0), prompt_message); + draw_sdf_string(ctx, (width - draw_sdf_string_width(prompt_message, FONT_SIZE_MAIN, SDF_FONT_THIN)) / 2, 50, prompt_message, FONT_SIZE_MAIN, rgb(255, 0, 0), SDF_FONT_THIN); } char password_circles[512] = {0};; strcpy(password_circles, ""); - for (int i = 0; i < strlen(password) && i < 512/4; ++i) { - strcat(password_circles, "⚫"); + for (unsigned int i = 0; i < strlen(password) && i < 512/4; ++i) { + strcat(password_circles, "\007"); } - set_font_size(15); - draw_string(ctx, (width - draw_string_width(password_circles)) / 2, 100, rgb(255, 255, 255), password_circles); + draw_sdf_string(ctx, (width - draw_sdf_string_width(password_circles, FONT_SIZE_PASSWD, SDF_FONT_THIN)) / 2, 80, password_circles, FONT_SIZE_PASSWD, rgb(255, 255, 255), SDF_FONT_THIN); flip(ctx); yutani_flip(yctx, window); @@ -131,9 +127,7 @@ _done: } char ** args = &argv[1]; - int j = execvp(args[0], args); - - return 1; + return execvp(args[0], args); } return 1; diff --git a/apps/head.c b/apps/head.c new file mode 100644 index 00000000..fbf571b4 --- /dev/null +++ b/apps/head.c @@ -0,0 +1,72 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * head - Print the first `n` lines of a file. + */ +#include +#include +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + int n = 10; + int opt; + int print_names = 0; + int retval = 0; + + while ((opt = getopt(argc, argv, "n:")) != -1) { + switch (opt) { + case 'n': + n = atoi(optarg); + break; + } + } + + if (argc > optind + 1) { + /* Multiple files */ + print_names = 1; + } + + if (argc == optind) { + /* This is silly, but should work due to reasons. */ + argv[optind] = "-"; + argc++; + } + + for (int i = optind; i < argc; ++i) { + FILE * f = (!strcmp(argv[i],"-")) ? stdin : fopen(argv[i],"r"); + if (!f) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno)); + retval = 1; + continue; + } + + if (print_names) { + fprintf(stdout, "==> %s <==\n", (f == stdin) ? "standard input" : argv[i]); + } + + int line = 1; + + while (!feof(f)) { + int c = fgetc(f); + if (c >= 0) { + fputc(c, stdout); + + if (c == '\n') { + line++; + if (line > n) break; + } + } + } + + if (f != stdin) { + fclose(f); + } + } + + return retval; +} diff --git a/apps/hello.c b/apps/hello.c new file mode 100644 index 00000000..accb690a --- /dev/null +++ b/apps/hello.c @@ -0,0 +1,13 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011~2018 K. Lange + * + * hello - Prints "Hello, world." + */ +#include + +int main(int argc, char * argv[]) { + puts("Hello, world."); + return 0; +} diff --git a/apps/help-browser.c b/apps/help-browser.c new file mode 100644 index 00000000..0ce96bd3 --- /dev/null +++ b/apps/help-browser.c @@ -0,0 +1,242 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * help-browser - Display documentation. + * + * This is a work-in-progress reimplementation of the help browser + * from mainline ToaruOS. It is currently incomplete. + * + * Eventually, this should be a rich text document browser, almost + * akin to a web browser. Right now it just says "Hello, world." + */ +#include +#include + +#include +#include +#include +#include +#include + +#define APPLICATION_TITLE "Help Browser" + +static yutani_t * yctx; +static yutani_window_t * main_window; +static gfx_context_t * ctx; + +static int application_running = 1; + +static gfx_context_t * contents = NULL; +static sprite_t * contents_sprite = NULL; + +static struct menu_bar menu_bar = {0}; +static struct menu_bar_entries menu_entries[] = { + {"File", "file"}, + {"Go", "go"}, + {"Help", "help"}, + {NULL, NULL}, +}; + +static void _menu_action_exit(struct MenuEntry * entry) { + application_running = 0; +} + +static void redraw_text(void) { + draw_sdf_string(contents, 30, 30, "Hello, world.", 16, rgb(0,0,0), SDF_FONT_THIN); +} + +static void reinitialize_contents(void) { + if (contents) { + free(contents); + } + + if (contents_sprite) { + sprite_free(contents_sprite); + } + + /* Calculate height for current directory */ + int calculated_height = 200; + + struct decor_bounds bounds; + decor_get_bounds(main_window, &bounds); + + contents_sprite = create_sprite(main_window->width - bounds.width, calculated_height, ALPHA_EMBEDDED); + contents = init_graphics_sprite(contents_sprite); + + draw_fill(contents, rgb(255,255,255)); + + /* Draw file entries */ + redraw_text(); +} + +static void redraw_window(void) { + draw_fill(ctx, rgb(255,255,255)); + + render_decorations(main_window, ctx, APPLICATION_TITLE); + + struct decor_bounds bounds; + decor_get_bounds(main_window, &bounds); + + menu_bar.x = bounds.left_width; + menu_bar.y = bounds.top_height; + menu_bar.width = ctx->width - bounds.width; + menu_bar.window = main_window; + menu_bar_render(&menu_bar, ctx); + + gfx_clear_clip(ctx); + gfx_add_clip(ctx, bounds.left_width, bounds.top_height + MENU_BAR_HEIGHT, ctx->width - bounds.width, ctx->height - MENU_BAR_HEIGHT - bounds.height); + draw_sprite(ctx, contents_sprite, bounds.left_width, bounds.top_height + MENU_BAR_HEIGHT); + gfx_clear_clip(ctx); + gfx_add_clip(ctx, 0, 0, ctx->width, ctx->height); + + flip(ctx); + yutani_flip(yctx, main_window); +} + +static void resize_finish(int w, int h) { + int height_changed = (main_window->width != (unsigned int)w); + + yutani_window_resize_accept(yctx, main_window, w, h); + reinit_graphics_yutani(ctx, main_window); + + if (height_changed) { + reinitialize_contents(); + } + + redraw_window(); + yutani_window_resize_done(yctx, main_window); + + yutani_flip(yctx, main_window); +} + +static void _menu_action_navigate(struct MenuEntry * entry) { + /* go to entry->action */ +} + +static void _menu_action_back(struct MenuEntry * entry) { + /* go back */ +} + +static void _menu_action_forward(struct MenuEntry * entry) { + /* go forward */ +} + +static void _menu_action_about(struct MenuEntry * entry) { + /* Show About dialog */ + char about_cmd[1024] = "\0"; + strcat(about_cmd, "about \"About Help Browser\" /usr/share/icons/48/help.bmp \"ToaruOS Help Browser\" \"(C) 2018 K. Lange\n-\nPart of ToaruOS, which is free software\nreleased under the NCSA/University of Illinois\nlicense.\n-\n%https://toaruos.org\n%https://gitlab.com/toarus\" "); + char coords[100]; + sprintf(coords, "%d %d &", (int)main_window->x + (int)main_window->width / 2, (int)main_window->y + (int)main_window->height / 2); + strcat(about_cmd, coords); + system(about_cmd); + redraw_window(); +} + +int main(int argc, char * argv[]) { + + yctx = yutani_init(); + init_decorations(); + main_window = yutani_window_create(yctx, 640, 480); + yutani_window_move(yctx, main_window, yctx->display_width / 2 - main_window->width / 2, yctx->display_height / 2 - main_window->height / 2); + ctx = init_graphics_yutani_double_buffer(main_window); + + yutani_window_advertise_icon(yctx, main_window, APPLICATION_TITLE, "help"); + + menu_bar.entries = menu_entries; + menu_bar.redraw_callback = redraw_window; + + menu_bar.set = menu_set_create(); + + struct MenuList * m = menu_create(); /* File */ + menu_insert(m, menu_create_normal("exit",NULL,"Exit", _menu_action_exit)); + menu_set_insert(menu_bar.set, "file", m); + + m = menu_create(); /* Go */ + menu_insert(m, menu_create_normal("home","0_index.trt","Home",_menu_action_navigate)); + menu_insert(m, menu_create_normal("bookmark","special:contents","Topics",_menu_action_navigate)); + menu_insert(m, menu_create_separator()); + menu_insert(m, menu_create_normal("back",NULL,"Back",_menu_action_back)); + menu_insert(m, menu_create_normal("forward",NULL,"Forward",_menu_action_forward)); + menu_set_insert(menu_bar.set, "go", m); + + m = menu_create(); + menu_insert(m, menu_create_normal("help","help_browser.trt","Contents",_menu_action_navigate)); + menu_insert(m, menu_create_separator()); + menu_insert(m, menu_create_normal("star",NULL,"About " APPLICATION_TITLE,_menu_action_about)); + menu_set_insert(menu_bar.set, "help", m); + + reinitialize_contents(); + redraw_window(); + + while (application_running) { + yutani_msg_t * m = yutani_poll(yctx); + while (m) { + if (menu_process_event(yctx, m)) { + redraw_window(); + } + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { + _menu_action_exit(NULL); + } + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * wf = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + if (win == main_window) { + win->focused = wf->focused; + redraw_window(); + } + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + if (wr->wid == main_window->wid) { + resize_finish(wr->width, wr->height); + } + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid); + + if (win == main_window) { + int result = decor_handle_event(yctx, m); + switch (result) { + case DECOR_CLOSE: + _menu_action_exit(NULL); + break; + case DECOR_RIGHT: + /* right click in decoration, show appropriate menu */ + decor_show_default_menu(main_window, main_window->x + me->new_x, main_window->y + me->new_y); + break; + default: + /* Other actions */ + break; + } + + /* Menu bar */ + menu_bar_mouse_event(yctx, main_window, &menu_bar, me, me->new_x, me->new_y); + } + } + break; + case YUTANI_MSG_WINDOW_CLOSE: + case YUTANI_MSG_SESSION_END: + _menu_action_exit(NULL); + break; + default: + break; + } + free(m); + m = yutani_poll_async(yctx); + } + } +} diff --git a/apps/hexify.c b/apps/hexify.c new file mode 100644 index 00000000..e6a0e924 --- /dev/null +++ b/apps/hexify.c @@ -0,0 +1,199 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * hexify - Convert binary to hex. + * + * This is based on the output of xxd. + * Does NOT a hex-to-bin option - something to consider. + */ +#include +#include +#include +#include +#include + +void print_line(unsigned char * buf, unsigned int width, unsigned int sizer, unsigned int offset) { + fprintf(stdout, "%08x: ", sizer); + for (unsigned int i = 0; i < width; ) { + if (i >= offset) { + fprintf(stdout, " "); + } else { + fprintf(stdout, "%02x", buf[i]); + } + i++; + if (i == width) break; /* in case of odd width */ + if (i >= offset) { + fprintf(stdout, " "); + } else { + fprintf(stdout, "%02x ", buf[i]); + } + i++; + } + fprintf(stdout, " "); + for (unsigned int i = 0; i < width; i++) { + if (i >= offset) { + fprintf(stdout, " "); + } else { + if (isprint(buf[i])) { + fprintf(stdout, "%c", buf[i]); + } else { + fprintf(stdout, "."); + } + } + } + fprintf(stdout, "\n"); +} + +static int stoih(int w, char c[w], unsigned int *out) { + *out = 0; + for (int i = 0; i < w; ++i) { + (*out) <<= 4; + if (c[i] >= '0' && c[i] <= '9') { + *out |= (c[i] - '0'); + } else if (c[i] >= 'A' && c[i] <= 'F') { + *out |= (c[i] - 'A' + 0xA); + } else if (c[i] >= 'a' && c[i] <= 'f') { + *out |= (c[i] - 'a' + 0xA); + } else { + *out = 0; + return 1; + } + } + + return 0; +} + +int main(int argc, char * argv[]) { + unsigned int width = 16; /* TODO make configurable */ + int opt; + int direction = 0; + + while ((opt = getopt(argc, argv, "?w:d")) != -1) { + switch (opt) { + default: + case '?': + fprintf(stderr, "%s: convert to/from hexadecimal dump\n", argv[0]); + return 1; + case 'w': + width = atoi(optarg); + break; + case 'd': + direction = 1; + break; + } + } + + FILE * f; + char * name; + + if (optind < argc) { + f = fopen(argv[optind], "r"); + name = argv[optind]; + if (!f) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + } + } else { + name = "[stdin]"; + f = stdin; + } + + if (direction == 0) { + /* Convert to hexadecimal */ + + unsigned int sizer = 0; + unsigned int offset = 0; + unsigned char buf[width]; + while (!feof(f)) { + unsigned int r = fread(buf+offset, 1, width-offset, f); + offset += r; + + if (offset == width) { + print_line(buf, width, sizer, offset); + offset = 0; + sizer += width; + } + } + + if (offset != 0) { + print_line(buf, width, sizer, offset); + } + + } else { + /* Convert from hexify's output format */ + unsigned int eoffset = 0; + unsigned int lineno = 1; + while (!feof(f)) { + /* Read offset */ + char offset_bytes[8]; + fread(&offset_bytes, 1, 8, f); + + /* Convert offset for verification */ + unsigned int offset; + if (stoih(8, offset_bytes, &offset)) { + fprintf(stderr, "%s: %s: syntax error (bad offset) on line %d\n", argv[0], name, lineno); + fprintf(stderr, "offset bytes: %8s\n", offset_bytes); + return 1; + } + + if (offset != eoffset) { + fprintf(stderr, "%s: %s: offset mismatch on line %d\n", argv[0], name, lineno); + fprintf(stderr, "expected 0x%x, got 0x%x\n", offset, eoffset); + return 1; + } + + /* Read ": " */ + char tmp[2]; + fread(&tmp, 1, 2, f); + + if (tmp[0] != ':' || tmp[1] != ' ') { + fprintf(stderr, "%s: %s: syntax error (unexpected characters after offset) on line %d\n", argv[0], name, lineno); + return 1; + } + + /* Read [width] characters */ + for (unsigned int i = 0; i < width; ) { + unsigned int byte = 0; + for (unsigned int j = 0; i < width && j < 2; ++j, ++i) { + fread(&tmp, 1, 2, f); + if (tmp[0] == ' ' && tmp[1] == ' ') { + /* done; return */ + return 0; + } + if (stoih(2, tmp, &byte)) { + fprintf(stderr, "%s: %s: syntax error (bad byte) on line %d\n", argv[0], name, lineno); + fprintf(stderr, "byte bytes: %2s\n", tmp); + return 1; + } + fwrite(&byte, 1, 1, stdout); + } + /* Read space */ + fread(&tmp, 1, 1, f); + if (tmp[0] != ' ') { + fprintf(stderr, "%s: %s: syntax error (unexpected characters after byte) on line %d\n", argv[0], name, lineno); + fprintf(stderr, "unexpected character: %c\n", tmp[0]); + return 1; + } + } + + fread(&tmp, 1, 1, f); + if (tmp[0] != ' ') { + fprintf(stderr, "%s: %s: syntax error (unexpected characters after bytes) on line %d\n", argv[0], name, lineno); + } + + /* Read correct number of characters, plus line feed */ + char tmp2[width+2]; + fread(&tmp2, 1, width+1, f); + tmp2[width+1] = '\0'; + if (tmp2[width] != '\n') { + fprintf(stderr, "%s: %s: syntax error: expected end of line, got garbage on line %d\n", argv[0], name, lineno); + fprintf(stderr, "eol data: %s\n", tmp2); + } + + lineno++; + eoffset += width; + } + } + return 0; +} diff --git a/userspace/core/hostname.c b/apps/hostname.c similarity index 68% rename from userspace/core/hostname.c rename to apps/hostname.c index e133ca25..8231446b 100644 --- a/userspace/core/hostname.c +++ b/apps/hostname.c @@ -1,30 +1,28 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ /* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange * * hostname * * Prints or sets the system hostname. */ #include -#include - -#define ROOT_UID 0 +#include +#include int main(int argc, char * argv[]) { if ((argc > 1 && argv[1][0] == '-') || (argc < 2)) { - char tmp[256]; - syscall_gethostname(tmp); + char tmp[256] = {0}; + gethostname(tmp, 255); printf("%s\n", tmp); return 0; } else { - if (syscall_getuid() != ROOT_UID) { + if (getuid() != 0) { fprintf(stderr,"Must be root to set hostname.\n"); return 1; } else { - syscall_sethostname(argv[1]); + sethostname(argv[1], strlen(argv[1])); FILE * file = fopen("/etc/hostname", "w"); if (!file) { return 1; diff --git a/apps/imgviewer.c b/apps/imgviewer.c new file mode 100644 index 00000000..8c7f91c7 --- /dev/null +++ b/apps/imgviewer.c @@ -0,0 +1,235 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * imgviewer - Display bitmaps in a graphical window. + * + * This is probably the 4th time I've (re)written a version of + * this application... This uses the libtoaru_graphics sprite + * functionality to load images, so it will support whatever + * that ends up supporting - which at the time of writing is + * just bitmaps of various types. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Pointer to graphics memory */ +static yutani_t * yctx; +static yutani_window_t * window = NULL; +static gfx_context_t * ctx = NULL; + +static int decor_left_width = 0; +static int decor_top_height = 0; +static int decor_right_width = 0; +static int decor_bottom_height = 0; +static int decor_width = 0; +static int decor_height = 0; + +int left = 40; +int top = 40; +int width = 300; +int height = 300; + +sprite_t img = {0}; + +#define APPLICATION_TITLE "Image Viewer" + +void usage(char * argv[]) { + printf( + "Image Viewer - Shows images.\n" + "\n" + "usage: %s \033[3mimage\033[0m\n" + "\n" + " -? --help \033[3mShow this help message.\033[0m\n", + argv[0]); +} + +static void decors() { + render_decorations(window, ctx, APPLICATION_TITLE); +} + +void redraw() { + static double r = 0.0; + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + GFX(ctx,x+decor_left_width,y+decor_top_height) = (((y / 10) % 2 == 0) ^ ((x / 10) % 2 == 0)) ? rgb(107,107,107) : rgb(147,147,147); + } + } + + draw_sprite(ctx, &img, decor_left_width + width/2 - img.width/2, decor_top_height + height/2 - img.height/2); + decors(); + flip(ctx); + r += 0.02; +} + +void resize_finish(int w, int h) { + yutani_window_resize_accept(yctx, window, w, h); + reinit_graphics_yutani(ctx, window); + + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); + + decor_left_width = bounds.left_width; + decor_top_height = bounds.top_height; + decor_right_width = bounds.right_width; + decor_bottom_height = bounds.bottom_height; + decor_width = bounds.width; + decor_height = bounds.height; + + width = w - decor_left_width - decor_right_width; + height = h - decor_top_height - decor_bottom_height; + + redraw(); + yutani_window_resize_done(yctx, window); + + yutani_flip(yctx, window); +} + + +int main(int argc, char * argv[]) { + + static struct option long_opts[] = { + {"help", no_argument, 0, '?'}, + {0,0,0,0} + }; + + if (argc > 1) { + /* Read some arguments */ + int index, c; + while ((c = getopt_long(argc, argv, "h", long_opts, &index)) != -1) { + if (!c) { + if (long_opts[index].flag == 0) { + c = long_opts[index].val; + } + } + switch (c) { + case 'h': + usage(argv); + exit(0); + break; + default: + break; + } + } + } + + yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } + init_decorations(); + + struct decor_bounds bounds; + decor_get_bounds(NULL, &bounds); + + decor_left_width = bounds.left_width; + decor_top_height = bounds.top_height; + decor_right_width = bounds.right_width; + decor_bottom_height = bounds.bottom_height; + decor_width = bounds.width; + decor_height = bounds.height; + + load_sprite(&img, argv[optind]); + if (!img.width) { + fprintf(stderr, "%s: failed to open image %s\n", argv[0], argv[optind]); + return 1; + } + img.alpha = ALPHA_EMBEDDED; + + width = img.width; + height = img.height; + + window = yutani_window_create(yctx, width + decor_width, height + decor_height); + yutani_window_move(yctx, window, left, top); + + yutani_window_advertise_icon(yctx, window, APPLICATION_TITLE, "imgviewer"); + + ctx = init_graphics_yutani_double_buffer(window); + + redraw(); + yutani_flip(yctx, window); + + int playing = 1; + while (playing) { + yutani_msg_t * m = yutani_poll(yctx); + while (m) { + if (menu_process_event(yctx, m)) { + /* just decorations should be fine */ + decors(); + yutani_flip(yctx, window); + } + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { + playing = 0; + } + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * wf = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + if (win && win == window) { + win->focused = wf->focused; + decors(); + yutani_flip(yctx, window); + } + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + resize_finish(wr->width, wr->height); + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + int result = decor_handle_event(yctx, m); + switch (result) { + case DECOR_CLOSE: + playing = 0; + break; + case DECOR_RIGHT: + /* right click in decoration, show appropriate menu */ + decor_show_default_menu(window, window->x + me->new_x, window->y + me->new_y); + break; + default: + /* Other actions */ + break; + } + } + break; + case YUTANI_MSG_WINDOW_CLOSE: + case YUTANI_MSG_SESSION_END: + playing = 0; + break; + default: + break; + } + free(m); + m = yutani_poll_async(yctx); + } + } + + yutani_close(yctx, window); + + return 0; +} diff --git a/apps/init.c b/apps/init.c new file mode 100644 index 00000000..0b01aeff --- /dev/null +++ b/apps/init.c @@ -0,0 +1,146 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * init - First process. + * + * `init` calls startup scripts and then waits for them to complete. + * It also waits for orphaned proceses so they can be collected. + * + * `init` itself is statically-linked, so minimizing libc dependencies + * is worthwhile as it reduces to the total size of init itself, which + * remains in memory throughout the entire lifetime of the OS. + * + * Startup scripts for init are stored in /etc/startup.d and are run + * in sorted alphabetical order. It is generally recommended that these + * startup scripts be named with numbers at the front to ensure easy + * ordering. This system of running a set of scripts on startup is + * somewhat similar to how sysvinit worked, but no claims of + * compatibility are made. + * + * Startup scripts can be any executable binary. Shell scripts are + * generally used to allow easy editing, but you could also use + * a binary (even a dynamically linked one) as a startup script. + * `init` will wait for each startup script (that is, it will wait for + * the original process it started to exit) before running the next one. + * So if you wish to run daemons, be sure to fork them off and then + * exit so that the rest of the startup process can continue. + * + * When the last startup script finishes, `init` will reboot the system. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INITD_PATH "/etc/startup.d" + +/* Initialize fd 0, 1, 2 */ +void set_console(void) { + /* default to /dev/ttyS0 (serial COM1) */ + int _stdin = syscall_open("/dev/ttyS0", 0, 0); + if (_stdin < 0) { + /* if /dev/ttyS0 failed to open, fall back to /dev/null */ + syscall_open("/dev/null", 0, 0); + syscall_open("/dev/null", 1, 0); + syscall_open("/dev/null", 1, 0); + } else { + /* otherwise also use /dev/ttyS0 for stdout, stderr */ + syscall_open("/dev/ttyS0", 1, 0); + syscall_open("/dev/ttyS0", 1, 0); + } +} + +/* Run a startup script and wait for it to finish */ +int start_options(char * args[]) { + + /* Fork child to run script */ + int cpid = syscall_fork(); + + /* Child process... */ + if (!cpid) { + /* Pass environment from init to child */ + syscall_execve(args[0], args, environ); + /* exec failed, exit this subprocess */ + syscall_exit(0); + } + + /* Wait for the child process to finish */ + int pid = 0; + do { + /* + * Wait, ignoring kernel threads + * (which also end up as children to init) + */ + pid = waitpid(-1, NULL, WNOKERN); + + if (pid == -1 && errno == ECHILD) { + /* There are no more children */ + break; + } + + if (pid == cpid) { + /* The child process finished */ + break; + } + + /* Continue while no error (or error was "interrupted") */ + } while ((pid > 0) || (pid == -1 && errno == EINTR)); + + return cpid; +} + +int main(int argc, char * argv[]) { + /* Initialize stdin/out/err */ + set_console(); + + /* Get directory listing for /etc/startup.d */ + int initd_dir = syscall_open(INITD_PATH, 0, 0); + if (initd_dir < 0) { + /* No init scripts; try to start getty as a fallback */ + start_options((char *[]){"/bin/getty",NULL}); + } else { + int count = 0, i = 0, ret = 0; + + /* Figure out how many entries we have with a dry run */ + do { + struct dirent ent; + ret = syscall_readdir(initd_dir, ++count, &ent); + } while (ret > 0); + + /* Read each directory entry */ + struct dirent entries[count]; + do { + syscall_readdir(initd_dir, i, &entries[i]); + i++; + } while (i < count); + + /* Sort the directory entries */ + int comparator(const void * c1, const void * c2) { + const struct dirent * d1 = c1; + const struct dirent * d2 = c2; + return strcmp(d1->d_name, d2->d_name); + } + qsort(entries, count, sizeof(struct dirent), comparator); + + /* Run scripts */ + for (int i = 0; i < count; ++i) { + if (entries[i].d_name[0] != '.') { + char path[256]; + sprintf(path, "/etc/startup.d/%s", entries[i].d_name); + start_options((char *[]){path, NULL}); + } + } + } + + /* Self-explanatory */ + syscall_reboot(); + return 0; +} diff --git a/userspace/extra/insmod.c b/apps/insmod.c similarity index 61% rename from userspace/extra/insmod.c rename to apps/insmod.c index b47adff6..19364f65 100644 --- a/userspace/extra/insmod.c +++ b/apps/insmod.c @@ -1,6 +1,10 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016 Kevin Lange + * Copyright (C) 2016 K. Lange + * + * insmod - Load kernel module + * */ #include #include diff --git a/apps/irc.c b/apps/irc.c new file mode 100644 index 00000000..9e1f8a68 --- /dev/null +++ b/apps/irc.c @@ -0,0 +1,542 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * irc - Internet Relay Chat client + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _ITALIC "\033[3m" +#define _END "\033[0m\n" + +#define VERSION_STRING "0.3.0" + +/* Theming */ +#define TIME_FMT "%02d:%02d:%02d" +#define TIME_ARGS hr, min, sec + +static char * nick = "toaru-user"; +static char * host = NULL; +static char * pass = NULL; +static unsigned short port = 6667; + +static char * channel = NULL; + +static int sock_fd; +static FILE * sock_r; +static FILE * sock_w; + +struct color_pair { + int fg; + int bg; +}; + +static void show_usage(int argc, char * argv[]) { + fprintf(stderr, + "irc - Terminal IRC client.\n" + "\n" + "usage: %s [-h] [-p port] [-n nick] host\n" + "\n" + " -p port " _ITALIC "Specify port to connect to" _END + " -P pass " _ITALIC "Password for server connection" _END + " -n nick " _ITALIC "Specify a nick to use" _END + " -h " _ITALIC "Print this help message" _END + "\n", argv[0]); + exit(1); +} + +static struct termios old; + +static void set_unbuffered() { + tcgetattr(fileno(stdin), &old); + struct termios new = old; + new.c_lflag &= (~ICANON & ~ECHO); + tcsetattr(fileno(stdin), TCSAFLUSH, &new); +} + +static void set_buffered() { + tcsetattr(fileno(stdin), TCSAFLUSH, &old); +} + +static int user_color(char * user) { + int i = 0; + while (*user) { + i += *user; + user++; + } + i = i % 5; + switch (i) { + case 0: return 2; + case 1: return 3; + case 2: return 4; + case 3: return 6; + case 4: return 10; + } + return 0; +} + +static struct color_pair irc_color_to_pair(int fg, int bg) { + int _fg = 0; + int _bg = 0; + if (fg == -1) { + _fg = -1; + } else { + fg = fg % 16; + switch (fg) { + case 0: _fg = 15; break; + case 1: _fg = 0; break; + case 2: _fg = 4; break; + case 3: _fg = 2; break; + case 4: _fg = 9; break; + case 5: _fg = 1; break; + case 6: _fg = 5; break; + case 7: _fg = 3; break; + case 8: _fg = 11; break; + case 9: _fg = 10; break; + case 10: _fg = 6; break; + case 11: _fg = 14; break; + case 12: _fg = 12; break; + case 13: _fg = 13; break; + case 14: _fg = 8; break; + case 15: _fg = 7; break; + } + } + if (bg == -1) { + _bg = -1; + } else { + bg = bg % 16; + switch (bg) { + case 0: _bg = 15; break; + case 1: _bg = 0; break; + case 2: _bg = 4; break; + case 3: _bg = 2; break; + case 4: _bg = 9; break; + case 5: _bg = 1; break; + case 6: _bg = 5; break; + case 7: _bg = 3; break; + case 8: _bg = 11; break; + case 9: _bg = 10; break; + case 10: _bg = 6; break; + case 11: _bg = 14; break; + case 12: _bg = 12; break; + case 13: _bg = 13; break; + case 14: _bg = 8; break; + case 15: _bg = 7; break; + } + } + return (struct color_pair){_fg, _bg}; +} + +static void get_time(int * h, int * m, int * s) { + time_t rawtime; + time(&rawtime); + struct tm *tm_struct = localtime(&rawtime); + + *h = tm_struct->tm_hour; + *m = tm_struct->tm_min; + *s = tm_struct->tm_sec; +} + +static void print_color(struct color_pair t) { + fprintf(stdout, "\033["); + if (t.fg == -1) { + fprintf(stdout,"39"); + } else if (t.fg > 15) { + /* TODO */ + } else if (t.fg > 7) { + fprintf(stdout,"9%d", t.fg - 8); + } else { + fprintf(stdout,"3%d", t.fg); + } + fprintf(stdout, ";"); + if (t.bg == -1) { + fprintf(stdout, "49"); + } else if (t.bg > 15) { + /* TODO */ + } else if (t.bg > 7) { + fprintf(stdout,"10%d", t.bg - 8); + } else { + fprintf(stdout,"4%d", t.bg); + } + fprintf(stdout, "m"); + fflush(stdout); +} + +static void WRITE(const char * fmt, ...) { + + int bold_on = 0; + int italic_on = 0; + + va_list args; + va_start(args, fmt); + char * tmp; + vasprintf(&tmp, fmt, args); + va_end(args); + + struct winsize w; + ioctl(0, TIOCGWINSZ, &w); + fprintf(stdout,"\033[%d;1H\033[K", w.ws_row); + + int line_feed_pending = 0; + char * c = tmp; + + while (*c) { + if (*c == '\n') { + if (line_feed_pending) { + /* Print line feed */ + fprintf(stdout, "\n"); + } + line_feed_pending = 1; + c++; + continue; + } else { + if (line_feed_pending) { + line_feed_pending = 0; + /* Print line feed */ + fprintf(stdout, "\n"); + } + } + if (*c == 0x03) { + c++; + int i = -1; + int j = -1; + if (*c >= '0' && *c <= '9') { + i = (*c - '0'); + c++; + } + if (*c >= '0' && *c <= '9') { + i *= 10; + i += (*c - '0'); + c++; + } + if (*c == ',') { + c++; + if (*c >= '0' && *c <= '9') { + j = (*c - '0'); + c++; + } + if (*c >= '0' && *c <= '9') { + j *= 10; + j = (*c - '0'); + c++; + } + } + struct color_pair t = irc_color_to_pair(i, j); + print_color(t); + continue; + } + if (*c == 0x02) { + if (bold_on) { + fprintf(stdout,"\033[22m"); + bold_on = 0; + } else { + fprintf(stdout,"\033[1m"); + bold_on = 1; + } + c++; + continue; + } + if (*c == 0x16) { + if (italic_on) { + fprintf(stdout,"\033[23m"); + italic_on = 0; + } else { + fprintf(stdout,"\033[3m"); + italic_on = 1; + } + c++; + continue; + } + if (*c == 0x0f) { + fprintf(stdout, "\033[0m"); + c++; + bold_on = 0; + italic_on = 0; + continue; + } + + fprintf(stdout, "%c", *c); + c++; + } + if (line_feed_pending) { + fprintf(stdout, "\033[0m\033[K\n"); + } + fflush(stdout); + free(tmp); +} + +static void handle(char * line) { + char * c = line; + while (c < line + strlen(line)) { + char * e = strstr(c, "\r\n"); + if (e > line + strlen(line)) { + break; + } + + if (!e) { + /* Write c */ + WRITE(c); + goto next; + } + + *e = '\0'; + + if (strstr(c, "PING") == c) { + char * t = strstr(c, ":"); + fprintf(sock_w, "PONG %s\r\n", t); + fflush(sock_w); + goto next; + } + + char * user, * command, * channel, * message; + + user = c; + if (user[0] == ':') { + user++; + } + + command = strstr(user, " "); + if (!command) { + WRITE("%s\n", user); + goto next; + } + command[0] = '\0'; + command++; + + channel = strstr(command, " "); + if (!channel) { + WRITE("%s %s\n", user, command); + goto next; + } + channel[0] = '\0'; + channel++; + + message = strstr(channel, " "); + if (message) { + message[0] = '\0'; + message++; + if (message[0] == ':') { + message++; + } + } + + int hr, min, sec; + get_time(&hr, &min, &sec); + + if (!strcmp(command, "PRIVMSG")) { + if (!message) continue; + char * t = strstr(user, "!"); + if (t) { t[0] = '\0'; } + t = strstr(user, "@"); + if (t) { t[0] = '\0'; } + + if (strstr(message, "\001ACTION ") == message) { + message = message + 8; + char * x = strstr(message, "\001"); + if (x) *x = '\0'; + WRITE(TIME_FMT " \002* \003%d%s\003\002 %s\n", TIME_ARGS, user_color(user), user, message); + } else { + WRITE(TIME_FMT " \00314<\003%d%s\00314>\003 %s\n", TIME_ARGS, user_color(user), user, message); + } + } else if (!strcmp(command, "332")) { + if (!message) { + continue; + } + /* Topic */ + } else if (!strcmp(command, "JOIN")) { + char * t = strstr(user, "!"); + if (t) { t[0] = '\0'; } + t = strstr(user, "@"); + if (t) { t[0] = '\0'; } + if (channel[0] == ':') { channel++; } + + WRITE(TIME_FMT " \00312-\003!\00312-\00311 %s\003 has joined \002%s\n", TIME_ARGS, user, channel); + } else if (!strcmp(command, "PART")) { + char * t = strstr(user, "!"); + if (t) { t[0] = '\0'; } + t = strstr(user, "@"); + if (t) { t[0] = '\0'; } + if (channel[0] == ':') { channel++; } + + WRITE(TIME_FMT " \00312-\003!\00312\003-\00310 %s\003 has left \002%s\n", TIME_ARGS, user, channel); + } else if (!strcmp(command, "372")) { + WRITE(TIME_FMT " \00314%s\003 %s\n", TIME_ARGS, user, message ? message : ""); + } else if (!strcmp(command, "376")) { + /* End of MOTD */ + WRITE(TIME_FMT " \00314%s (end of MOTD)\n", TIME_ARGS, user); + } else { + WRITE(TIME_FMT " \00310%s %s %s %s\n", TIME_ARGS, user, command, channel, message ? message : ""); + } + +next: + if (!e) break; + c = e + 2; + } +} + +static void redraw_buffer(char * buf) { + struct winsize w; + ioctl(0, TIOCGWINSZ, &w); + fprintf(stdout,"\033[%d;1H [%s] ", w.ws_row, channel ? channel : "(status)"); + fprintf(stdout,"%s\033[K", buf); + fflush(stdout); +} + +void handle_input(char * buf) { + fflush(stdout); + if (strstr(buf, "/help") == buf) { + WRITE("[help] help text goes here\n"); + } else if (strstr(buf, "/quit") == buf) { + char * m = strstr(buf, " "); if (m) m++; + fprintf(sock_w, "QUIT :%s\r\n", m ? m : "https://gitlab.com/toaruos"); + fflush(sock_w); + fprintf(stderr,"\033[0m\n"); + set_buffered(); + exit(0); + } else if (strstr(buf,"/part") == buf) { + if (!channel) { + fprintf(stderr, "Not in a channel.\n"); + return; + } + char * m = strstr(buf, " "); if (m) m++; + fprintf(sock_w, "PART %s%s%s\r\n", channel, m ? " :" : "", m ? m : ""); + fflush(sock_w); + free(channel); + channel = NULL; + } else if (strstr(buf,"/join ") == buf) { + char * m = strstr(buf, " "); if (m) m++; + fprintf(sock_w, "JOIN %s\r\n", m); + fflush(sock_w); + channel = strdup(m); + } else if (strstr(buf, "/") == buf) { + WRITE("[system] Unknown command: %s\n", buf); + } else { + int hr, min, sec; + get_time(&hr, &min, &sec); + WRITE("%02d:%02d:%02d \00314<\003\002%s\002\00314>\003 %s\n", hr, min, sec, nick, buf); + fprintf(sock_w, "PRIVMSG %s :%s\r\n", channel, buf); + } + redraw_buffer(""); +} + +int main(int argc, char * argv[]) { + + /* Option parsing */ + int c; + while ((c = getopt(argc, argv, "?hp:n:P:")) != -1) { + switch (c) { + case 'n': + nick = optarg; + break; + case 'P': + pass = optarg; + break; + case 'p': + port = atoi(optarg); + break; + case 'h': + case '?': + default: + show_usage(argc, argv); + break; + } + } + + if (optind >= argc) { + show_usage(argc, argv); + } + + host = argv[optind]; + + /* Connect */ + { + char tmphost[512]; + sprintf(tmphost, "/dev/net/%s:%d", host, port); + sock_fd = open(tmphost, O_RDWR); + if (sock_fd < 0) { + fprintf(stderr, "%s: Connection failed or network not available.\n", argv[0]); + return 1; + } + sock_r = fdopen(sock_fd, "r"); + sock_w = fdopen(sock_fd, "w"); + } + + set_unbuffered(); + + fprintf(stdout, " - Toaru IRC v %s - \n", VERSION_STRING); + fprintf(stdout, " Copyright 2015-2018 K. Lange\n"); + fprintf(stdout, " https://toaruos.org - https://gitlab.com/toaruos\n"); + fprintf(stdout, " \n"); + fprintf(stdout, " For help, type /help\n"); + + if (pass) { + fprintf(sock_w, "PASS %s\r\n", pass); + } + fprintf(sock_w, "NICK %s\r\nUSER %s * 0 :%s\r\n", nick, nick, nick); + fflush(sock_w); + + int fds[] = {sock_fd, STDIN_FILENO, sock_fd}; + + char net_buf[2048]; + memset(net_buf, 0, 2048); + int net_buf_p = 0; + + char buf[1024] = {0}; + int buf_p = 0; + + while (1) { + int index = fswait2(2,fds,200); + + if (index == 1) { + /* stdin */ + int c = fgetc(stdin); + if (c < 0) { + continue; + } + if (c == 0x08) { + /* Remove from buffer */ + if (buf_p) { + buf[buf_p-1] = '\0'; + buf_p--; + redraw_buffer(buf); + } + } else if (c == '\n') { + /* Send buffer */ + handle_input(buf); + memset(buf, 0, 1024); + buf_p = 0; + } else { + /* Append buffer, or check special keys */ + buf[buf_p] = c; + buf_p++; + redraw_buffer(buf); + } + } else if (index == 0) { + /* network */ + do { + int c = fgetc(sock_r); + if (c < 0) continue; + net_buf[net_buf_p] = c; + net_buf_p++; + if (c == '\n' || net_buf_p == 2046) { + handle(net_buf); + net_buf_p = 0; + memset(net_buf, 0, 2048); + redraw_buffer(buf); + } + } while (!_fwouldblock(sock_r)); + } else { + /* timer */ + } + } + +} diff --git a/userspace/gui/basic/julia.c b/apps/julia.c similarity index 76% rename from userspace/gui/basic/julia.c rename to apps/julia.c index 5d1fda3b..92f29ba6 100644 --- a/userspace/gui/basic/julia.c +++ b/apps/julia.c @@ -1,9 +1,9 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* - * Julia Fractal Generator + * Copyright (C) 2013-2018 K. Lange + * + * julia - Julia Fractal Generator * * This is the updated windowed version of the * julia fractal generator demo. @@ -11,31 +11,32 @@ #include #include -#include #include #include #include #include #include -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/decorations.h" +#include +#include +#include +#include -#define DIRECT_OFFSET(x,y) ((x) + (y) * window->width) - -/* - * Macros make verything easier. - */ -#define SPRITE(sprite,x,y) sprite->bitmap[sprite->width * (y) + (x)] - -#define GFX_(xpt, ypt) ((uint32_t *)window->buffer)[DIRECT_OFFSET(xpt+decor_left_width,ypt+decor_top_height)] +#define GFX_(xpt, ypt) (GFX(ctx,xpt+decor_left_width,ypt+decor_top_height)) /* Pointer to graphics memory */ static yutani_t * yctx; static yutani_window_t * window = NULL; static gfx_context_t * ctx = NULL; +static int decor_left_width = 0; +static int decor_top_height = 0; +static int decor_right_width = 0; +static int decor_bottom_height = 0; +static int decor_width = 0; +static int decor_height = 0; + + /* Julia fractals elements */ float conx = -0.74; /* real part of c */ float cony = 0.1; /* imag part of c */ @@ -159,6 +160,7 @@ void redraw() { newcolor = lastcolor; i+= 2; } while ( i < width ); + yutani_flip(yctx, window); ++j; } while ( j < height ); } @@ -167,12 +169,25 @@ void resize_finish(int w, int h) { yutani_window_resize_accept(yctx, window, w, h); reinit_graphics_yutani(ctx, window); + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); + + decor_left_width = bounds.left_width; + decor_top_height = bounds.top_height; + decor_right_width = bounds.right_width; + decor_bottom_height = bounds.bottom_height; + decor_width = bounds.width; + decor_height = bounds.height; + width = w - decor_left_width - decor_right_width; height = h - decor_top_height - decor_bottom_height; + draw_fill(ctx, rgb(0,0,0)); + decors(); + yutani_window_resize_done(yctx, window); + redraw(); - yutani_window_resize_done(yctx, window); yutani_flip(yctx, window); } @@ -237,9 +252,23 @@ int main(int argc, char * argv[]) { } yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } init_decorations(); - window = yutani_window_create(yctx, width + decor_width(), height + decor_height()); + struct decor_bounds bounds; + decor_get_bounds(NULL, &bounds); + + decor_left_width = bounds.left_width; + decor_top_height = bounds.top_height; + decor_right_width = bounds.right_width; + decor_bottom_height = bounds.bottom_height; + decor_width = bounds.width; + decor_height = bounds.height; + + window = yutani_window_create(yctx, width + decor_width, height + decor_height); yutani_window_move(yctx, window, left, top); yutani_window_advertise_icon(yctx, window, "Julia Fractals", "julia"); @@ -252,7 +281,12 @@ int main(int argc, char * argv[]) { int playing = 1; while (playing) { yutani_msg_t * m = yutani_poll(yctx); - if (m) { + while (m) { + if (menu_process_event(yctx, m)) { + /* just decorations should be fine */ + decors(); + yutani_flip(yctx, window); + } switch (m->type) { case YUTANI_MSG_KEY_EVENT: { @@ -266,7 +300,7 @@ int main(int argc, char * argv[]) { { struct yutani_msg_window_focus_change * wf = (void*)m->data; yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); - if (win) { + if (win && win == window) { win->focused = wf->focused; decors(); yutani_flip(yctx, window); @@ -281,25 +315,32 @@ int main(int argc, char * argv[]) { break; case YUTANI_MSG_WINDOW_MOUSE_EVENT: { + struct yutani_msg_window_mouse_event * me = (void*)m->data; int result = decor_handle_event(yctx, m); switch (result) { case DECOR_CLOSE: playing = 0; break; + case DECOR_RIGHT: + /* right click in decoration, show appropriate menu */ + decor_show_default_menu(window, window->x + me->new_x, window->y + me->new_y); + break; default: /* Other actions */ break; } } break; + case YUTANI_MSG_WINDOW_CLOSE: case YUTANI_MSG_SESSION_END: playing = 0; break; default: break; } + free(m); + m = yutani_poll_async(yctx); } - free(m); } yutani_close(yctx, window); diff --git a/apps/kcmdline.c b/apps/kcmdline.c new file mode 100644 index 00000000..a6456888 --- /dev/null +++ b/apps/kcmdline.c @@ -0,0 +1,138 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * kcmdline - Parse /proc/cmdline usefully. + * + * Parses /proc/cmdline and provides an interface for querying + * whether an argument was present, and its value if applicable. + * + * Also converts ASCII field separators to spaces so that cmdline + * arguments can have spaces in them. + * + * Useful for shell scripts. + * + * TODO: This should probably be a library we can use in other + * applications... + */ +#include +#include +#include +#include +#include + +hashmap_t * args_map = NULL; + +int tokenize(char * str, char * sep, char **buf) { + char * pch_i; + char * save_i; + int argc = 0; + pch_i = strtok_r(str,sep,&save_i); + if (!pch_i) { return 0; } + while (pch_i != NULL) { + buf[argc] = (char *)pch_i; + ++argc; + pch_i = strtok_r(NULL,sep,&save_i); + } + buf[argc] = NULL; + return argc; +} + +void args_parse(char * _arg) { + char * arg = strdup(_arg); + char * argv[1024]; + int argc = tokenize(arg, " ", argv); + + for (int i = 0; i < argc; ++i) { + char * c = strdup(argv[i]); + + char * name; + char * value; + + name = c; + value = NULL; + /* Find the first = and replace it with a null */ + char * v = c; + while (*v) { + if (*v == '=') { + *v = '\0'; + v++; + value = v; + char * tmp = value; + /* scan it for \037 and replace with spaces */ + while (*tmp) { + if (*tmp == '\037') { + *tmp = ' '; + } + tmp++; + } + goto _break; + } + v++; + } + +_break: + hashmap_set(args_map, name, value); + } + + free(arg); +} + +void show_usage(int argc, char * argv[]) { + printf( + "kcmdline - query the kernel command line\n" + "\n" + "usage: %s -g ARG...\n" + " %s -q ARG...\n" + "\n" + " -g \033[3mprint the value for the requested argument\033[0m\n" + " -q \033[3mquery whether the requested argument is present (0 = yes)\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0], argv[0]); +} + +int main(int argc, char * argv[]) { + /* Open */ + FILE * f = fopen("/proc/cmdline", "r"); + if (!f) return 1; + + /* Read */ + char * cmdline = malloc(4096); /* cmdline can't be longer than that */ + memset(cmdline, 0, 4096); + size_t size = fread(cmdline, 1, 4096, f); + if (cmdline[size-1] == '\n') cmdline[size-1] = '\0'; + fclose(f); + + /* Parse */ + args_map = hashmap_create(10); + args_parse(cmdline); + + /* Figure out what we're doing */ + int opt; + while ((opt = getopt(argc, argv, "?g:q:s")) != -1) { + switch (opt) { + case 'g': + if (hashmap_has(args_map, optarg)) { + char * tmp = (char*)hashmap_get(args_map, optarg); + if (!tmp) { + printf("%s\n", optarg); /* special case = present but not set should yield name of variable */ + } else { + printf("%s\n", tmp); + } + return 0; + } else { + return 1; + } + case 'q': + return !hashmap_has(args_map,optarg); + case 's': + return size; + case '?': + show_usage(argc, argv); + return 1; + } + } + + fprintf(stdout, "%s\n", cmdline); +} diff --git a/apps/kdebug.c b/apps/kdebug.c new file mode 100644 index 00000000..d1d320a6 --- /dev/null +++ b/apps/kdebug.c @@ -0,0 +1,16 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014-2018 K. Lange + * + * kdebug - Launch kernel shell + */ +#include +#include + +int main(int argc, char * argv[]) { + syscall_system_function(7, NULL); + int status; + wait(&status); + return WEXITSTATUS(status); +} diff --git a/userspace/core/kill.c b/apps/kill.c similarity index 84% rename from userspace/core/kill.c rename to apps/kill.c index 175a7560..ccc1a42a 100644 --- a/userspace/core/kill.c +++ b/apps/kill.c @@ -1,10 +1,11 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2017 Kevin Lange + * Copyright (C) 2013-2018 K. Lange * - * kill + * kill - Send a signal to a process * - * Send a signal to another process + * Supports signal names like any mature `kill` should. */ #include #include @@ -59,14 +60,14 @@ struct sig_def signals[] = { void usage(char * argv[]) { printf( - "kill - send a signal to another process\n" + "%s - send a signal to another process\n" "\n" "usage: %s [-\033[3mx\033[0m] \033[3mprocess\033[0m\n" "\n" " -h --help \033[3mShow this help message.\033[0m\n" " -\033[3mx\033[0m \033[3mSignal number to send\033[0m\n" "\n", - argv[0]); + argv[0], argv[0]); } int main(int argc, char * argv[]) { @@ -81,7 +82,7 @@ int main(int argc, char * argv[]) { if (argc > 2) { if (argv[1][0] == '-') { signum = -1; - if (strlen(argv[1]+1) > 3 && !strncmp(argv[1]+1,"SIG",3)) { + if (strlen(argv[1]+1) > 3 && strstr(argv[1]+1,"SIG") == (argv[1]+1)) { struct sig_def * s = signals; while (s->name) { if (!strcmp(argv[1]+4,s->name)) { diff --git a/apps/killall.c b/apps/killall.c new file mode 100644 index 00000000..67d4b58d --- /dev/null +++ b/apps/killall.c @@ -0,0 +1,222 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * killall - Send signals to processes matching name + * + * Find processes by name and send them signals. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct process { + int pid; + int ppid; + int tgid; + char name[100]; + char path[200]; +} p_t; + +#define LINE_LEN 4096 + +p_t * build_entry(struct dirent * dent) { + char tmp[256]; + FILE * f; + char line[LINE_LEN]; + + sprintf(tmp, "/proc/%s/status", dent->d_name); + f = fopen(tmp, "r"); + + p_t * proc = malloc(sizeof(p_t)); + + while (fgets(line, LINE_LEN, f) != NULL) { + char * n = strstr(line,"\n"); + if (n) { *n = '\0'; } + char * tab = strstr(line,"\t"); + if (tab) { + *tab = '\0'; + tab++; + } + if (strstr(line, "Pid:") == line) { + proc->pid = atoi(tab); + } else if (strstr(line, "PPid:") == line) { + proc->ppid = atoi(tab); + } else if (strstr(line, "Tgid:") == line) { + proc->tgid = atoi(tab); + } else if (strstr(line, "Name:") == line) { + strcpy(proc->name, tab); + } else if (strstr(line, "Path:") == line) { + strcpy(proc->path, tab); + } + } + + if (strstr(proc->name,"python") == proc->name) { + char * name = proc->path + strlen(proc->path) - 1; + + while (1) { + if (*name == '/') { + name++; + break; + } + if (name == proc->name) break; + name--; + } + + memcpy(proc->name, name, strlen(name)+1); + } + + if (proc->tgid != proc->pid) { + char tmp[100] = {0}; + sprintf(tmp, "{%s}", proc->name); + memcpy(proc->name, tmp, strlen(tmp)+1); + } + + fclose(f); + + return proc; +} + +void show_usage(int argc, char * argv[]) { + printf( + "killall - send signal to processes with given name\n" + "\n" + "usage: %s [-s SIG] name\n" + "\n" + " -s \033[3msignal to send\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); +} + +struct sig_def { + int sig; + const char * name; +}; + +struct sig_def signals[] = { + {SIGHUP,"HUP"}, + {SIGINT,"INT"}, + {SIGQUIT,"QUIT"}, + {SIGILL,"ILL"}, + {SIGTRAP,"TRAP"}, + {SIGABRT,"ABRT"}, + {SIGEMT,"EMT"}, + {SIGFPE,"FPE"}, + {SIGKILL,"KILL"}, + {SIGBUS,"BUS"}, + {SIGSEGV,"SEGV"}, + {SIGSYS,"SYS"}, + {SIGPIPE,"PIPE"}, + {SIGALRM,"ALRM"}, + {SIGTERM,"TERM"}, + {SIGUSR1,"USR1"}, + {SIGUSR2,"USR2"}, + {SIGCHLD,"CHLD"}, + {SIGPWR,"PWR"}, + {SIGWINCH,"WINCH"}, + {SIGURG,"URG"}, + {SIGPOLL,"POLL"}, + {SIGSTOP,"STOP"}, + {SIGTSTP,"TSTP"}, + {SIGCONT,"CONT"}, + {SIGTTIN,"TTIN"}, + {SIGTTOUT,"TTOUT"}, + {SIGVTALRM,"VTALRM"}, + {SIGPROF,"PROF"}, + {SIGXCPU,"XCPU"}, + {SIGXFSZ,"XFSZ"}, + {SIGWAITING,"WAITING"}, + {SIGDIAF,"DIAF"}, + {SIGHATE,"HATE"}, + {SIGWINEVENT,"WINEVENT"}, + {SIGCAT,"CAT"}, + {0,NULL}, +}; + +int main (int argc, char * argv[]) { + + int signum = SIGTERM; + + /* Open the directory */ + DIR * dirp = opendir("/proc"); + + char c; + while ((c = getopt(argc, argv, "s:?")) != -1) { + switch (c) { + case 's': + { + signum = -1; + if (strlen(optarg) > 3 && strstr(optarg,"SIG") == (optarg)) { + struct sig_def * s = signals; + while (s->name) { + if (!strcmp(optarg+3,s->name)) { + signum = s->sig; + break; + } + s++; + } + } else { + if (optarg[0] < '0' || optarg[0] > '9') { + struct sig_def * s = signals; + while (s->name) { + if (!strcmp(optarg,s->name)) { + signum = s->sig; + break; + } + s++; + } + } else { + signum = atoi(optarg); + } + } + if (signum == -1) { + fprintf(stderr,"%s: %s: invalid signal specification\n",argv[0],optarg); + return 1; + } + } + break; + case '?': + show_usage(argc, argv); + return 0; + } + } + + if (optind >= argc) { + show_usage(argc, argv); + return 1; + } + + int killed_something = 0; + + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') { + p_t * proc = build_entry(ent); + + if (!strcmp(proc->name, argv[optind])) { + kill(proc->pid, signum); + killed_something = 1; + } + } + ent = readdir(dirp); + } + closedir(dirp); + + if (!killed_something) { + fprintf(stderr, "%s: no process found\n", argv[optind]); + return 1; + } + return 0; +} + diff --git a/apps/live-session.c b/apps/live-session.c new file mode 100644 index 00000000..c412796e --- /dev/null +++ b/apps/live-session.c @@ -0,0 +1,61 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * live-session - Run live CD user session. + * + * Launches the general session manager as 'local', waits for the + * session to end, then launches the login manager. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define TRACE_APP_NAME "live-session" + +int main(int argc, char * argv[]) { + int pid; + + if (getuid() != 0) { + return 1; + } + + int _session_pid = fork(); + if (!_session_pid) { + setuid(1000); + toaru_auth_set_vars(); + + char * args[] = {"/bin/session", NULL}; + execvp(args[0], args); + + return 1; + } + + /* Dummy session for live-session prevents compositor from killing itself + * when the main session dies the first time. */ + yutani_init(); + + do { + pid = wait(NULL); + } while ((pid > 0 && pid != _session_pid) || (pid == -1 && errno == EINTR)); + + TRACE("Live session has ended, launching graphical login."); + int _glogin_pid = fork(); + if (!_glogin_pid) { + char * args[] = {"/bin/glogin",NULL}; + execvp(args[0],args); + system("reboot"); + } + + do { + pid = wait(NULL); + } while ((pid > 0 && pid != _glogin_pid) || (pid == -1 && errno == EINTR)); + + return 0; +} diff --git a/userspace/core/ln.c b/apps/ln.c similarity index 79% rename from userspace/core/ln.c rename to apps/ln.c index 3e674849..90585735 100644 --- a/userspace/core/ln.c +++ b/apps/ln.c @@ -2,11 +2,13 @@ * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md * Copyright (C) 2015 Mike Gerow + * 2018 K. Lange */ #include #include #include +#include static const char usage[] = "Usage: %s [-s] TARGET NAME\n" @@ -39,15 +41,20 @@ int main(int argc, char * argv[]) { if (symlink_flag) { if(symlink(target, name) < 0) { - perror("symlink"); + fprintf(stderr, "%s: %s: %s\n", argv[0], name, strerror(errno)); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } +#ifdef link if (link(target, name) < 0) { - perror("link"); + fprintf(stderr, "%s: %s: %s\n", argv[0], name, strerror(errno)); exit(EXIT_FAILURE); } +#else + fprintf(stderr, "%s: %s: hard link not supported\n", argv[0], name); +#endif + exit(EXIT_SUCCESS); } diff --git a/apps/login-loop.c b/apps/login-loop.c new file mode 100644 index 00000000..7f01756a --- /dev/null +++ b/apps/login-loop.c @@ -0,0 +1,32 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * login-loop - Continuously call `login` + * + * Used by the VGA terminal to provide interactive login sessions. + */ +#include +#include +#include + +int main(int argc, char * argv[]) { + while (1) { + pid_t f = fork(); + if (!f) { + char * args[] = { + "login", + NULL + }; + execvp(args[0], args); + } else { + int result; + do { + result = waitpid(f, NULL, 0); + } while (result < 0); + } + } + + return 1; +} diff --git a/userspace/core/login.c b/apps/login.c similarity index 65% rename from userspace/core/login.c rename to apps/login.c index 64b4ea2c..77502754 100644 --- a/userspace/core/login.c +++ b/apps/login.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2014 K. Lange * * Login Service * @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -19,10 +18,11 @@ #include #include #include +#include #include #include -#include "lib/toaru_auth.h" +#include #define LINE_LEN 1024 @@ -44,6 +44,30 @@ void sig_segv(int sig) { int main(int argc, char ** argv) { + char * user = NULL; + int uid; + pid_t pid, f; + + int opt; + while ((opt = getopt(argc, argv, "f:")) != -1) { + switch (opt) { + case 'f': + user = optarg; + break; + } + } + + if (user) { + struct passwd * pw = getpwnam(user); + if (pw) { + uid = pw->pw_uid; + goto do_fork; + } else { + fprintf(stderr, "%s: no such user\n", argv[0]); + return 1; + } + } + printf("\n"); system("uname -a"); printf("\n"); @@ -53,12 +77,13 @@ int main(int argc, char ** argv) { signal(SIGSEGV, sig_segv); while (1) { - char * username = malloc(sizeof(char) * 1024); - char * password = malloc(sizeof(char) * 1024); + + char username[1024] = {0}; + char password[1024] = {0}; /* TODO: gethostname() */ char _hostname[256]; - syscall_gethostname(_hostname); + gethostname(_hostname, 255); fprintf(stdout, "%s login: ", _hostname); fflush(stdout); @@ -72,6 +97,11 @@ int main(int argc, char ** argv) { } username[strlen(username)-1] = '\0'; + if (!strcmp(username, "reboot")) { + /* Quick hack so vga text mode login can exit */ + system("reboot"); + } + fprintf(stdout, "password: "); fflush(stdout); @@ -95,7 +125,7 @@ int main(int argc, char ** argv) { tcsetattr(fileno(stdin), TCSAFLUSH, &old); fprintf(stdout, "\n"); - int uid = toaru_auth_check_pass(username, password); + uid = toaru_auth_check_pass(username, password); if (uid < 0) { sleep(2); @@ -103,30 +133,31 @@ int main(int argc, char ** argv) { continue; } - system("cat /etc/motd"); - - pid_t pid = getpid(); - - pid_t f = fork(); - if (getpid() != pid) { - setuid(uid); - toaru_auth_set_vars(); - char * args[] = { - getenv("SHELL"), - NULL - }; - int i = execvp(args[0], args); - } else { - child = f; - int result; - do { - result = waitpid(f, NULL, 0); - } while (result < 0); - } - child = 0; - free(username); - free(password); + break; } + system("cat /etc/motd"); + +do_fork: + pid = getpid(); + f = fork(); + if (getpid() != pid) { + setuid(uid); + toaru_auth_set_vars(); + char * args[] = { + getenv("SHELL"), + NULL + }; + execvp(args[0], args); + return 1; + } else { + child = f; + int result; + do { + result = waitpid(f, NULL, 0); + } while (result < 0); + } + child = 0; + return 0; } diff --git a/userspace/core/ls.c b/apps/ls.c similarity index 89% rename from userspace/core/ls.c rename to apps/ls.c index 8ad39f0e..c5becec9 100644 --- a/userspace/core/ls.c +++ b/apps/ls.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2018 K. Lange * * ls * @@ -15,17 +15,21 @@ #include #include #include -#include #include #include #include +#include #include #include #include #include -#include "lib/list.h" +#define TRACE_APP_NAME "ls" +//#include "lib/trace.h" +#define TRACE(...) + +#include #define MIN_COL_SPACING 2 @@ -49,7 +53,6 @@ static int human_readable = 0; static int stdout_is_tty = 1; static int this_year = 0; -static int explicit_path_set = 0; static int show_hidden = 0; static int long_mode = 0; static int print_dir = 0; @@ -95,6 +98,7 @@ static int filecmp(const void * c1, const void * c2) { if (a == b) return strcmp(d1->name, d2->name); else if (a < b) return -1; else if (a > b) return 1; + return 0; /* impossible ? */ } static int filecmp_notypesort(const void * c1, const void * c2) { @@ -122,12 +126,15 @@ static void print_entry(struct tfile * file, int colwidth) { static int print_username(char * _out, int uid) { + TRACE("getpwuid"); struct passwd * p = getpwuid(uid); int out = 0; if (p) { + TRACE("p is set"); out = sprintf(_out, "%s", p->pw_name); } else { + TRACE("p is not set"); out = sprintf(_out, "%d", uid); } @@ -139,12 +146,12 @@ static int print_username(char * _out, int uid) { static int print_human_readable_size(char * _out, size_t s) { if (s >= 1<<20) { size_t t = s / (1 << 20); - return sprintf(_out, "%d.%1dM", t, (s - t * (1 << 20)) / ((1 << 20) / 10)); + return sprintf(_out, "%d.%1dM", (int)t, (int)(s - t * (1 << 20)) / ((1 << 20) / 10)); } else if (s >= 1<<10) { size_t t = s / (1 << 10); - return sprintf(_out, "%d.%1dK", t, (s - t * (1 << 10)) / ((1 << 10) / 10)); + return sprintf(_out, "%d.%1dK", (int)t, (int)(s - t * (1 << 10)) / ((1 << 10) / 10)); } else { - return sprintf(_out, "%d", s); + return sprintf(_out, "%d", (int)s); } } @@ -153,22 +160,26 @@ static void update_column_widths(int * widths, struct tfile * file) { int n; /* Links */ + TRACE("links"); n = sprintf(tmp, "%d", file->statbuf.st_nlink); if (n > widths[0]) widths[0] = n; /* User */ + TRACE("user"); n = print_username(tmp, file->statbuf.st_uid); if (n > widths[1]) widths[1] = n; /* Group */ + TRACE("group"); n = print_username(tmp, file->statbuf.st_gid); if (n > widths[2]) widths[2] = n; /* File size */ + TRACE("file size"); if (human_readable) { n = print_human_readable_size(tmp, file->statbuf.st_size); } else { - n = sprintf(tmp, "%d", file->statbuf.st_size); + n = sprintf(tmp, "%d", (int)file->statbuf.st_size); } if (n > widths[3]) widths[3] = n; } @@ -208,11 +219,11 @@ static void print_entry_long(int * widths, struct tfile * file) { print_human_readable_size(tmp, file->statbuf.st_size); printf("%*s ", widths[3], tmp); } else { - printf("%*d ", widths[3], file->statbuf.st_size); + printf("%*d ", widths[3], (int)file->statbuf.st_size); } char time_buf[80]; - struct tm * timeinfo = localtime(&file->statbuf.st_mtime); + struct tm * timeinfo = localtime((time_t*)&file->statbuf.st_mtime); if (timeinfo->tm_year == this_year) { strftime(time_buf, 80, "%b %d %H:%M", timeinfo); } else { @@ -252,10 +263,12 @@ static void show_usage(int argc, char * argv[]) { static void display_tfiles(struct tfile ** ents_array, int numents) { if (long_mode) { + TRACE("long mode display, column lengths"); int widths[4] = {0,0,0,0}; for (int i = 0; i < numents; i++) { update_column_widths(widths, ents_array[i]); } + TRACE("actual printing"); for (int i = 0; i < numents; i++) { print_entry_long(widths, ents_array[i]); } @@ -263,7 +276,7 @@ static void display_tfiles(struct tfile ** ents_array, int numents) { /* Determine the gridding dimensions */ int ent_max_len = 0; for (int i = 0; i < numents; i++) { - ent_max_len = MAX(ent_max_len, strlen(ents_array[i]->name)); + ent_max_len = MAX(ent_max_len, (int)strlen(ents_array[i]->name)); } int col_ext = ent_max_len + MIN_COL_SPACING; @@ -300,6 +313,7 @@ static int display_dir(char * p) { /* Read the entries in the directory */ list_t * ents_list = list_create(); + TRACE("reading entries"); struct dirent * ent = readdir(dirp); while (ent != NULL) { if (show_hidden || (ent->d_name[0] != '.')) { @@ -307,9 +321,9 @@ static int display_dir(char * p) { f->name = strdup(ent->d_name); - char tmp[strlen(p)+strlen(ent->d_name)+1]; + char tmp[strlen(p)+strlen(ent->d_name)+2]; sprintf(tmp, "%s/%s", p, ent->d_name); - int t = lstat(tmp, &f->statbuf); + lstat(tmp, &f->statbuf); if (S_ISLNK(f->statbuf.st_mode)) { stat(tmp, &f->statbufl); f->link = malloc(4096); @@ -322,8 +336,12 @@ static int display_dir(char * p) { } closedir(dirp); + TRACE("copying"); + /* Now, copy those entries into an array (for sorting) */ + if (!ents_list->length) return 0; + struct tfile ** file_arr = malloc(sizeof(struct tfile *) * ents_list->length); int index = 0; foreach(node, ents_list) { @@ -332,8 +350,10 @@ static int display_dir(char * p) { list_free(ents_list); + TRACE("sorting"); qsort(file_arr, index, sizeof(struct tfile *), filecmp_notypesort); + TRACE("displaying"); display_tfiles(file_arr, index); free(file_arr); @@ -347,7 +367,7 @@ int main (int argc, char * argv[]) { char * p = "."; if (argc > 1) { - int index, c; + int c; while ((c = getopt(argc, argv, "ahl?")) != -1) { switch (c) { case 'a': @@ -373,6 +393,7 @@ int main (int argc, char * argv[]) { } } + stdout_is_tty = isatty(STDOUT_FILENO); if (long_mode) { @@ -384,6 +405,7 @@ int main (int argc, char * argv[]) { } if (stdout_is_tty) { + TRACE("getting display size"); struct winsize w; ioctl(1, TIOCGWINSZ, &w); term_width = w.ws_col; @@ -394,6 +416,7 @@ int main (int argc, char * argv[]) { int out = 0; if (argc == 1 || optind == argc) { + TRACE("no file to look up"); display_dir(p); } else { list_t * files = list_create(); @@ -416,6 +439,11 @@ int main (int argc, char * argv[]) { else p = argv[optind]; } + if (!files->length) { + /* No valid entries */ + return out; + } + struct tfile ** file_arr = malloc(sizeof(struct tfile *) * files->length); int index = 0; foreach(node, files) { diff --git a/apps/lspci.c b/apps/lspci.c new file mode 100644 index 00000000..3e6d5750 --- /dev/null +++ b/apps/lspci.c @@ -0,0 +1,132 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * lspci - Print information about connected PCI devices. + * + */ +#include +#include +#include +#include + +struct device_class { + char * code; + char * name; +} device_classes[] = { + {"0101", "IDE interface"}, + {"0102", "Floppy disk controller"}, + {"0105", "ATA controller"}, + {"0106", "SATA controller"}, + {"0200", "Ethernet controller"}, + {"0280", "Network controller"}, + {"0300", "VGA compatible controller"}, + {"0380", "Display controller"}, + {"0401", "Multimedia audio controller"}, + {"0403", "Audio device"}, + {"0480", "Multimedia controller"}, + {"0600", "Host bridge"}, + {"0601", "ISA bridge"}, + {"0604", "PCI bridge"}, + {"0680", "Bridge"}, + {"0880", "System peripheral"}, + {NULL, NULL}, +}; + +static void show_usage(char * argv[]) { + fprintf(stderr, + "lspci - show information about PCI devices\n" + "\n" + "usage: %s [-n]\n" + "\n" + " -n \033[3mshow numeric device codes\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); +} + +int main(int argc, char * argv[]) { + int numeric = 0; + int opt; + while ((opt = getopt(argc, argv, "n?")) != -1) { + switch (opt) { + case '?': + show_usage(argv); + return 0; + case 'n': + numeric = 1; + break; + } + } + + FILE * f = fopen("/proc/pci","r"); + if (!f) { + fprintf(stderr, "%s: %s: %s\n", argv[0], "/proc/pci", strerror(errno)); + return 1; + } + + while (!feof(f)) { + char line[1024]; + fgets(line, 1024, f); + if (line[0] == ' ') { + /* Skip; don't care about this information */ + continue; + } + /* Read bus, etc. verbatim */ + char * device_bus = line; + + /* Read device class */ + char * device_class = strstr(line," ("); + if (!device_class) { + fprintf(stderr, "%s: parse error\n", argv[0]); + return 1; + } + *device_class = '\0'; + device_class++; /* space */ + device_class++; /* ( */ + + char * device_vendor = strstr(device_class, ", "); + if (!device_vendor) { + fprintf(stderr, "%s: parse error\n", argv[0]); + return 1; + } + *device_vendor = '\0'; + device_vendor++; /* comma */ + device_vendor++; /* space */ + + char * device_code = strstr(device_vendor, ":"); + if (!device_code) { + fprintf(stderr, "%s: parse error\n", argv[0]); + return 1; + } + *device_code = '\0'; + device_code++; /* colon */ + + char * device_name = strstr(device_code, ") "); + if (!device_name) { + fprintf(stderr, "%s: parse error\n", argv[0]); + return 1; + } + *device_name = '\0'; + device_name++; /* ) */ + device_name++; /* space */ + + char * linefeed = strstr(device_name, "\n"); + if (linefeed) *linefeed = '\0'; + + if (numeric) { + fprintf(stdout, "%s %s: %s:%s\n", device_bus, device_class, device_vendor, device_code); + } else { + for (struct device_class * c = device_classes; c->code; ++c) { + if (!strcmp(device_class, c->code)) { + device_class = c->name; + break; + } + } + /* TODO: We should also look up vendor + device names ourselves and possibly remove them from the kernel */ + fprintf(stdout, "%s %s: %s\n", device_bus, device_class, device_name); + } + } + + return 0; +} diff --git a/apps/menu.c b/apps/menu.c new file mode 100644 index 00000000..739d12af --- /dev/null +++ b/apps/menu.c @@ -0,0 +1,56 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * menu - Display a menu file and print actions + * + * This is a demo of the menu library, and can be used by scripts + * to display menus. It may be broken without a root window for + * the menus to display on, though? + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static yutani_t * yctx; + +static void _action_callback(struct MenuEntry * self) { + struct MenuEntry_Normal * _self = (void *)self; + + fprintf(stdout, "%s\n", _self->action); + exit(0); +} + +int main(int argc, char * argv[]) { + + if (argc < 2) { + fprintf(stderr, "%s: expected argument\n", argv[0]); + return 1; + } + + yctx = yutani_init(); + + /* Create menu from file. */ + struct MenuSet * menu = menu_set_from_description(argv[1], _action_callback); + menu_show(menu_set_get_root(menu), yctx); + + while (1) { + yutani_msg_t * m = yutani_poll(yctx); + if (menu_process_event(yctx, m)) { + return 1; + } + free(m); + } + + return 0; +} diff --git a/apps/migrate.c b/apps/migrate.c new file mode 100644 index 00000000..8092a956 --- /dev/null +++ b/apps/migrate.c @@ -0,0 +1,240 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * migrate - Relocate root filesystem to tmpfs + * + * Run as part of system startup to move the ext2 root ramdisk + * into a flexible in-memory temporary filesystem, which allows + * file creation and editing and is much faster than the using + * the ext2 driver against the static in-memory ramdisk. + * + * Based on the original Python implementation. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#define TRACE_APP_NAME "migrate" + +#define TRACE_(...) do { if (_debug) { TRACE(__VA_ARGS__); } } while (0) + +#define CHUNK_SIZE 4096 + +static int _debug = 0; + +int tokenize(char * str, char * sep, char **buf) { + char * pch_i; + char * save_i; + int argc = 0; + pch_i = strtok_r(str,sep,&save_i); + if (!pch_i) { return 0; } + while (pch_i != NULL) { + buf[argc] = (char *)pch_i; + ++argc; + pch_i = strtok_r(NULL,sep,&save_i); + } + buf[argc] = NULL; + return argc; +} + +void copy_link(char * source, char * dest, int mode, int uid, int gid) { + //fprintf(stderr, "need to copy link %s to %s\n", source, dest); + char tmp[1024]; + readlink(source, tmp, 1024); + symlink(tmp, dest); + chmod(dest, mode); + chown(dest, uid, gid); +} + +void copy_file(char * source, char * dest, int mode,int uid, int gid) { + //fprintf(stderr, "need to copy file %s to %s %x\n", source, dest, mode); + + int d_fd = open(dest, O_WRONLY | O_CREAT, mode); + int s_fd = open(source, O_RDONLY); + + ssize_t length; + + length = lseek(s_fd, 0, SEEK_END); + lseek(s_fd, 0, SEEK_SET); + + //fprintf(stderr, "%d bytes to copy\n", length); + + char buf[CHUNK_SIZE]; + + while (length > 0) { + size_t r = read(s_fd, buf, length < CHUNK_SIZE ? length : CHUNK_SIZE); + //fprintf(stderr, "copying %d bytes from %s to %s\n", r, source, dest); + write(d_fd, buf, r); + length -= r; + //fprintf(stderr, "%d bytes remaining\n", length); + } + + close(s_fd); + close(d_fd); + + chown(dest, uid, gid); +} + +void copy_directory(char * source, char * dest, int mode, int uid, int gid) { + DIR * dirp = opendir(source); + if (dirp == NULL) { + fprintf(stderr, "Failed to copy directory %s\n", source); + return; + } + + //fprintf(stderr, "Creating %s\n", dest); + if (!strcmp(dest, "/")) { + dest = ""; + } else { + mkdir(dest, mode); + } + + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (!strcmp(ent->d_name,".") || !strcmp(ent->d_name,"..")) { + //fprintf(stderr, "Skipping %s\n", ent->d_name); + ent = readdir(dirp); + continue; + } + //fprintf(stderr, "not skipping %s/%s → %s/%s\n", source, ent->d_name, dest, ent->d_name); + struct stat statbuf; + char tmp[strlen(source)+strlen(ent->d_name)+2]; + sprintf(tmp, "%s/%s", source, ent->d_name); + char tmp2[strlen(dest)+strlen(ent->d_name)+2]; + sprintf(tmp2, "%s/%s", dest, ent->d_name); + //fprintf(stderr,"%s → %s\n", tmp, tmp2); + lstat(tmp,&statbuf); + if (S_ISLNK(statbuf.st_mode)) { + copy_link(tmp, tmp2, statbuf.st_mode & 07777, statbuf.st_uid, statbuf.st_gid); + } else if (S_ISDIR(statbuf.st_mode)) { + copy_directory(tmp, tmp2, statbuf.st_mode & 07777, statbuf.st_uid, statbuf.st_gid); + } else if (S_ISREG(statbuf.st_mode)) { + copy_file(tmp, tmp2, statbuf.st_mode & 07777, statbuf.st_uid, statbuf.st_gid); + } else { + fprintf(stderr, " %s is not any of the required file types?\n", tmp); + } + ent = readdir(dirp); + } + closedir(dirp); + + chown(dest, uid, gid); +} + +void free_ramdisk(char * path) { + int fd = open(path, O_RDONLY); + ioctl(fd, 0x4001, NULL); + close(fd); +} + +hashmap_t * get_cmdline(void) { + int fd = open("/proc/cmdline", O_RDONLY); + char * out = malloc(1024); + size_t r = read(fd, out, 1024); + out[r] = '\0'; + if (out[r-1] == '\n') { + out[r-1] = '\0'; + } + + char * arg = strdup(out); + char * argv[1024]; + int argc = tokenize(arg, " ", argv); + + /* New let's parse the tokens into the arguments list so we can index by key */ + + hashmap_t * args = hashmap_create(10); + + for (int i = 0; i < argc; ++i) { + char * c = strdup(argv[i]); + + char * name; + char * value; + + name = c; + value = NULL; + /* Find the first = and replace it with a null */ + char * v = c; + while (*v) { + if (*v == '=') { + *v = '\0'; + v++; + value = v; + goto _break; + } + v++; + } + +_break: + hashmap_set(args, name, value); + } + + free(arg); + free(out); + + return args; +} + +int main(int argc, char * argv[]) { + + hashmap_t * cmdline = get_cmdline(); + + if (hashmap_has(cmdline, "logtoserial")) { + _debug = 1; + } + + if (hashmap_has(cmdline, "root")) { + TRACE_("Original root was %s", hashmap_get(cmdline, "root")); + } else if (hashmap_has(cmdline,"init") && !strcmp(hashmap_get(cmdline,"init"),"/dev/ram0")) { + TRACE_("Init is ram0, so this is probably a netboot image, going to assume root is /tmp/netboot.img"); + hashmap_set(cmdline,"root","/tmp/netboot.img"); + } else { + TRACE_("Fatal: Don't know how to boot this. No root set.\n"); + return 1; + } + + char * root = hashmap_get(cmdline,"root"); + + char * start = hashmap_get(cmdline,"_start"); + if (!start) { + start = ""; + } + char * root_type = hashmap_get(cmdline,"root_type"); + if (!root_type) { + root_type = "ext2"; + } + + char tmp[1024]; + + TRACE_("Remounting root to /dev/base"); + sprintf(tmp, "mount %s %s /dev/base", root_type, root); + system(tmp); + + TRACE_("Mounting tmpfs to /"); + system("mount tmpfs x /"); + + TRACE_("Migrating root..."); + copy_directory("/dev/base","/",0660,0,0); + system("mount tmpfs x /dev/base"); + + if (strstr(root, "/dev/ram") != NULL) { + char * tmp = strdup(root); + char * c = strchr(tmp, ','); + if (c) { + *c = '\0'; + } + TRACE_("Freeing ramdisk at %s", tmp); + free_ramdisk(tmp); + free(tmp); + } + + return 0; +} diff --git a/userspace/extra/mixerctl.c b/apps/mixerctl.c similarity index 72% rename from userspace/extra/mixerctl.c rename to apps/mixerctl.c index a1de302f..32d6c034 100644 --- a/userspace/extra/mixerctl.c +++ b/apps/mixerctl.c @@ -10,21 +10,24 @@ #include #include -#include "lib/sound.h" +#include -static const char usage[] = +static char usage[] = +"%s - Control audio mixer settings.\n" +"\n" "Usage %s [-d device_id] -l\n" " %s [-d device_id] [-k knob_id] -r\n" " %s [-d device_id] [-k knob_id] -w knob_value\n" " %s -h\n" -" -d: Device id to address. Defaults to the main sound device.\n" -" -l: List the knobs on a device.\n" -" -k: Knob id to address. Defaults to the device's master knob.\n" -" -r: Perform a read on the given device's knob. Defaults to the device's\n" -" master knob.\n" -" -w: Perform a write on the given device's knob. The value should be a\n" -" float from 0.0 to 1.0.\n" -" -h: Print this help message and exit.\n"; +"\n" +" -d: \033[3mDevice id to address. Defaults to the main sound device.\033[0m\n" +" -l: \033[3mList the knobs on a device.\033[0m\n" +" -k: \033[3mKnob id to address. Defaults to the device's master knob.\033[0m\n" +" -r: \033[3mPerform a read on the given device's knob. Defaults to the device's\n" +" master knob.\033[0m\n" +" -w: \033[3mPerform a write on the given device's knob. The value should be a\n" +" float from 0.0 to 1.0.\033[0m\n" +" -h: \033[3mPrint this help message and exit.\033[0m\n"; int main(int argc, char * argv[]) { uint32_t device_id = SND_DEVICE_MAIN; @@ -36,16 +39,16 @@ int main(int argc, char * argv[]) { int c; - while ((c = getopt(argc, argv, "d:lk:rw:h")) != -1) { + while ((c = getopt(argc, argv, "d:lk:rw:h?")) != -1) { switch (c) { case 'd': - device_id = atol(optarg); + device_id = atoi(optarg); break; case 'l': list_flag = 1; break; case 'k': - knob_id = atol(optarg); + knob_id = atoi(optarg); break; case 'r': read_flag = 1; @@ -59,17 +62,16 @@ int main(int argc, char * argv[]) { } break; case 'h': - fprintf(stdout, usage, argv[0], argv[0], argv[0], argv[0]); - exit(EXIT_SUCCESS); + case '?': default: - fprintf(stderr, usage, argv[0], argv[0], argv[0], argv[0]); + fprintf(stderr, usage, argv[0], argv[0], argv[0], argv[0], argv[0]); exit(EXIT_FAILURE); } } int mixer = open("/dev/mixer", O_RDONLY); if (mixer < 1) { - perror("open"); + //perror("open"); exit(EXIT_FAILURE); } @@ -88,7 +90,7 @@ int main(int argc, char * argv[]) { perror("ioctl"); exit(EXIT_FAILURE); } - fprintf(stdout, "%d: %s\n", info.id, info.name); + fprintf(stdout, "%d: %s\n", (unsigned int)info.id, info.name); } exit(EXIT_SUCCESS); diff --git a/apps/mkdir.c b/apps/mkdir.c new file mode 100644 index 00000000..469f9b88 --- /dev/null +++ b/apps/mkdir.c @@ -0,0 +1,71 @@ +/* vim:tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2014 K. Lange + * + * mkdir + * + * Create a directory. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +int makedir(const char * dir, int mask, int parents) { + if (!parents) return mkdir(dir,mask); + + char * tmp = strdup(dir); + char * c = tmp; + while ((c = strchr(c+1,'/'))) { + *c = '\0'; + if (mkdir(tmp,mask) < 0) { + if (errno == EEXIST) { + *c = '/'; + continue; + } else { + return -1; + } + } + *c = '/'; + continue; + } + + return mkdir(tmp, mask); +} + +int main(int argc, char ** argv) { + int retval = 0; + int parents = 0; + int opt; + + while ((opt = getopt(argc, argv, "m:p")) != -1) { + switch (opt) { + case 'm': + fprintf(stderr, "%s: -m unsupported\n", argv[0]); + return 1; + case 'p': + parents = 1; + break; + } + } + + if (optind == argc) { + fprintf(stderr, "%s: expected argument\n", argv[0]); + return 1; + } + + for (int i = optind; i < argc; ++i) { + if (makedir(argv[i], 0777, parents) < 0) { + if (parents && errno == EEXIST) continue; + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno)); + retval = 1; + } + } + + return retval; +} diff --git a/userspace/core/mount.c b/apps/mount.c similarity index 63% rename from userspace/core/mount.c rename to apps/mount.c index 96e5625a..c1f53a8e 100644 --- a/userspace/core/mount.c +++ b/apps/mount.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * mount * @@ -9,9 +9,8 @@ */ #include - -/* Probably should go somewhere */ -extern int mount(char* src,char* tgt,char* typ,unsigned long,void*); +#include +#include int main(int argc, char ** argv) { if (argc < 4) { @@ -19,9 +18,11 @@ int main(int argc, char ** argv) { return 1; } - if (mount(argv[2], argv[3], argv[1], 0, NULL) < 0) { - perror("mount"); - return 1; + int ret = mount(argv[2], argv[3], argv[1], 0, NULL); + + if (ret < 0) { + fprintf(stderr, "%s: %s\n", argv[0], strerror(errno)); + return ret; } return 0; diff --git a/apps/mv.c b/apps/mv.c new file mode 100644 index 00000000..48286e19 --- /dev/null +++ b/apps/mv.c @@ -0,0 +1,41 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * DUMMY mv implementation that calls cp + rm + * + * TODO: Actually implement the plumbing for mv! + */ +#include +#include +#include +#include +#include + +static int call(char * args[]) { + pid_t pid = fork(); + if (!pid) { + execvp(args[0], args); + exit(1); + } else { + int status; + waitpid(pid, &status, 0); + return status; + } +} + +int main(int argc, char * argv[]) { + if (argc < 3) { + fprintf(stderr, "%s: missing operand\n", argv[0]); + return 1; + } + if (!strcmp(argv[1], argv[2])) { + fprintf(stderr, "%s: %s and %s are the same file\n", argv[0], argv[1], argv[2]); + return 1; + } + /* TODO stat magic for other ways to reference the same file */ + if (call((char *[]){"/bin/cp",argv[1],argv[2],NULL})) return 1; + if (call((char *[]){"/bin/rm",argv[1],NULL})) return 1; + return 0; +} diff --git a/userspace/net/nslookup.c b/apps/nslookup.c similarity index 71% rename from userspace/net/nslookup.c rename to apps/nslookup.c index fb95be0b..0be41285 100644 --- a/userspace/net/nslookup.c +++ b/apps/nslookup.c @@ -1,7 +1,7 @@ -/* vim: ts=4 sw=4 noexpandtab +/* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016 Kevin Lange + * Copyright (C) 2016-2018 K. Lange * * nslookup - perform nameserver lookups * @@ -11,15 +11,14 @@ #include #include #include - -#include "lib/network.h" +#include static void ip_ntoa(uint32_t src_addr, char * out) { sprintf(out, "%d.%d.%d.%d", - (src_addr & 0xFF000000) >> 24, - (src_addr & 0xFF0000) >> 16, - (src_addr & 0xFF00) >> 8, - (src_addr & 0xFF)); + (unsigned int)((src_addr & 0xFF000000) >> 24), + (unsigned int)((src_addr & 0xFF0000) >> 16), + (unsigned int)((src_addr & 0xFF00) >> 8), + (unsigned int)((src_addr & 0xFF))); } int main(int argc, char * argv[]) { diff --git a/userspace/extra/nyancat/nyancat.c b/apps/nyancat.c similarity index 96% rename from userspace/extra/nyancat/nyancat.c rename to apps/nyancat.c index dd05ed1d..9dd940c7 100644 --- a/userspace/extra/nyancat/nyancat.c +++ b/apps/nyancat.c @@ -1,8 +1,8 @@ -/* - * Copyright (c) 2011-2013 Kevin Lange. All rights reserved. +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * Copyright (c) 2011-2018 K. Lange. All rights reserved. * - * Developed by: Kevin Lange - * http://github.com/klange/nyancat + * Developed by: K. Lange + * http://gitlab.com/klange/nyancat * http://nyancat.dakko.us * * 40-column support by: Peter Hazenberg @@ -35,7 +35,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimers in the * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the Association for Computing Machinery, Kevin + * 3. Neither the names of the Association for Computing Machinery, K. * Lange, nor the names of its contributors may be used to endorse * or promote products derived from this Software without specific prior * written permission. @@ -77,13 +77,13 @@ * (it surprises some people that telnet is, really, * a protocol, and not just raw text transmission) */ -#include "telnet.h" +#include "nyancat/telnet.h" /* * The animation frames are stored separately in * this header so they don't clutter the core source */ -#include "animation.h" +#include "nyancat/animation.h" /* * Color palette to use for final output @@ -193,12 +193,14 @@ void SIGINT_handler(int sig){ * Handle the alarm which breaks us off of options * handling if we didn't receive a terminal */ +#if 0 void SIGALRM_handler(int sig) { (void)sig; alarm(0); longjmp(environment, 1); /* Unreachable */ } +#endif /* * Handle the loss of stdout, as would be the case when @@ -239,12 +241,12 @@ void newline(int n) { /* We will send `n` linefeeds to the client */ if (telnet) { /* Send the telnet newline sequence */ - putc('\r', stdout); - putc(0, stdout); - putc('\n', stdout); + fputc('\r', stdout); + fputc(0, stdout); + fputc('\n', stdout); } else { /* Send a regular line feed */ - putc('\n', stdout); + fputc('\n', stdout); } } } @@ -317,6 +319,13 @@ void send_command(int cmd, int opt) { } } +static int _tolower(int c) { + if (c >= 'A' && c <= 'Z') { + return c - 'A' + 'a'; + } + return c; +} + /* * Print the usage / help text describing options */ @@ -348,10 +357,10 @@ int main(int argc, char ** argv) { char term[1024] = {'a','n','s','i', 0}; unsigned int k; int ttype; - uint32_t option = 0, done = 0, sb_mode = 0; + //uint32_t option = 0, done = 0, sb_mode = 0; /* Various pieces for the telnet communication */ - char sb[1024] = {0}; - unsigned short sb_len = 0; + //char sb[1024] = {0}; + //unsigned short sb_len = 0; /* Whether or not to show the MOTD intro */ char show_intro = 0; @@ -435,6 +444,7 @@ int main(int argc, char ** argv) { } } + (void)skip_intro; #if 0 if (telnet) { /* Telnet mode */ @@ -577,7 +587,7 @@ int main(int argc, char ** argv) { /* Convert the entire terminal string to lower case */ for (k = 0; k < strlen(term); ++k) { - term[k] = tolower(term[k]); + term[k] = _tolower(term[k]); } /* Do our terminal detection */ @@ -599,7 +609,7 @@ int main(int argc, char ** argv) { ttype = 3; /* Accepts LINUX mode */ } else if (strstr(term, "vt100") && terminal_width == 40) { ttype = 7; /* No color support, only 40 columns */ - } else if (!strncmp(term, "st", 2)) { + } else if (strstr(term, "st") == term) { ttype = 1; /* suckless simple terminal is xterm-256color-compatible */ } else { ttype = 2; /* Everything else */ @@ -773,7 +783,7 @@ int main(int argc, char ** argv) { newline(3); printf(" \033[1mNyancat Telnet Server\033[0m"); newline(2); - printf(" written and run by \033[1;32mKevin Lange\033[1;34m @kevinlange\033[0m"); + printf(" written and run by \033[1;32mK. Lange\033[1;34m @_klange\033[0m"); newline(2); printf(" If things don't look right, try:"); newline(1); @@ -891,7 +901,8 @@ int main(int argc, char ** argv) { * The \033[0m prevents the Apple ][ from flipping everything, but * makes the whole nyancat less bright on the vt220 */ - printf("\033[1;37mYou have nyaned for %0.0f seconds!\033[J\033[0m", diff); + //printf("\033[1;37mYou have nyaned for %0.0f seconds!\033[J\033[0m", diff); + printf("\033[1;37mYou have nyaned for %d seconds!\033[J\033[0m", (int)diff); } /* Reset the last color so that the escape sequences rewrite */ last = 0; diff --git a/userspace/extra/nyancat/animation.h b/apps/nyancat/animation.h similarity index 100% rename from userspace/extra/nyancat/animation.h rename to apps/nyancat/animation.h diff --git a/userspace/extra/nyancat/telnet.h b/apps/nyancat/telnet.h similarity index 100% rename from userspace/extra/nyancat/telnet.h rename to apps/nyancat/telnet.h diff --git a/apps/panel.c b/apps/panel.c new file mode 100644 index 00000000..0383f5b8 --- /dev/null +++ b/apps/panel.c @@ -0,0 +1,1288 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * Yutani Panel + * + * Provides an applications menu, a window list, status widgets, + * and a clock, manages the user session, and provides alt-tab + * window switching and alt-f2 app runner. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PANEL_HEIGHT 28 +#define FONT_SIZE 14 +#define TIME_LEFT 108 +#define DATE_WIDTH 70 + +#define GRADIENT_HEIGHT 24 +#define APP_OFFSET 140 +#define TEXT_Y_OFFSET 2 +#define ICON_PADDING 2 +#define MAX_TEXT_WIDTH 180 +#define MIN_TEXT_WIDTH 50 + +#define HILIGHT_COLOR rgb(142,216,255) +#define FOCUS_COLOR rgb(255,255,255) +#define TEXT_COLOR rgb(230,230,230) +#define ICON_COLOR rgb(230,230,230) + +#define GRADIENT_AT(y) premultiply(rgba(72, 167, 255, ((24-(y))*160)/24)) + +#define ALTTAB_WIDTH 250 +#define ALTTAB_HEIGHT 100 +#define ALTTAB_BACKGROUND premultiply(rgba(0,0,0,150)) +#define ALTTAB_OFFSET 10 + +#define ALTF2_WIDTH 400 +#define ALTF2_HEIGHT 200 + +#define MAX_WINDOW_COUNT 100 + +#define TOTAL_CELL_WIDTH (title_width) +#define LEFT_BOUND (width - TIME_LEFT - DATE_WIDTH - ICON_PADDING - widgets_width) + +#define WIDGET_WIDTH 24 +#define WIDGET_RIGHT (width - TIME_LEFT - DATE_WIDTH) +#define WIDGET_POSITION(i) (WIDGET_RIGHT - WIDGET_WIDTH * (i+1)) + +static yutani_t * yctx; + +static gfx_context_t * ctx = NULL; +static yutani_window_t * panel = NULL; + +static gfx_context_t * actx = NULL; +static yutani_window_t * alttab = NULL; + +static gfx_context_t * a2ctx = NULL; +static yutani_window_t * alt_f2 = NULL; + +static list_t * window_list = NULL; +static volatile int lock = 0; +static volatile int drawlock = 0; + +static size_t bg_size; +static char * bg_blob; + +static int width; +static int height; + +static int widgets_width = 0; +static int widgets_volume_enabled = 0; +static int widgets_network_enabled = 0; + +static int network_status = 0; + +static sprite_t * sprite_panel; +static sprite_t * sprite_logout; + +static sprite_t * sprite_volume_mute; +static sprite_t * sprite_volume_low; +static sprite_t * sprite_volume_med; +static sprite_t * sprite_volume_high; + +static sprite_t * sprite_net_active; +static sprite_t * sprite_net_disabled; + +struct MenuList * appmenu; +struct MenuList * window_menu; +struct MenuList * logout_menu; +struct MenuList * netstat; +static yutani_wid_t _window_menu_wid = 0; + +static int _close_enough(struct yutani_msg_window_mouse_event * me) { + if (me->command == YUTANI_MOUSE_EVENT_RAISE && sqrt(pow(me->new_x - me->old_x, 2) + pow(me->new_y - me->old_y, 2)) < 10) { + return 1; + } + return 0; +} + + +static int center_x(int x) { + return (width - x) / 2; +} + +static int center_y(int y) { + return (height - y) / 2; +} + +static int center_x_a(int x) { + return (ALTTAB_WIDTH - x) / 2; +} + +static int center_x_a2(int x) { + return (ALTF2_WIDTH - x) / 2; +} + +static void redraw(void); + +static volatile int _continue = 1; + +struct window_ad { + yutani_wid_t wid; + uint32_t flags; + char * name; + char * icon; + char * strings; + int left; +}; + +typedef struct { + char * icon; + char * appname; + char * title; +} application_t; + +/* Windows, indexed by list order */ +static struct window_ad * ads_by_l[MAX_WINDOW_COUNT+1] = {NULL}; +/* Windows, indexed by z-order */ +static struct window_ad * ads_by_z[MAX_WINDOW_COUNT+1] = {NULL}; + +static int focused_app = -1; +static int active_window = -1; +static int was_tabbing = 0; +static int new_focused = -1; + +static int title_width = 0; + +static void toggle_hide_panel(void) { + static int panel_hidden = 0; + + if (panel_hidden) { + /* Unhide the panel */ + for (int i = PANEL_HEIGHT-1; i >= 0; i--) { + yutani_window_move(yctx, panel, 0, -i); + usleep(10000); + } + panel_hidden = 0; + } else { + /* Hide the panel */ + for (int i = 1; i <= PANEL_HEIGHT-1; i++) { + yutani_window_move(yctx, panel, 0, -i); + usleep(10000); + } + panel_hidden = 1; + } +} + +/* Handle SIGINT by telling other threads (clock) to shut down */ +static void sig_int(int sig) { + printf("Received shutdown signal in panel!\n"); + _continue = 0; +} + +static void launch_application(char * app) { + if (!fork()) { + printf("Starting %s\n", app); + char * args[] = {"/bin/sh", "-c", app, NULL}; + execvp(args[0], args); + exit(1); + } +} + +/* Update the hover-focus window */ +static void set_focused(int i) { + if (focused_app != i) { + focused_app = i; + redraw(); + } +} + +static void _window_menu_start_move(struct MenuEntry * self) { + if (!_window_menu_wid) + return; + yutani_focus_window(yctx, _window_menu_wid); + yutani_window_drag_start_wid(yctx, _window_menu_wid); +} + +static void _window_menu_start_maximize(struct MenuEntry * self) { + if (!_window_menu_wid) + return; + yutani_special_request_wid(yctx, _window_menu_wid, YUTANI_SPECIAL_REQUEST_MAXIMIZE); + yutani_focus_window(yctx, _window_menu_wid); +} + +static void _window_menu_close(struct MenuEntry * self) { + if (!_window_menu_wid) + return; + yutani_focus_window(yctx, _window_menu_wid); + yutani_special_request_wid(yctx, _window_menu_wid, YUTANI_SPECIAL_REQUEST_PLEASE_CLOSE); +} + +static void window_show_menu(yutani_wid_t wid, int y, int x) { + if (window_menu->window) return; + _window_menu_wid = wid; + menu_show(window_menu, yctx); + yutani_window_move(yctx, window_menu->window, y, x); +} + + +#define VOLUME_DEVICE_ID 0 +#define VOLUME_KNOB_ID 0 +static uint32_t volume_level = 0; +static int mixer = -1; +static void update_volume_level(void) { + if (mixer == -1) { + mixer = open("/dev/mixer", O_RDONLY); + } + + snd_knob_value_t value = {0}; + value.device = VOLUME_DEVICE_ID; /* TODO configure this somewhere */ + value.id = VOLUME_KNOB_ID; /* TODO this too */ + + ioctl(mixer, SND_MIXER_READ_KNOB, &value); + volume_level = value.val; +} +static void volume_raise(void) { + if (volume_level > 0xE0000000) volume_level = 0xF0000000; + else volume_level += 0x10000000; + + snd_knob_value_t value = {0}; + value.device = VOLUME_DEVICE_ID; /* TODO configure this somewhere */ + value.id = VOLUME_KNOB_ID; /* TODO this too */ + value.val = volume_level; + + ioctl(mixer, SND_MIXER_WRITE_KNOB, &value); + redraw(); +} +static void volume_lower(void) { + if (volume_level < 0x20000000) volume_level = 0x0; + else volume_level -= 0x10000000; + + snd_knob_value_t value = {0}; + value.device = VOLUME_DEVICE_ID; /* TODO configure this somewhere */ + value.id = VOLUME_KNOB_ID; /* TODO this too */ + value.val = volume_level; + + ioctl(mixer, SND_MIXER_WRITE_KNOB, &value); + redraw(); +} + +static int netstat_left = 0; + +static struct MenuEntry_Normal * netstat_ip_entry; +static char * netstat_ip = NULL; +static struct MenuEntry_Normal * netstat_device_entry; +static char * netstat_device = NULL; +static struct MenuEntry_Normal * netstat_gateway_entry; +static char * netstat_gateway = NULL; +static struct MenuEntry_Normal * netstat_dns_entry; +static char * netstat_dns = NULL; +static struct MenuEntry_Normal * netstat_mac_entry; +static char * netstat_mac = NULL; + +static void update_network_status(void) { + FILE * net = fopen("/proc/netif","r"); + + if (!net) return; + + char line[256]; + + do { + memset(line, 0, 256); + fgets(line, 256, net); + if (!*line) break; + if (strstr(line,"no network") != NULL) { + network_status = 0; + break; + } else if (strstr(line,"ip:") != NULL) { + network_status = 1; + if (netstat_ip) { + free(netstat_ip); + } + char tmp[512]; + sprintf(tmp, "IP: %s", &line[strlen("ip: ")]); + char * lf = strstr(tmp,"\n"); + if (lf) *lf = '\0'; + netstat_ip = strdup(tmp); + } else if (strstr(line,"device:") != NULL) { + network_status = 1; + if (netstat_device) { + free(netstat_device); + } + char tmp[512]; + sprintf(tmp, "Device: %s", &line[strlen("device: ")]); + char * lf = strstr(tmp,"\n"); + if (lf) *lf = '\0'; + netstat_device = strdup(tmp); + } else if (strstr(line,"gateway:") != NULL) { + network_status = 1; + if (netstat_gateway) { + free(netstat_gateway); + } + char tmp[512]; + sprintf(tmp, "Gateway: %s", &line[strlen("gateway: ")]); + char * lf = strstr(tmp,"\n"); + if (lf) *lf = '\0'; + netstat_gateway = strdup(tmp); + } else if (strstr(line,"dns:") != NULL) { + network_status = 1; + if (netstat_dns) { + free(netstat_dns); + } + char tmp[512]; + sprintf(tmp, "Primary DNS: %s", &line[strlen("dns: ")]); + char * lf = strstr(tmp,"\n"); + if (lf) *lf = '\0'; + netstat_dns = strdup(tmp); + } else if (strstr(line,"mac:") != NULL) { + network_status = 1; + if (netstat_mac) { + free(netstat_mac); + } + char tmp[512]; + sprintf(tmp, "MAC: %s", &line[strlen("mac: ")]); + char * lf = strstr(tmp,"\n"); + if (lf) *lf = '\0'; + netstat_mac = strdup(tmp); + } + } while (1); + + fclose(net); +} + +static void show_logout_menu(void) { + if (!logout_menu->window) { + menu_show(logout_menu, yctx); + if (logout_menu->window) { + yutani_window_move(yctx, logout_menu->window, width - logout_menu->window->width, PANEL_HEIGHT); + } + } +} + +static void show_app_menu(void) { + if (!appmenu->window) { + menu_show(appmenu, yctx); + if (appmenu->window) { + yutani_window_move(yctx, appmenu->window, 0, PANEL_HEIGHT); + } + } +} + +static void show_network_status(void) { + if (!netstat) { + netstat = menu_create(); + menu_insert(netstat, menu_create_normal(NULL, NULL, "Network Status", NULL)); + menu_insert(netstat, menu_create_separator()); + netstat_ip_entry = (struct MenuEntry_Normal *)menu_create_normal(NULL, NULL, "", NULL); + menu_insert(netstat, netstat_ip_entry); + netstat_dns_entry = (struct MenuEntry_Normal *)menu_create_normal(NULL, NULL, "", NULL); + menu_insert(netstat, netstat_dns_entry); + netstat_gateway_entry = (struct MenuEntry_Normal *)menu_create_normal(NULL, NULL, "", NULL); + menu_insert(netstat, netstat_gateway_entry); + netstat_mac_entry = (struct MenuEntry_Normal *)menu_create_normal(NULL, NULL, "", NULL); + menu_insert(netstat, netstat_mac_entry); + netstat_device_entry = (struct MenuEntry_Normal *)menu_create_normal(NULL, NULL, "", NULL); + menu_insert(netstat, netstat_device_entry); + } + if (network_status) { + menu_update_title(netstat_ip_entry, netstat_ip); + menu_update_title(netstat_device_entry, netstat_device ? netstat_device : "(?)"); + menu_update_title(netstat_dns_entry, netstat_dns ? netstat_dns : "(?)"); + menu_update_title(netstat_gateway_entry, netstat_gateway ? netstat_gateway : "(?)"); + menu_update_title(netstat_mac_entry, netstat_mac ? netstat_mac : "(?)"); + } else { + menu_update_title(netstat_ip_entry, "No network."); + menu_update_title(netstat_device_entry, ""); + menu_update_title(netstat_dns_entry, ""); + menu_update_title(netstat_gateway_entry, ""); + menu_update_title(netstat_mac_entry, ""); + } + if (!netstat->window) { + menu_show(netstat, yctx); + if (netstat->window) { + if (netstat_left + netstat->window->width > (unsigned int)width) { + yutani_window_move(yctx, netstat->window, width - netstat->window->width, PANEL_HEIGHT); + } else { + yutani_window_move(yctx, netstat->window, netstat_left, PANEL_HEIGHT); + } + } + } +} + +/* Callback for mouse events */ +static void panel_check_click(struct yutani_msg_window_mouse_event * evt) { + if (evt->wid == panel->wid) { + if (evt->command == YUTANI_MOUSE_EVENT_CLICK || _close_enough(evt)) { + /* Up-down click */ + if (evt->new_x >= width - 24 ) { + show_logout_menu(); + } else if (evt->new_x < APP_OFFSET) { + show_app_menu(); + } else if (evt->new_x >= APP_OFFSET && evt->new_x < LEFT_BOUND) { + for (int i = 0; i < MAX_WINDOW_COUNT; ++i) { + if (ads_by_l[i] == NULL) break; + if (evt->new_x >= ads_by_l[i]->left && evt->new_x < ads_by_l[i]->left + TOTAL_CELL_WIDTH) { + yutani_focus_window(yctx, ads_by_l[i]->wid); + break; + } + } + } + int widget = 0; + if (widgets_network_enabled) { + if (evt->new_x > WIDGET_POSITION(widget) && evt->new_x < WIDGET_POSITION(widget-1)) { + netstat_left = WIDGET_POSITION(widget); + show_network_status(); + } + widget++; + } + if (widgets_volume_enabled) { + if (evt->new_x > WIDGET_POSITION(widget) && evt->new_x < WIDGET_POSITION(widget-1)) { + /* TODO: Show the volume manager */ + } + widget++; + } + } else if (evt->buttons & YUTANI_MOUSE_BUTTON_RIGHT) { + if (evt->new_x >= APP_OFFSET && evt->new_x < LEFT_BOUND) { + for (int i = 0; i < MAX_WINDOW_COUNT; ++i) { + if (ads_by_l[i] == NULL) break; + if (evt->new_x >= ads_by_l[i]->left && evt->new_x < ads_by_l[i]->left + TOTAL_CELL_WIDTH) { + window_show_menu(ads_by_l[i]->wid, evt->new_x, PANEL_HEIGHT); + } + } + } + } else if (evt->command == YUTANI_MOUSE_EVENT_MOVE || evt->command == YUTANI_MOUSE_EVENT_ENTER) { + /* Movement, or mouse entered window */ + if (evt->new_y < PANEL_HEIGHT) { + for (int i = 0; i < MAX_WINDOW_COUNT; ++i) { + if (ads_by_l[i] == NULL) { + set_focused(-1); + break; + } + if (evt->new_x >= ads_by_l[i]->left && evt->new_x < ads_by_l[i]->left + TOTAL_CELL_WIDTH) { + set_focused(i); + break; + } + } + } else { + set_focused(-1); + } + + int scroll_direction = 0; + if (evt->buttons & YUTANI_MOUSE_SCROLL_UP) scroll_direction = -1; + else if (evt->buttons & YUTANI_MOUSE_SCROLL_DOWN) scroll_direction = 1; + + if (scroll_direction) { + int widget = 0; + if (widgets_network_enabled) { + if (evt->new_x > WIDGET_POSITION(widget) && evt->new_x < WIDGET_POSITION(widget-1)) { + /* Ignore */ + } + widget++; + } + if (widgets_volume_enabled) { + if (evt->new_x > WIDGET_POSITION(widget) && evt->new_x < WIDGET_POSITION(widget-1)) { + if (scroll_direction == 1) { + volume_lower(); + } else if (scroll_direction == -1) { + volume_raise(); + } + } + widget++; + } + if (evt->new_x >= APP_OFFSET && evt->new_x < LEFT_BOUND) { + if (scroll_direction != 0) { + struct window_ad * last = window_list->tail ? window_list->tail->value : NULL; + int focus_next = 0; + foreach(node, window_list) { + struct window_ad * ad = node->value; + if (focus_next) { + yutani_focus_window(yctx, ad->wid); + return; + } + if (ad->flags & 1) { + if (scroll_direction == -1) { + yutani_focus_window(yctx, last->wid); + return; + } + if (scroll_direction == 1) { + focus_next = 1; + } + } + last = ad; + } + if (focus_next && window_list->head) { + struct window_ad * ad = window_list->head->value; + yutani_focus_window(yctx, ad->wid); + return; + } + } + } + } + } else if (evt->command == YUTANI_MOUSE_EVENT_LEAVE) { + /* Mouse left panel window */ + set_focused(-1); + } + } +} + +static char altf2_buffer[1024] = {0}; +static unsigned int altf2_collected = 0; + +#if 0 +static list_t * altf2_apps = NULL; + +struct altf2_app { + char * name; + sprite_t * icon; +}; + +static sprite_t * find_icon(char * name) { + struct { + char * name; + char * icon; + } special[] = { + {"about", "star"}, + {"help-browser", "help"}, + {"terminal", "utilities-terminal"}, + {NULL,NULL}, + }; + + int i = 0; + while (special[i].name) { + if (!strcmp(special[i].name, name)) { + return icon_get_48(special[i].icon); + } + i++; + } + + return icon_get_48(name); +} +#endif + +static void close_altf2(void) { + free(a2ctx->backbuffer); + free(a2ctx); + + altf2_buffer[0] = 0; + altf2_collected = 0; + + yutani_close(yctx, alt_f2); + alt_f2 = NULL; +} + +static void redraw_altf2(void) { + +#if 0 + if (!altf2_apps) { + /* initialize */ + + } +#endif + + draw_fill(a2ctx, 0); + draw_rounded_rectangle(a2ctx,0,0, ALTF2_WIDTH, ALTF2_HEIGHT, 10, ALTTAB_BACKGROUND); + + int t = draw_sdf_string_width(altf2_buffer, 22, SDF_FONT_THIN); + draw_sdf_string(a2ctx, center_x_a2(t), 60, altf2_buffer, 22, rgb(255,255,255), SDF_FONT_THIN); + + flip(a2ctx); + yutani_flip(yctx, alt_f2); +} + +static void redraw_alttab(void) { + /* Draw the background, right now just a dark semi-transparent box */ + draw_fill(actx, 0); + draw_rounded_rectangle(actx,0,0, ALTTAB_WIDTH, ALTTAB_HEIGHT, 10, ALTTAB_BACKGROUND); + + if (ads_by_z[new_focused]) { + struct window_ad * ad = ads_by_z[new_focused]; + + sprite_t * icon = icon_get_48(ad->icon); + + /* Draw it, scaled if necessary */ + if (icon->width == 48) { + draw_sprite(actx, icon, center_x_a(48), ALTTAB_OFFSET); + } else { + draw_sprite_scaled(actx, icon, center_x_a(48), ALTTAB_OFFSET, 48, 48); + } + + int t = draw_sdf_string_width(ad->name, 18, SDF_FONT_THIN); + + draw_sdf_string(actx, center_x_a(t), 12+ALTTAB_OFFSET+40, ad->name, 18, rgb(255,255,255), SDF_FONT_THIN); + } + + flip(actx); + yutani_flip(yctx, alttab); +} + +static void launch_application_menu(struct MenuEntry * self) { + struct MenuEntry_Normal * _self = (void *)self; + + if (!strcmp((char *)_self->action,"log-out")) { + yutani_session_end(yctx); + _continue = 0; + } else { + launch_application((char *)_self->action); + } +} + +static void handle_key_event(struct yutani_msg_key_event * ke) { + if (alt_f2 && ke->wid == alt_f2->wid) { + if (ke->event.action == KEY_ACTION_DOWN) { + if (ke->event.keycode == KEY_ESCAPE) { + close_altf2(); + return; + } + if (ke->event.key == '\b') { + if (altf2_collected) { + altf2_buffer[altf2_collected-1] = '\0'; + altf2_collected--; + redraw_altf2(); + } + return; + } + if (ke->event.key == '\n') { + /* execute */ + launch_application(altf2_buffer); + close_altf2(); + return; + } + if (!ke->event.key) { + return; + } + + /* Try to add it */ + if (altf2_collected < sizeof(altf2_buffer) - 1) { + altf2_buffer[altf2_collected] = ke->event.key; + altf2_collected++; + altf2_buffer[altf2_collected] = 0; + redraw_altf2(); + } + } + } + + if ((ke->event.modifiers & KEY_MOD_LEFT_CTRL) && + (ke->event.modifiers & KEY_MOD_LEFT_ALT) && + (ke->event.keycode == 't') && + (ke->event.action == KEY_ACTION_DOWN)) { + + launch_application("exec terminal"); + return; + } + + if ((ke->event.modifiers & KEY_MOD_LEFT_CTRL) && + (ke->event.keycode == KEY_F11) && + (ke->event.action == KEY_ACTION_DOWN)) { + + fprintf(stderr, "[panel] Toggling visibility.\n"); + toggle_hide_panel(); + return; + } + + if ((ke->event.modifiers & KEY_MOD_LEFT_ALT) && + (ke->event.keycode == KEY_F1) && + (ke->event.action == KEY_ACTION_DOWN)) { + /* show menu */ + show_app_menu(); + } + + if ((ke->event.modifiers & KEY_MOD_LEFT_ALT) && + (ke->event.keycode == KEY_F2) && + (ke->event.action == KEY_ACTION_DOWN)) { + /* show menu */ + if (!alt_f2) { + alt_f2 = yutani_window_create(yctx, ALTF2_WIDTH, ALTF2_HEIGHT); + yutani_window_move(yctx, alt_f2, center_x(ALTF2_WIDTH), center_y(ALTF2_HEIGHT)); + a2ctx = init_graphics_yutani_double_buffer(alt_f2); + redraw_altf2(); + } + } + + if ((was_tabbing) && (ke->event.keycode == 0 || ke->event.keycode == KEY_LEFT_ALT) && + (ke->event.modifiers == 0) && (ke->event.action == KEY_ACTION_UP)) { + + fprintf(stderr, "[panel] Stopping focus new_focused = %d\n", new_focused); + + struct window_ad * ad = ads_by_z[new_focused]; + + if (!ad) return; + + yutani_focus_window(yctx, ad->wid); + was_tabbing = 0; + new_focused = -1; + + free(actx->backbuffer); + free(actx); + + yutani_close(yctx, alttab); + + return; + } + + if ((ke->event.modifiers & KEY_MOD_LEFT_ALT) && + (ke->event.keycode == '\t') && + (ke->event.action == KEY_ACTION_DOWN)) { + + int direction = (ke->event.modifiers & KEY_MOD_LEFT_SHIFT) ? 1 : -1; + + if (window_list->length < 1) return; + + if (was_tabbing) { + new_focused = new_focused + direction; + } else { + new_focused = active_window + direction; + /* Create tab window */ + alttab = yutani_window_create(yctx, ALTTAB_WIDTH, ALTTAB_HEIGHT); + + /* Center window */ + yutani_window_move(yctx, alttab, center_x(ALTTAB_WIDTH), center_y(ALTTAB_HEIGHT)); + + /* Initialize graphics context against the window */ + actx = init_graphics_yutani_double_buffer(alttab); + } + + if (new_focused < 0) { + new_focused = 0; + for (int i = 0; i < MAX_WINDOW_COUNT; i++) { + if (ads_by_z[i+1] == NULL) { + new_focused = i; + break; + } + } + } else if (ads_by_z[new_focused] == NULL) { + new_focused = 0; + } + + was_tabbing = 1; + + redraw_alttab(); + } + +} + +static void redraw(void) { + spin_lock(&drawlock); + + struct timeval now; + struct tm * timeinfo; + char buffer[80]; + + uint32_t txt_color = TEXT_COLOR; + int t = 0; + + /* Redraw the background */ + memcpy(ctx->backbuffer, bg_blob, bg_size); + + /* Get the current time for the clock */ + gettimeofday(&now, NULL); + timeinfo = localtime((time_t *)&now.tv_sec); + + /* Hours : Minutes : Seconds */ + strftime(buffer, 80, "%H:%M:%S", timeinfo); + draw_sdf_string(ctx, width - TIME_LEFT, 3, buffer, 20, txt_color, SDF_FONT_THIN); + + /* Day-of-week */ + strftime(buffer, 80, "%A", timeinfo); + t = draw_sdf_string_width(buffer, 12, SDF_FONT_THIN); + t = (DATE_WIDTH - t) / 2; + draw_sdf_string(ctx, width - TIME_LEFT - DATE_WIDTH + t, 2, buffer, 12, txt_color, SDF_FONT_THIN); + + /* Month Day */ + strftime(buffer, 80, "%h %e", timeinfo); + t = draw_sdf_string_width(buffer, 12, SDF_FONT_BOLD); + t = (DATE_WIDTH - t) / 2; + draw_sdf_string(ctx, width - TIME_LEFT - DATE_WIDTH + t, 12, buffer, 12, txt_color, SDF_FONT_BOLD); + + /* Applications menu */ + draw_sdf_string(ctx, 8, 3, "Applications", 20, appmenu->window ? HILIGHT_COLOR : txt_color, SDF_FONT_THIN); + + /* Draw each widget */ + /* - Volume */ + int widget = 0; + if (widgets_network_enabled) { + uint32_t color = (netstat && netstat->window) ? HILIGHT_COLOR : ICON_COLOR; + if (network_status == 1) { + draw_sprite_alpha_paint(ctx, sprite_net_active, WIDGET_POSITION(widget), 0, 1.0, color); + } else { + draw_sprite_alpha_paint(ctx, sprite_net_disabled, WIDGET_POSITION(widget), 0, 1.0, color); + } + widget++; + } + if (widgets_volume_enabled) { + if (volume_level < 10) { + draw_sprite_alpha_paint(ctx, sprite_volume_mute, WIDGET_POSITION(widget), 0, 1.0, ICON_COLOR); + } else if (volume_level < 0x547ae147) { + draw_sprite_alpha_paint(ctx, sprite_volume_low, WIDGET_POSITION(widget), 0, 1.0, ICON_COLOR); + } else if (volume_level < 0xa8f5c28e) { + draw_sprite_alpha_paint(ctx, sprite_volume_med, WIDGET_POSITION(widget), 0, 1.0, ICON_COLOR); + } else { + draw_sprite_alpha_paint(ctx, sprite_volume_high, WIDGET_POSITION(widget), 0, 1.0, ICON_COLOR); + } + widget++; + } + + /* Now draw the window list */ + int i = 0, j = 0; + spin_lock(&lock); + if (window_list) { + foreach(node, window_list) { + struct window_ad * ad = node->value; + char * s = ""; + char tmp_title[50]; + int w = 0; + + if (APP_OFFSET + i + w > LEFT_BOUND) { + break; + } + + if (title_width > MIN_TEXT_WIDTH) { + + memset(tmp_title, 0x0, 50); + int t_l = strlen(ad->name); + if (t_l > 45) { + t_l = 45; + } + for (int i = 0; i < t_l; ++i) { + tmp_title[i] = ad->name[i]; + if (!ad->name[i]) break; + } + + while (draw_sdf_string_width(tmp_title, 16, SDF_FONT_THIN) > title_width - ICON_PADDING) { + t_l--; + tmp_title[t_l] = '.'; + tmp_title[t_l+1] = '.'; + tmp_title[t_l+2] = '.'; + tmp_title[t_l+3] = '\0'; + } + w += title_width; + + s = tmp_title; + } + + /* Hilight the focused window */ + if (ad->flags & 1) { + /* This is the focused window */ + for (int y = 0; y < GRADIENT_HEIGHT; ++y) { + for (int x = APP_OFFSET + i; x < APP_OFFSET + i + w; ++x) { + GFX(ctx, x, y) = alpha_blend_rgba(GFX(ctx, x, y), GRADIENT_AT(y)); + } + } + } + + /* Get the icon for this window */ + sprite_t * icon = icon_get_48(ad->icon); + + { + sprite_t * _tmp_s = create_sprite(48, PANEL_HEIGHT-2, ALPHA_EMBEDDED); + gfx_context_t * _tmp = init_graphics_sprite(_tmp_s); + + draw_fill(_tmp, rgba(0,0,0,0)); + /* Draw it, scaled if necessary */ + if (icon->width == 48) { + draw_sprite(_tmp, icon, 0, 0); + } else { + draw_sprite_scaled(_tmp, icon, 0, 0, 48, 48); + } + + free(_tmp); + draw_sprite_alpha(ctx, _tmp_s, APP_OFFSET + i + w - 48 - 2, 0, 0.7); + sprite_free(_tmp_s); + } + + + { + sprite_t * _tmp_s = create_sprite(w, PANEL_HEIGHT, ALPHA_EMBEDDED); + gfx_context_t * _tmp = init_graphics_sprite(_tmp_s); + + draw_fill(_tmp, rgba(0,0,0,0)); + draw_sdf_string(_tmp, 0, 0, s, 16, rgb(0,0,0), SDF_FONT_THIN); + blur_context_box(_tmp, 4); + + free(_tmp); + draw_sprite(ctx, _tmp_s, APP_OFFSET + i + 2, TEXT_Y_OFFSET + 2); + sprite_free(_tmp_s); + + } + + if (title_width > MIN_TEXT_WIDTH) { + /* Then draw the window title, with appropriate color */ + if (j == focused_app) { + /* Current hilighted - title should be a light blue */ + draw_sdf_string(ctx, APP_OFFSET + i + 2, TEXT_Y_OFFSET + 2, s, 16, HILIGHT_COLOR, SDF_FONT_THIN); + } else { + if (ad->flags & 1) { + /* Top window should be white */ + draw_sdf_string(ctx, APP_OFFSET + i + 2, TEXT_Y_OFFSET + 2, s, 16, FOCUS_COLOR, SDF_FONT_THIN); + } else { + /* Otherwise, off white */ + draw_sdf_string(ctx, APP_OFFSET + i + 2, TEXT_Y_OFFSET + 2, s, 16, txt_color, SDF_FONT_THIN); + } + } + } + + /* XXX This keeps track of how far left each window list item is + * so we can map clicks up in the mouse callback. */ + if (j < MAX_WINDOW_COUNT) { + if (ads_by_l[j]) { + ads_by_l[j]->left = APP_OFFSET + i; + } + } + j++; + i += w; + } + } + spin_unlock(&lock); + + /* Draw the logout button; XXX This should probably have some sort of focus hilight */ + draw_sprite_alpha_paint(ctx, sprite_logout, width - 23, 1, 1.0, (logout_menu->window ? HILIGHT_COLOR : ICON_COLOR)); /* Logout button */ + + /* Flip */ + flip(ctx); + yutani_flip(yctx, panel); + + spin_unlock(&drawlock); +} + +static void update_window_list(void) { + yutani_query_windows(yctx); + + list_t * new_window_list = list_create(); + + int i = 0; + while (1) { + /* We wait for a series of WINDOW_ADVERTISE messsages */ + yutani_msg_t * m = yutani_wait_for(yctx, YUTANI_MSG_WINDOW_ADVERTISE); + struct yutani_msg_window_advertise * wa = (void*)m->data; + + if (wa->size == 0) { + /* A sentinal at the end will have a size of 0 */ + free(m); + break; + } + + /* Store each window advertisement */ + struct window_ad * ad = malloc(sizeof(struct window_ad)); + + char * s = malloc(wa->size); + memcpy(s, wa->strings, wa->size); + ad->name = &s[wa->offsets[0]]; + ad->icon = &s[wa->offsets[1]]; + ad->strings = s; + ad->flags = wa->flags; + ad->wid = wa->wid; + + ads_by_z[i] = ad; + i++; + ads_by_z[i] = NULL; + + node_t * next = NULL; + + /* And insert it, ordered by wid, into the window list */ + foreach(node, new_window_list) { + struct window_ad * n = node->value; + + if (n->wid > ad->wid) { + next = node; + break; + } + } + + if (next) { + list_insert_before(new_window_list, next, ad); + } else { + list_insert(new_window_list, ad); + } + free(m); + } + active_window = i-1; + + i = 0; + /* + * Update each of the wid entries in our array so we can map + * clicks to window focus events for each window + */ + foreach(node, new_window_list) { + struct window_ad * ad = node->value; + if (i < MAX_WINDOW_COUNT) { + ads_by_l[i] = ad; + ads_by_l[i+1] = NULL; + } + i++; + } + + /* Then free up the old list and replace it with the new list */ + spin_lock(&lock); + + if (new_window_list->length) { + int tmp = LEFT_BOUND; + tmp -= APP_OFFSET; + if (tmp < 0) { + title_width = 0; + } else { + title_width = tmp / new_window_list->length; + if (title_width > MAX_TEXT_WIDTH) { + title_width = MAX_TEXT_WIDTH; + } + if (title_width < MIN_TEXT_WIDTH) { + title_width = 0; + } + } + } else { + title_width = 0; + } + if (window_list) { + foreach(node, window_list) { + struct window_ad * ad = (void*)node->value; + free(ad->strings); + free(ad); + } + list_free(window_list); + free(window_list); + } + window_list = new_window_list; + spin_unlock(&lock); + + /* And redraw the panel */ + redraw(); +} + +static void resize_finish(int xwidth, int xheight) { + yutani_window_resize_accept(yctx, panel, xwidth, xheight); + + reinit_graphics_yutani(ctx, panel); + yutani_window_resize_done(yctx, panel); + + width = xwidth; + + /* Draw the background */ + draw_fill(ctx, rgba(0,0,0,0)); + for (int i = 0; i < xwidth; i += sprite_panel->width) { + draw_sprite(ctx, sprite_panel, i, 0); + } + + /* Copy the prerendered background so we can redraw it quickly */ + bg_size = panel->width * panel->height * sizeof(uint32_t); + bg_blob = realloc(bg_blob, bg_size); + memcpy(bg_blob, ctx->backbuffer, bg_size); + + update_window_list(); + redraw(); +} + +static void bind_keys(void) { + + /* Cltr-Alt-T = launch terminal */ + yutani_key_bind(yctx, 't', KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT, YUTANI_BIND_STEAL); + + /* Alt+Tab = app switcher*/ + yutani_key_bind(yctx, '\t', KEY_MOD_LEFT_ALT, YUTANI_BIND_STEAL); + yutani_key_bind(yctx, '\t', KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT, YUTANI_BIND_STEAL); + + /* Ctrl-F11 = toggle panel visibility */ + yutani_key_bind(yctx, KEY_F11, KEY_MOD_LEFT_CTRL, YUTANI_BIND_STEAL); + + /* Alt+F1 = show menu */ + yutani_key_bind(yctx, KEY_F1, KEY_MOD_LEFT_ALT, YUTANI_BIND_STEAL); + + /* Alt+F2 = show app runner */ + yutani_key_bind(yctx, KEY_F2, KEY_MOD_LEFT_ALT, YUTANI_BIND_STEAL); + + /* This lets us receive all just-modifier key releases */ + yutani_key_bind(yctx, KEY_LEFT_ALT, 0, YUTANI_BIND_PASSTHROUGH); + +} + +static void sig_usr2(int sig) { + yutani_set_stack(yctx, panel, YUTANI_ZORDER_TOP); + yutani_flip(yctx, panel); + bind_keys(); +} + +int main (int argc, char ** argv) { + if (argc < 2 || strcmp(argv[1],"--really")) { + fprintf(stderr, + "%s: Desktop environment panel / dock\n" + "\n" + " Renders the application menu, window list, widgets,\n" + " alt-tab window switcher, clock, etc.\n" + " You probably don't want to run this directly - it is\n" + " started automatically by the session manager.\n", argv[0]); + return 1; + } + + /* Connect to window server */ + yctx = yutani_init(); + + /* For convenience, store the display size */ + width = yctx->display_width; + height = yctx->display_height; + + /* Create the panel window */ + panel = yutani_window_create_flags(yctx, width, PANEL_HEIGHT, YUTANI_WINDOW_FLAG_NO_STEAL_FOCUS); + + /* And move it to the top layer */ + yutani_set_stack(yctx, panel, YUTANI_ZORDER_TOP); + + /* Initialize graphics context against the window */ + ctx = init_graphics_yutani_double_buffer(panel); + + /* Clear it out (the compositor should initialize it cleared anyway */ + draw_fill(ctx, rgba(0,0,0,0)); + flip(ctx); + yutani_flip(yctx, panel); + + /* Load textures for the background and logout button */ + sprite_panel = malloc(sizeof(sprite_t)); + sprite_logout = malloc(sizeof(sprite_t)); + + load_sprite(sprite_panel, "/usr/share/panel.bmp"); + sprite_panel->alpha = ALPHA_EMBEDDED; + load_sprite(sprite_logout, "/usr/share/icons/panel-shutdown.bmp"); + sprite_logout->alpha = ALPHA_FORCE_SLOW_EMBEDDED; + + struct stat stat_tmp; + if (!stat("/dev/dsp",&stat_tmp)) { + widgets_volume_enabled = 1; + widgets_width += WIDGET_WIDTH; + sprite_volume_mute = malloc(sizeof(sprite_t)); + sprite_volume_low = malloc(sizeof(sprite_t)); + sprite_volume_med = malloc(sizeof(sprite_t)); + sprite_volume_high = malloc(sizeof(sprite_t)); + load_sprite(sprite_volume_mute, "/usr/share/icons/24/volume-mute.bmp"); + sprite_volume_mute->alpha = ALPHA_FORCE_SLOW_EMBEDDED; + load_sprite(sprite_volume_low, "/usr/share/icons/24/volume-low.bmp"); + sprite_volume_low->alpha = ALPHA_FORCE_SLOW_EMBEDDED; + load_sprite(sprite_volume_med, "/usr/share/icons/24/volume-medium.bmp"); + sprite_volume_med->alpha = ALPHA_FORCE_SLOW_EMBEDDED; + load_sprite(sprite_volume_high, "/usr/share/icons/24/volume-full.bmp"); + sprite_volume_high->alpha = ALPHA_FORCE_SLOW_EMBEDDED; + /* XXX store current volume */ + } + + { + widgets_network_enabled = 1; + widgets_width += WIDGET_WIDTH; + sprite_net_active = malloc(sizeof(sprite_t)); + load_sprite(sprite_net_active, "/usr/share/icons/24/net-active.bmp"); + sprite_net_active->alpha = ALPHA_FORCE_SLOW_EMBEDDED; + sprite_net_disabled = malloc(sizeof(sprite_t)); + load_sprite(sprite_net_disabled, "/usr/share/icons/24/net-disconnected.bmp"); + sprite_net_disabled->alpha = ALPHA_FORCE_SLOW_EMBEDDED; + } + + /* Draw the background */ + for (int i = 0; i < width; i += sprite_panel->width) { + draw_sprite(ctx, sprite_panel, i, 0); + } + + /* Copy the prerendered background so we can redraw it quickly */ + bg_size = panel->width * panel->height * sizeof(uint32_t); + bg_blob = malloc(bg_size); + memcpy(bg_blob, ctx->backbuffer, bg_size); + + /* Catch SIGINT */ + signal(SIGINT, sig_int); + signal(SIGUSR2, sig_usr2); + + appmenu = menu_set_get_root(menu_set_from_description("/usr/share/demo.menu", launch_application_menu)); + + window_menu = menu_create(); + menu_insert(window_menu, menu_create_normal(NULL, NULL, "Maximize", _window_menu_start_maximize)); + menu_insert(window_menu, menu_create_normal(NULL, NULL, "Move", _window_menu_start_move)); + menu_insert(window_menu, menu_create_separator()); + menu_insert(window_menu, menu_create_normal(NULL, NULL, "Close", _window_menu_close)); + + logout_menu = menu_create(); + menu_insert(logout_menu, menu_create_normal("exit", "log-out", "Log Out", launch_application_menu)); + + /* Subscribe to window updates */ + yutani_subscribe_windows(yctx); + + /* Ask compositor for window list */ + update_window_list(); + + /* Key bindings */ + bind_keys(); + + time_t last_tick = 0; + + int fds[1] = {fileno(yctx->sock)}; + + while (_continue) { + + int index = fswait2(1,fds,200); + + if (index == 0) { + /* Respond to Yutani events */ + yutani_msg_t * m = yutani_poll(yctx); + while (m) { + menu_process_event(yctx, m); + switch (m->type) { + /* New window information is available */ + case YUTANI_MSG_NOTIFY: + update_window_list(); + break; + /* Mouse movement / click */ + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + panel_check_click((struct yutani_msg_window_mouse_event *)m->data); + break; + case YUTANI_MSG_KEY_EVENT: + handle_key_event((struct yutani_msg_key_event *)m->data); + break; + case YUTANI_MSG_WELCOME: + { + struct yutani_msg_welcome * mw = (void*)m->data; + width = mw->display_width; + height = mw->display_height; + yutani_window_resize(yctx, panel, mw->display_width, PANEL_HEIGHT); + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + resize_finish(wr->width, wr->height); + } + break; + default: + break; + } + free(m); + m = yutani_poll_async(yctx); + } + } else { + struct timeval now; + gettimeofday(&now, NULL); + if (now.tv_sec != last_tick) { + last_tick = now.tv_sec; + waitpid(-1, NULL, WNOHANG); + update_volume_level(); + update_network_status(); + redraw(); + } + } + } + + /* Close the panel window */ + yutani_close(yctx, panel); + + /* Stop notifying us of window changes */ + yutani_unsubscribe_windows(yctx); + + return 0; +} + diff --git a/userspace/extra/piano.c b/apps/piano.c similarity index 85% rename from userspace/extra/piano.c rename to apps/piano.c index 9ff7cfaa..291c22ae 100644 --- a/userspace/extra/piano.c +++ b/apps/piano.c @@ -1,6 +1,9 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange + * + * piano - Interactively make beeping noises */ #include #include @@ -45,8 +48,9 @@ int main(int argc, char * argv[]) { set_unbuffered(); char c; - while (c = fgetc(stdin)) { + while ((c = fgetc(stdin))) { switch (c) { + case 'q': return 0; case 'z': return 0; case 'a': note(10, 1308); break; case 'w': note(10, 1386); break; diff --git a/apps/pidof.c b/apps/pidof.c new file mode 100644 index 00000000..497e63d8 --- /dev/null +++ b/apps/pidof.c @@ -0,0 +1,120 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * pidof - Find and print process IDs + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct process { + int pid; + int ppid; + int tgid; + char name[100]; + char path[200]; +} p_t; + +#define LINE_LEN 4096 + +p_t * build_entry(struct dirent * dent) { + char tmp[256]; + FILE * f; + char line[LINE_LEN]; + + sprintf(tmp, "/proc/%s/status", dent->d_name); + f = fopen(tmp, "r"); + + p_t * proc = malloc(sizeof(p_t)); + + while (fgets(line, LINE_LEN, f) != NULL) { + char * n = strstr(line,"\n"); + if (n) { *n = '\0'; } + char * tab = strstr(line,"\t"); + if (tab) { + *tab = '\0'; + tab++; + } + if (strstr(line, "Pid:") == line) { + proc->pid = atoi(tab); + } else if (strstr(line, "PPid:") == line) { + proc->ppid = atoi(tab); + } else if (strstr(line, "Tgid:") == line) { + proc->tgid = atoi(tab); + } else if (strstr(line, "Name:") == line) { + strcpy(proc->name, tab); + } else if (strstr(line, "Path:") == line) { + strcpy(proc->path, tab); + } + } + + if (strstr(proc->name,"python") == proc->name) { + char * name = proc->path + strlen(proc->path) - 1; + + while (1) { + if (*name == '/') { + name++; + break; + } + if (name == proc->name) break; + name--; + } + + memcpy(proc->name, name, strlen(name)+1); + } + + if (proc->tgid != proc->pid) { + char tmp[100] = {0}; + sprintf(tmp, "{%s}", proc->name); + memcpy(proc->name, tmp, strlen(tmp)+1); + } + + fclose(f); + + return proc; +} + +int main (int argc, char * argv[]) { + + if (argc < 2) return 1; + + int space = 0; + + /* Open the directory */ + DIR * dirp = opendir("/proc"); + + int found_something = 0; + + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') { + p_t * proc = build_entry(ent); + + if (!strcmp(proc->name, argv[optind])) { + if (space++) printf(" "); + printf("%d", proc->pid); + found_something = 1; + } + } + ent = readdir(dirp); + } + closedir(dirp); + + if (!found_something) { + return 1; + } + printf("\n"); + return 0; +} + + diff --git a/userspace/gui/basic/plasma.c b/apps/plasma.c similarity index 65% rename from userspace/gui/basic/plasma.c rename to apps/plasma.c index aeecef41..7d7abc3c 100644 --- a/userspace/gui/basic/plasma.c +++ b/apps/plasma.c @@ -1,22 +1,23 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* - * test-gfx + * Copyright (C) 2013-2018 K. Lange + * + * plasma - Draw animated plasma in a window * - * Windowed graphical test application. */ #include #include #include -#include +#include +#include +#include -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/decorations.h" -#include "lib/pthread.h" -#include "lib/spinlock.h" +#include +#include +#include +#include +#include #define dist(a,b,c,d) sqrt((double)(((a) - (c)) * ((a) - (c)) + ((b) - (d)) * ((b) - (d)))) @@ -35,7 +36,7 @@ static int volatile draw_lock = 0; gfx_context_t * ctx; void redraw_borders() { - render_decorations(wina, ctx, "🔥 Plasma 🔥"); + render_decorations(wina, ctx, "Plasma"); } uint32_t hsv_to_rgb(int h, float s, float v) { @@ -69,9 +70,6 @@ void * draw_thread(void * garbage) { time += 1.0; - int w = win_width; - int h = win_height; - spin_lock(&draw_lock); for (int x = 0; x < win_width; ++x) { for (int y = 0; y < win_height; ++y) { @@ -86,35 +84,51 @@ void * draw_thread(void * garbage) { flip(ctx); yutani_flip(yctx, wina); spin_unlock(&draw_lock); - syscall_yield(); + sched_yield(); } + return NULL; } void resize_finish(int w, int h) { yutani_window_resize_accept(yctx, wina, w, h); reinit_graphics_yutani(ctx, wina); - win_width = w - decor_width(); - win_height = h - decor_height(); + struct decor_bounds bounds; + decor_get_bounds(wina, &bounds); + + win_width = w - bounds.width; + win_height = h - bounds.height; + off_x = bounds.left_width; + off_y = bounds.top_height; yutani_window_resize_done(yctx, wina); } int main (int argc, char ** argv) { yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } - win_width = 100; - win_height = 100; + win_width = 300; + win_height = 300; init_decorations(); - off_x = decor_left_width; - off_y = decor_top_height; + struct decor_bounds bounds; + decor_get_bounds(NULL, &bounds); /* Do something with a window */ - wina = yutani_window_create(yctx, win_width + decor_width(), win_height + decor_height()); + wina = yutani_window_create(yctx, win_width + bounds.width, win_height + bounds.height); yutani_window_move(yctx, wina, 300, 300); + decor_get_bounds(wina, &bounds); + off_x = bounds.left_width; + off_y = bounds.top_height; + win_width = wina->width - bounds.width; + win_height = wina->height - bounds.height; + ctx = init_graphics_yutani_double_buffer(wina); draw_fill(ctx, rgb(0,0,0)); @@ -129,7 +143,8 @@ int main (int argc, char ** argv) { while (!should_exit) { yutani_msg_t * m = yutani_poll(yctx); - if (m) { + while (m) { + menu_process_event(yctx, m); switch (m->type) { case YUTANI_MSG_KEY_EVENT: { @@ -143,34 +158,48 @@ int main (int argc, char ** argv) { { struct yutani_msg_window_focus_change * wf = (void*)m->data; yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); - if (win) { + if (win && win == wina) { win->focused = wf->focused; } } break; + case YUTANI_MSG_WINDOW_CLOSE: case YUTANI_MSG_SESSION_END: should_exit = 1; break; case YUTANI_MSG_RESIZE_OFFER: { struct yutani_msg_window_resize * wr = (void*)m->data; - spin_lock(&draw_lock); - resize_finish(wr->width, wr->height); - spin_unlock(&draw_lock); + if (wr->wid == wina->wid) { + spin_lock(&draw_lock); + resize_finish(wr->width, wr->height); + spin_unlock(&draw_lock); + } } break; case YUTANI_MSG_WINDOW_MOUSE_EVENT: - if (decor_handle_event(yctx, m) == DECOR_CLOSE) { - should_exit = 1; + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + switch (decor_handle_event(yctx, m)) { + case DECOR_CLOSE: + should_exit = 1; + break; + case DECOR_RIGHT: + decor_show_default_menu(wina, wina->x + me->new_x, wina->y + me->new_y); + break; + } } break; default: break; } free(m); + m = yutani_poll_async(yctx); } } + wait(NULL); + yutani_close(yctx, wina); return 0; } diff --git a/userspace/extra/play.c b/apps/play.c similarity index 61% rename from userspace/extra/play.c rename to apps/play.c index 65317a2e..fcf4e900 100644 --- a/userspace/extra/play.c +++ b/apps/play.c @@ -1,6 +1,12 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Kevin Lange + * Copyright (C) 2015-2018 K. Lange + * + * play - Play back PCM samples + * + * This needs very specifically-formatted PCM data to function + * properly - 16-bit, signed, stereo, little endian, and 48KHz. */ #include @@ -31,7 +37,7 @@ int main(int argc, char * argv[]) { char buf[0x1000]; int r; - while (r = read(song, buf, sizeof(buf))) { + while ((r = read(song, buf, sizeof(buf)))) { write(spkr, buf, r); } return 0; diff --git a/userspace/gui/basic/pong.c b/apps/pong.c similarity index 91% rename from userspace/gui/basic/pong.c rename to apps/pong.c index 3f192a4e..8b83546f 100644 --- a/userspace/gui/basic/pong.c +++ b/apps/pong.c @@ -1,8 +1,9 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Kevin Lange + * Copyright (C) 2015 K. Lange * - * Window Manager Pong + * pong - Window Manager Pong * * Play pong where the paddles and ball are all windows. * Use the WM bindings to drag the left paddle to play. @@ -23,14 +24,11 @@ #include #include #include - +#include #include -#include - -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/pthread.h" +#include +#include #define GAME_PATH "/usr/share/pong" @@ -98,7 +96,7 @@ static uint32_t current_time() { uint32_t sec_diff = t.tv_sec - start_time; uint32_t usec_diff = t.tv_usec - start_subtime; - if (t.tv_usec < start_subtime) { + if (t.tv_usec < (int)start_subtime) { sec_diff -= 1; usec_diff = (1000000 + t.tv_usec) - start_subtime; } @@ -233,9 +231,13 @@ int main (int argc, char ** argv) { ball.vel_y = ((double)rand() / RAND_MAX) * 6.0 - 3.0; ball.vel_x = -10.0; - load_sprite_png(&left.sprite, GAME_PATH "/paddle-red.png"); - load_sprite_png(&right.sprite,GAME_PATH "/paddle-blue.png"); - load_sprite_png(&ball.sprite, GAME_PATH "/ball.png"); + fprintf(stderr, "Loading sprites...\n"); + load_sprite(&left.sprite, GAME_PATH "/paddle-red.bmp"); + left.sprite.alpha = ALPHA_EMBEDDED; + load_sprite(&right.sprite,GAME_PATH "/paddle-blue.bmp"); + right.sprite.alpha = ALPHA_EMBEDDED; + load_sprite(&ball.sprite, GAME_PATH "/ball.bmp"); + ball.sprite.alpha = ALPHA_EMBEDDED; redraw(); update_left(); @@ -294,7 +296,7 @@ int main (int argc, char ** argv) { } free(m); } else { - syscall_yield(); + sched_yield(); } } diff --git a/apps/ps.c b/apps/ps.c new file mode 100644 index 00000000..f07acc72 --- /dev/null +++ b/apps/ps.c @@ -0,0 +1,289 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * ps + * + * print a list of running processes + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LINE_LEN 4096 + +static int show_all = 0; +static int show_threads = 0; +static int show_username = 0; +static int show_mem = 0; +static int collect_commandline = 0; + +static int widths[] = {3,3,4,3,3,4}; + +struct process { + int uid; + int pid; + int tid; + int mem; + int vsz; + int shm; + char * process; + char * command_line; +}; + +void print_username(int uid) { + struct passwd * p = getpwuid(uid); + + if (p) { + printf("%-8s", p->pw_name); + } else { + printf("%-8d", uid); + } + + endpwent(); +} + +struct process * process_entry(struct dirent *dent) { + char tmp[256]; + FILE * f; + char line[LINE_LEN]; + + int pid = 0, uid = 0, tgid = 0, mem = 0, shm = 0, vsz = 0; + char name[100]; + + sprintf(tmp, "/proc/%s/status", dent->d_name); + f = fopen(tmp, "r"); + + if (!f) { + return NULL; + } + + line[0] = 0; + + while (fgets(line, LINE_LEN, f) != NULL) { + char * n = strstr(line,"\n"); + if (n) { *n = '\0'; } + char * tab = strstr(line,"\t"); + if (tab) { + *tab = '\0'; + tab++; + } + if (strstr(line, "Pid:") == line) { + pid = atoi(tab); + } else if (strstr(line, "Uid:") == line) { + uid = atoi(tab); + } else if (strstr(line, "Tgid:") == line) { + tgid = atoi(tab); + } else if (strstr(line, "Name:") == line) { + strcpy(name, tab); + } else if (strstr(line, "VmSize:") == line) { + vsz = atoi(tab); + } else if (strstr(line, "RssShmem:") == line) { + shm = atoi(tab); + } else if (strstr(line, "MemPermille:") == line) { + mem = atoi(tab); + } + } + + fclose(f); + + if (!show_all) { + /* Filter not ours */ + if (uid != getuid()) return NULL; + } + + if (!show_threads) { + if (tgid != pid) return NULL; + } + + struct process * out = malloc(sizeof(struct process)); + out->uid = uid; + out->pid = tgid; + out->tid = pid; + out->mem = mem; + out->shm = shm; + out->vsz = vsz; + out->process = strdup(name); + out->command_line = NULL; + + char garbage[1024]; + int len; + + if ((len = sprintf(garbage, "%d", out->pid)) > widths[0]) widths[0] = len; + if ((len = sprintf(garbage, "%d", out->tid)) > widths[1]) widths[1] = len; + if ((len = sprintf(garbage, "%d", out->vsz)) > widths[3]) widths[3] = len; + if ((len = sprintf(garbage, "%d", out->shm)) > widths[4]) widths[4] = len; + if ((len = sprintf(garbage, "%d.%01d", out->mem / 10, out->mem % 10)) > widths[5]) widths[5] = len; + + struct passwd * p = getpwuid(out->uid); + if (p) { + if ((len = strlen(p->pw_name)) > widths[2]) widths[2] = len; + } else { + if ((len = sprintf(garbage, "%d", out->uid)) > widths[2]) widths[2] = len; + } + endpwent(); + + if (collect_commandline) { + sprintf(tmp, "/proc/%s/cmdline", dent->d_name); + f = fopen(tmp, "r"); + char foo[1024]; + int s = fread(foo, 1, 1024, f); + if (s > 0) { + out->command_line = malloc(s + 1); + memset(out->command_line, 0, s + 1); + memcpy(out->command_line, foo, s); + + for (int i = 0; i < s; ++i) { + if (out->command_line[i] == 30) { + out->command_line[i] = ' '; + } + } + + } + fclose(f); + } + + return out; +} + +void print_header(void) { + if (show_username) { + printf("%-*s ", widths[2], "USER"); + } + printf("%*s ", widths[0], "PID"); + if (show_threads) { + printf("%*s ", widths[1], "TID"); + } + if (show_mem) { + printf("%*s ", widths[5], "MEM%"); + printf("%*s ", widths[3], "VSZ"); + printf("%*s ", widths[4], "SHM"); + } + printf("CMD\n"); +} + +void print_entry(struct process * out) { + if (show_username) { + struct passwd * p = getpwuid(out->uid); + if (p) { + printf("%-*s ", widths[2], p->pw_name); + } else { + printf("%-*d ", widths[2], out->uid); + } + endpwent(); + } + printf("%*d ", widths[0], out->pid); + if (show_threads) { + printf("%*d ", widths[1], out->tid); + } + if (show_mem) { + char tmp[6]; + sprintf(tmp, "%*d.%01d", widths[5]-2, out->mem / 10, out->mem % 10); + printf("%*s ", widths[5], tmp); + printf("%*d ", widths[3], out->vsz); + printf("%*d ", widths[4], out->shm); + } + if (out->command_line) { + printf("%s\n", out->command_line); + } else { + printf("%s\n", out->process); + } +} + +void show_usage(int argc, char * argv[]) { + printf( + "ps - list running processes\n" + "\n" + "usage: %s [-A] [format]\n" + "\n" + " -A \033[3mshow other users' processes\033[0m\n" + " -T \033[3mshow threads\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n" + " [format] supports some BSD options:\n" + "\n" + " a \033[3mshow full command line\033[0m\n" + " u \033[3muse 'user-oriented' format\033[0m\n" + "\n", argv[0]); +} + +int main (int argc, char * argv[]) { + + /* Parse arguments */ + char c; + while ((c = getopt(argc, argv, "AT?")) != -1) { + switch (c) { + case 'A': + show_all = 1; + break; + case 'T': + show_threads = 1; + break; + case '?': + show_usage(argc, argv); + return 0; + } + } + + if (optind < argc) { + char * show = argv[optind]; + while (*show) { + switch (*show) { + case 'u': + show_username = 1; + show_mem = 1; + // fallthrough + case 'a': + collect_commandline = 1; + break; + default: + break; + } + show++; + } + } + + /* Open the directory */ + DIR * dirp = opendir("/proc"); + + /* Read the entries in the directory */ + list_t * ents_list = list_create(); + + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') { + struct process * p = process_entry(ent); + if (p) { + list_insert(ents_list, (void *)p); + } + } + + ent = readdir(dirp); + } + closedir(dirp); + + print_header(); + foreach(entry, ents_list) { + print_entry(entry->value); + } + + + return 0; +} + +/* + * vim: tabstop=4 + * vim: shiftwidth=4 + * vim: noexpandtab + */ diff --git a/userspace/core/pstree.c b/apps/pstree.c similarity index 75% rename from userspace/core/pstree.c rename to apps/pstree.c index a52111f1..69461c4f 100644 --- a/userspace/core/pstree.c +++ b/apps/pstree.c @@ -1,26 +1,22 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -/* - * pstree + * Copyright (C) 2014-2018 K. Lange + * + * pstree - Display a tree of running process * - * Prints running processes as a tree of */ - - #include #include #include #include #include #include -#include #include #include -#include "lib/list.h" -#include "lib/tree.h" +#include +#include typedef struct process { int pid; @@ -33,33 +29,37 @@ typedef struct process { #define LINE_LEN 4096 p_t * build_entry(struct dirent * dent) { - char tmp[256], buf[4096]; + char tmp[256]; FILE * f; - int read = 1; char line[LINE_LEN]; - int pid, uid; - - snprintf(tmp, 256, "/proc/%s/status", dent->d_name); + sprintf(tmp, "/proc/%s/status", dent->d_name); f = fopen(tmp, "r"); p_t * proc = malloc(sizeof(p_t)); while (fgets(line, LINE_LEN, f) != NULL) { + char * n = strstr(line,"\n"); + if (n) { *n = '\0'; } + char * tab = strstr(line,"\t"); + if (tab) { + *tab = '\0'; + tab++; + } if (strstr(line, "Pid:") == line) { - sscanf(line, "%s %d", &buf, &proc->pid); + proc->pid = atoi(tab); } else if (strstr(line, "PPid:") == line) { - sscanf(line, "%s %d", &buf, &proc->ppid); + proc->ppid = atoi(tab); } else if (strstr(line, "Tgid:") == line) { - sscanf(line, "%s %d", &buf, &proc->tgid); + proc->tgid = atoi(tab); } else if (strstr(line, "Name:") == line) { - sscanf(line, "%s %s", &buf, &proc->name); + strcpy(proc->name, tab); } else if (strstr(line, "Path:") == line) { - sscanf(line, "%s %s", &buf, &proc->path); + strcpy(proc->path, tab); } } - if (!strncmp(proc->name,"python",6)) { + if (strstr(proc->name,"python") == proc->name) { char * name = proc->path + strlen(proc->path) - 1; while (1) { @@ -96,7 +96,7 @@ void print_process_tree_node(tree_node_t * node, size_t depth, int indented, int p_t * proc = node->value; - for (int i = 0; i < strlen(proc->name)+3; ++i) { + for (int i = 0; i < (int)strlen(proc->name)+3; ++i) { lines[depth+i] = 0; } @@ -109,7 +109,7 @@ void print_process_tree_node(tree_node_t * node, size_t depth, int indented, int } depth += 3; } else if (depth) { - for (int i = 0; i < depth; ++i) { + for (int i = 0; i < (int)depth; ++i) { if (lines[i]) { printf("│"); } else { @@ -135,11 +135,12 @@ void print_process_tree_node(tree_node_t * node, size_t depth, int indented, int int t = 0; foreach(child, node->children) { /* Recursively print the children */ - print_process_tree_node(child->value, depth, !!(t++), ((t+1)!=node->children->length), lines); + print_process_tree_node(child->value, depth, !!(t), ((t+1)!=(int)node->children->length), lines); + t++; } } - for (int i = 0; i < strlen(proc->name)+3; ++i) { + for (int i = 0; i < (int)strlen(proc->name)+3; ++i) { lines[depth+i] = 0; } } @@ -181,3 +182,4 @@ int main (int argc, char * argv[]) { * vim: shiftwidth=4 * vim: noexpandtab */ + diff --git a/apps/pwd.c b/apps/pwd.c new file mode 100644 index 00000000..3491a65a --- /dev/null +++ b/apps/pwd.c @@ -0,0 +1,19 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * pwd - Print working directory + */ +#include +#include + +int main(int argc, char * argv[]) { + char tmp[1024]; + if (getcwd(tmp, 1023)) { + puts(tmp); + return 0; + } else { + return 1; + } +} diff --git a/apps/qemu-display-hack.c b/apps/qemu-display-hack.c new file mode 100644 index 00000000..7e580698 --- /dev/null +++ b/apps/qemu-display-hack.c @@ -0,0 +1,86 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * qemu-display-hack - Manage display size under QEMU + * + * Communicates with a harness on the host running QEMU to + * automatically update the display resolution when the + * QEMU window size changes, similar to how VirtualBox's + * display size changing works. + * + * This is automatically run at startup if the harness is + * detected by the 90_qemu_hack.sh startup script. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + + if (system("qemu-fwcfg -q opt/org.toaruos.displayharness") != 0) { + fprintf(stderr, "%s: display harness not enabled\n", argv[0]); + return 1; + } + + int fd = open("/dev/fb0", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: failed to open framebuffer: %s\n", argv[0], strerror(errno)); + return 1; + } + + struct vid_size s; + + FILE * f = fopen("/dev/ttyS1","r+"); + if (!f) { + fprintf(stderr, "%s: failed to open serial: %s\n", argv[0], strerror(errno)); + return 1; + } + + if (!fork()) { + + while (!feof(f)) { + char data[128]; + fgets(data, 128, f); + + char * linefeed = strstr(data,"\n"); + if (linefeed) { *linefeed = '\0'; } + + char * width; + char * height; + + width = strstr(data, " "); + if (width) { + *width = '\0'; + width++; + } else { + continue; /* bad line */ + } + + height = strstr(width, " "); + if (height) { + *height = '\0'; + height++; + } else { + continue; /* bad line */ + } + + s.width = atoi(width); + s.height = atoi(height); + + ioctl(fd, IO_VID_SET, &s); + fprintf(f, "X"); + fflush(f); + } + + return 0; + } + + return 0; +} diff --git a/apps/qemu-fwcfg.c b/apps/qemu-fwcfg.c new file mode 100644 index 00000000..ceebf0b6 --- /dev/null +++ b/apps/qemu-fwcfg.c @@ -0,0 +1,187 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * qemu-fwcfg - Read QEMU fwcfg values. + * + * Provides easy access to values and files set by QEMU's -fw_cfg + * flag. This is used by the QEMU harness, as well as the bootloader, + * and can be used to provide files directly to the guest. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FW_CFG_PORT_OUT 0x510 +#define FW_CFG_PORT_IN 0x511 +#define FW_CFG_SELECT_QEMU 0x0000 +#define FW_CFG_SELECT_LIST 0x0019 + +static int port_fd = -1; + +/* outw / inb helper functions */ +static void outports(unsigned short _port, unsigned short _data) { + lseek(port_fd, _port, SEEK_SET); + write(port_fd, &_data, 2); +} + +static unsigned char inportb(unsigned short _port) { + unsigned char out; + lseek(port_fd, _port, SEEK_SET); + read(port_fd, &out, 1); + return out; +} + +/* Despite primarily emulating x86, these are all big-endian */ +static void swap_bytes(void * in, int count) { + char * bytes = in; + if (count == 4) { + uint32_t * t = in; + *t = (bytes[0] << 24) | (bytes[1] << 12) | (bytes[2] << 8) | bytes[3]; + } else if (count == 2) { + uint16_t * t = in; + *t = (bytes[0] << 8) | bytes[1]; + } +} + +/* Layout of the information returned from the fw_cfg port */ +struct fw_cfg_file { + uint32_t size; + uint16_t select; + uint16_t reserved; + char name[56]; +}; + +static int usage(char * argv[]) { + printf( + "Obtain QEMU fw_cfg values\n" + "\n" + "usage: %s [-?ln] [config name]\n" + "\n" + " -l \033[3mlist available config entries\033[0m\n" + " -n \033[3mdon't print a new line after data\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); + return 1; +} + +static void sig_pass(int sig) { + exit(1); +} + +int main(int argc, char * argv[]) { + + uint32_t count = 0; + uint8_t * bytes = (uint8_t *)&count; + int found = 0; + struct fw_cfg_file file; + uint8_t * tmp = (uint8_t *)&file; + + int opt = 0; + int list = 0; + int no_newline = 0; + int query_quietly = 0; + + while ((opt = getopt(argc, argv, "?lnq")) != -1) { + switch (opt) { + case '?': + return usage(argv); + case 'n': + no_newline = 1; + break; + case 'q': + query_quietly = 1; + break; + case 'l': + list = 1; + break; + } + } + + if (optind >= argc && !list) { + return usage(argv); + } + + port_fd = open("/dev/port", O_RDWR); + + if (port_fd < 0) { + fprintf(stderr, "%s: could not open port IO device\n", argv[0]); + return 1; + } + + signal(SIGILL, sig_pass); + + /* First check for QEMU */ + outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_QEMU); + if (inportb(FW_CFG_PORT_IN) != 'Q' || + inportb(FW_CFG_PORT_IN) != 'E' || + inportb(FW_CFG_PORT_IN) != 'M' || + inportb(FW_CFG_PORT_IN) != 'U') { + fprintf(stderr, "%s: this doesn't seem to be qemu\n", argv[0]); + return 1; + } + + /* Then get the list of "files" so we can look at names */ + outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_LIST); + for (int i = 0; i < 4; ++i) { + bytes[i] = inportb(FW_CFG_PORT_IN); + } + swap_bytes(&count, sizeof(count)); + + for (unsigned int i = 0; i < count; ++i) { + + /* read one file entry */ + for (unsigned int j = 0; j < sizeof(struct fw_cfg_file); ++j) { + tmp[j] = inportb(FW_CFG_PORT_IN); + } + + /* endian swap to get file size and selector ID */ + swap_bytes(&file.size, sizeof(file.size)); + swap_bytes(&file.select, sizeof(file.select)); + + if (list) { + /* 0x0020 org/whatever (1234 bytes) */ + fprintf(stdout, "0x%04x %s (%d byte%s)\n", file.select, file.name, (int)file.size, file.size == 1 ? "" : "s"); + } else { + if (!strcmp(file.name, argv[optind])) { + /* found the requested file */ + found = 1; + break; + } + } + } + + if (query_quietly) { + return !found; + } + + if (found) { + /* if we found the requested file, read it from the port */ + outports(FW_CFG_PORT_OUT, file.select); + + for (unsigned int i = 0; i < file.size; ++i) { + fputc(inportb(FW_CFG_PORT_IN), stdout); + } + + if (!no_newline) { + fprintf(stdout, "\n"); + } else { + fflush(stdout); + } + + } else if (!list) { + fprintf(stderr, "%s: config option not found\n", argv[0]); + return 1; + } + + return 0; +} diff --git a/userspace/util/readelf.c b/apps/readelf.c similarity index 78% rename from userspace/util/readelf.c rename to apps/readelf.c index 5d73e248..fdda7522 100644 --- a/userspace/util/readelf.c +++ b/apps/readelf.c @@ -1,19 +1,20 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2018 K Lange + * + * readelf - Show information about ELF objects + * + * This is a very custom implementation and nothing remotely + * like the version that comes with binutils. Making it more + * like that version might be worthwhile. */ -/* - * ToAruOS Miniature ELF Reader - * (C) 2011 Kevin Lange - */ - #include #include #include #include - -/* The Master ELF Header */ -#include "../../kernel/include/elf.h" +#include +#include /** * Show usage for the readelf application. @@ -40,12 +41,17 @@ int main(int argc, char ** argv) { size_t binary_size; /**< Size of the file */ char * binary_buf; /**< Buffer to store the binary in memory */ Elf32_Header * header; /**< ELF header */ - char * string_table; /**< The section header string table */ - char * sym_string_table; /**< The symbol string table */ + char * string_table = NULL; /**< The section header string table */ + char * sym_string_table = NULL; /**< The symbol string table */ /* Open the requested binary */ binary = fopen(argv[1], "r"); + if (!binary) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], strerror(errno)); + return 1; + } + /* Jump to the end so we can get the size */ fseek(binary, 0, SEEK_END); binary_size = ftell(binary); @@ -117,17 +123,17 @@ int main(int argc, char ** argv) { } /* Entry point in memory */ - printf("Binary entry point in virtual memory is at 0x%x\n", header->e_entry); + printf("Binary entry point in virtual memory is at 0x%x\n", (unsigned int)header->e_entry); /* Program header table offset */ printf("Program header table is at +0x%x and one entry is 0x%x bytes.\n" "There are %d total program headers.\n", - header->e_phoff, header->e_phentsize, header->e_phnum); + (unsigned int)header->e_phoff, (unsigned int)header->e_phentsize, (unsigned int)header->e_phnum); /* Section header table offset */ printf("Section header table is at +0x%x and one entry is 0x%x bytes.\n" "There are %d total section headers.\n", - header->e_shoff, header->e_shentsize, header->e_shnum); + (unsigned int)header->e_shoff, (unsigned int)header->e_shentsize, (unsigned int)header->e_shnum); /* Read the program headers */ printf("\033[1mProgram Headers\033[0m\n"); @@ -166,12 +172,17 @@ int main(int argc, char ** argv) { if (shdr->sh_type == SHT_STRTAB) { if (i == header->e_shstrndx) { string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset); - printf("Found the section string table at 0x%x\n", shdr->sh_offset); + printf("Found the section string table at 0x%x\n", (unsigned int)shdr->sh_offset); } } i++; } + if (!string_table) { + printf("No string table, skipping rest of output.\n"); + return 1; + } + /* Find the (hopefully two) string tables */ printf("\033[1mString Tables\033[0m\n"); for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) { @@ -183,13 +194,13 @@ int main(int argc, char ** argv) { if (shdr->sh_type == SHT_STRTAB) { if (!strcmp((char *)((uintptr_t)string_table + shdr->sh_name), ".strtab")) { sym_string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset); - printf("Found the symbol string table at 0x%x\n", shdr->sh_offset); + printf("Found the symbol string table at 0x%x\n", (unsigned int)shdr->sh_offset); } - printf("Displaying string table at 0x%x\n", shdr->sh_offset); + printf("Displaying string table at 0x%x\n", (unsigned int)shdr->sh_offset); char * _string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset); unsigned int j = 1; int k = 0; - printf("%d\n", shdr->sh_size); + printf("%d\n", (unsigned int)shdr->sh_size); while (j < shdr->sh_size) { int t = strlen((char *)((uintptr_t)_string_table + j)); if (t) { @@ -212,10 +223,10 @@ int main(int argc, char ** argv) { } Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x)); - printf("[%d] %s\n", shdr->sh_type, (char *)((uintptr_t)string_table + shdr->sh_name)); - printf("Section starts at 0x%x and is 0x%x bytes long.\n", shdr->sh_offset, shdr->sh_size); + printf("[%d] %s\n", (unsigned int)shdr->sh_type, (char *)((uintptr_t)string_table + shdr->sh_name)); + printf("Section starts at 0x%x and is 0x%x bytes long.\n", (unsigned int)shdr->sh_offset, (unsigned int)shdr->sh_size); if (shdr->sh_addr) { - printf("It should be loaded at 0x%x.\n", shdr->sh_addr); + printf("It should be loaded at 0x%x.\n", (unsigned int)shdr->sh_addr); } } @@ -233,7 +244,7 @@ int main(int argc, char ** argv) { Elf32_Sym * table = (Elf32_Sym *)((uintptr_t)binary_buf + (shdr->sh_offset)); while ((uintptr_t)table - ((uintptr_t)binary_buf + shdr->sh_offset) < shdr->sh_size) { - printf("%s: 0x%x [0x%x]\n", (char *)((uintptr_t)sym_string_table + table->st_name), table->st_value, table->st_size); + printf("%s: 0x%x [0x%x]\n", (char *)((uintptr_t)sym_string_table + table->st_name), (unsigned int)table->st_value, (unsigned int)table->st_size); table++; } } @@ -243,8 +254,3 @@ int main(int argc, char ** argv) { return 0; } -/* - * vim:noexpandtab - * vim:tabstop=4 - * vim:shiftwidth=4 - */ diff --git a/userspace/core/readlink.c b/apps/readlink.c similarity index 92% rename from userspace/core/readlink.c rename to apps/readlink.c index 7782c1a9..5ea2c960 100644 --- a/userspace/core/readlink.c +++ b/apps/readlink.c @@ -9,7 +9,7 @@ #define MAX_LINK_SIZE 4096 -static const char usage[] = +static char usage[] = "Usage: %s LINK\n"; int main(int argc, char * argv[]) { @@ -21,7 +21,7 @@ int main(int argc, char * argv[]) { char buf[MAX_LINK_SIZE]; if (readlink(name, buf, sizeof(buf)) < 0) { - perror("link"); + //perror("link"); exit(EXIT_FAILURE); } fprintf(stdout, "%s\n", buf); diff --git a/userspace/core/reboot.c b/apps/reboot.c similarity index 57% rename from userspace/core/reboot.c rename to apps/reboot.c index 275bb989..d95b4ed1 100644 --- a/userspace/core/reboot.c +++ b/apps/reboot.c @@ -1,11 +1,10 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* - * reboot + * Copyright (C) 2013-2014 K. Lange + * + * reboot - Reboot the system * - * Reboot the system. */ #include #include diff --git a/apps/rm.c b/apps/rm.c new file mode 100644 index 00000000..e77e05d3 --- /dev/null +++ b/apps/rm.c @@ -0,0 +1,31 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * rm - Unlink files + * + * TODO: Support recursive, directory removal, etc. + */ +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + if (argc < 2) { + fprintf(stderr, "usage: %s FILE...\n", argv[0]); + return 1; + } + + int ret = 0; + + for (int i = 1; i < argc; ++i) { + if (unlink(argv[i]) < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno)); + ret = 1; + } + } + + return ret; +} diff --git a/apps/sdf-demo.c b/apps/sdf-demo.c new file mode 100644 index 00000000..631e3f5c --- /dev/null +++ b/apps/sdf-demo.c @@ -0,0 +1,156 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * sdf-demo - SDF font rasterizer demo + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Pointer to graphics memory */ +static yutani_t * yctx; +static yutani_window_t * window = NULL; +static gfx_context_t * ctx = NULL; + +static int width = 500; +static int height = 500; + +static int left = 200; +static int top = 200; + +static int size = 16; + +static void decors() { + render_decorations(window, ctx, "SDF Demo"); +} + +void redraw() { + draw_fill(ctx, rgb(255,255,255)); + + decors(); + + draw_sdf_string(ctx, 30, 30, "ABCDEFGHIJKLMNOPQRSTUVWXYZABC", size, rgb(0,0,0), SDF_FONT_THIN); + draw_sdf_string(ctx, 30, 60, "abcdefghijklmnopqrstuvwxyzabc", size, rgb(0,0,0), SDF_FONT_THIN); + draw_sdf_string(ctx, 30, 90, "ABCDEFGHIJKLMNOPQRSTUVWXYZABC", size, rgb(0,0,0), SDF_FONT_BOLD); + draw_sdf_string(ctx, 30,120, "abcdefghijklmnopqrstuvwxyzabc", size, rgb(0,0,0), SDF_FONT_BOLD); +} + +void resize_finish(int w, int h) { + yutani_window_resize_accept(yctx, window, w, h); + reinit_graphics_yutani(ctx, window); + + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); + + width = w - bounds.left_width - bounds.right_width; + height = h - bounds.top_height - bounds.bottom_height; + + redraw(); + + yutani_window_resize_done(yctx, window); + yutani_flip(yctx, window); +} + + +int main(int argc, char * argv[]) { + + yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } + init_decorations(); + + struct decor_bounds bounds; + decor_get_bounds(NULL, &bounds); + + window = yutani_window_create(yctx, width + bounds.width, height + bounds.height); + yutani_window_move(yctx, window, left, top); + + yutani_window_advertise_icon(yctx, window, "SDF Demo", "sdf"); + + ctx = init_graphics_yutani(window); + + redraw(); + yutani_flip(yctx, window); + + int playing = 1; + while (playing) { + yutani_msg_t * m = yutani_poll(yctx); + if (m) { + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { + playing = 0; + } else if (ke->event.action == KEY_ACTION_DOWN) { + if (size <= 20) { + size += 1; + } else if (size > 20) { + size += 5; + } + if (size > 100) { + size = 1; + } + redraw(); + yutani_flip(yctx,window); + } + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * wf = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + if (win) { + win->focused = wf->focused; + decors(); + yutani_flip(yctx, window); + } + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + resize_finish(wr->width, wr->height); + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + int result = decor_handle_event(yctx, m); + switch (result) { + case DECOR_CLOSE: + playing = 0; + break; + default: + /* Other actions */ + break; + } + } + break; + case YUTANI_MSG_SESSION_END: + playing = 0; + break; + default: + break; + } + } + free(m); + } + + yutani_close(yctx, window); + + return 0; +} + diff --git a/userspace/extra/serial-console.c b/apps/serial-console.c similarity index 96% rename from userspace/extra/serial-console.c rename to apps/serial-console.c index af536c5d..4fbb7158 100644 --- a/userspace/extra/serial-console.c +++ b/apps/serial-console.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2014 K. Lange * * serial console * @@ -12,11 +12,12 @@ #include #include #include -#include #include +#include #include #include #include +#include int fd = 0; @@ -90,7 +91,7 @@ int main(int argc, char ** argv) { int fds[2] = {STDIN_FILENO, fd}; while (1) { - int index = syscall_fswait(2, fds); + int index = fswait(2, fds); if (index == -1) { fprintf(stderr, "serial-console: fswait: erroneous file descriptor\n"); diff --git a/userspace/gui/core/gsession.c b/apps/session.c similarity index 53% rename from userspace/gui/core/gsession.c rename to apps/session.c index 78169a71..5b5b0abf 100644 --- a/userspace/gui/core/gsession.c +++ b/apps/session.c @@ -1,30 +1,41 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2018 K. Lange * - * Graphical Session Manager + * session - UI session manager * + * Runs a background and panel for a single user and waits + * for them to exit. */ #include #include #include -#include #include #include #include int main(int argc, char * argv[]) { - /* Starts a graphical session and then spins waiting for a kill (logout) signal */ + + char path[1024]; + char * home = getenv("HOME"); + if (home) { + sprintf(path, "%s/.yutanirc", home); + char * args[] = {path, NULL}; + execvp(args[0], args); + } + + /* Fallback */ + + int _background_pid = fork(); + if (!_background_pid) { + char * args[] = {"/bin/background", "--really", NULL}; + execvp(args[0], args); + } int _panel_pid = fork(); if (!_panel_pid) { - char * args[] = {"/bin/panel.py", NULL}; - execvp(args[0], args); - } - int _toastd_pid = fork(); - if (!_toastd_pid) { - char * args[] = {"/bin/toastd.py", NULL}; + char * args[] = {"/bin/panel", "--really", NULL}; execvp(args[0], args); } diff --git a/apps/set-resolution.c b/apps/set-resolution.c new file mode 100644 index 00000000..bfd22f4a --- /dev/null +++ b/apps/set-resolution.c @@ -0,0 +1,48 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * set-resolution - Change the display resolution. + * + * Simple tool to interface with the IO_VID_SET ioctl. + * + * TODO: This is probably something we should request from the + * compositor rather than a separate application... + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + if (argc < 3) { + fprintf(stderr, "Usage: %s width height\n", argv[0]); + } + + /* Open framebuffer */ + int fd = open("/dev/fb0", O_RDONLY); + + if (fd < 0) { + perror("open"); + return 1; + } + + /* Prepare ioctl from arguments */ + struct vid_size s; + s.width = atoi(argv[1]); + s.height = atoi(argv[2]); + + /* Send ioctl */ + if (ioctl(fd, IO_VID_SET, &s) < 0) { + perror("ioctl"); + return 1; + } + + return 0; +} diff --git a/apps/sh.c b/apps/sh.c new file mode 100644 index 00000000..10e9b809 --- /dev/null +++ b/apps/sh.c @@ -0,0 +1,1811 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * E-Shell + * + * This is "experimental shell" - a vaguely-unix-like command + * interface. It has a very rudimentary parser that understands + * some things like pipes or writing out to a file. It has a + * handful of built-in commands, including ones that implement + * some more useful shell syntax such as loops and conditionals. + * There is support for tab completion of filenames and commands. + */ + +#define _XOPEN_SOURCE 500 +#define _POSIX_C_SOURCE 200112L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef environ +extern char **environ; +#endif + +#ifndef toaru +#define tcsetpgrp(a,b) +#endif + +#define PIPE_TOKEN "\xFF\xFFPIPE\xFF\xFF" +#define STAR_TOKEN "\xFF\xFFSTAR\xFF\xFF" +#define WRITE_TOKEN "\xFF\xFFWRITE\xFF\xFF" +#define APPEND_TOKEN "\xFF\xFF""APPEND\xFF" + +/* A shell command is like a C program */ +typedef uint32_t(*shell_command_t) (int argc, char ** argv); + +/* We have a static array that fits a certain number of them. */ +int SHELL_COMMANDS = 64; +char ** shell_commands; /* Command names */ +shell_command_t * shell_pointers; /* Command functions */ +char ** shell_descript; /* Command descriptions */ + +/* This is the number of actual commands installed */ +int shell_commands_len = 0; + +int shell_interactive = 1; +int last_ret = 0; +char ** shell_argv = NULL; +int shell_argc = 0; +int experimental_rline = 1; + +static int current_line = 0; +static char * current_file = NULL; + +int pid; /* Process ID of the shell */ + +void shell_install_command(char * name, shell_command_t func, char * desc) { + if (shell_commands_len == SHELL_COMMANDS) { + SHELL_COMMANDS *= 2; + shell_commands = realloc(shell_commands, sizeof(char *) * SHELL_COMMANDS); + shell_pointers = realloc(shell_pointers, sizeof(shell_command_t) * SHELL_COMMANDS); + shell_descript = realloc(shell_descript, sizeof(char *) * SHELL_COMMANDS); + return; + } + shell_commands[shell_commands_len] = name; + shell_pointers[shell_commands_len] = func; + shell_descript[shell_commands_len] = desc; + shell_commands_len++; +} + +shell_command_t shell_find(char * str) { + for (int i = 0; i < shell_commands_len; ++i) { + if (!strcmp(str, shell_commands[i])) { + return shell_pointers[i]; + } + } + return NULL; +} + +void install_commands(); + +/* Maximum command length */ +#define LINE_LEN 4096 + +/* Current working directory */ +char cwd[1024] = {'/',0}; + +/* Username */ +char username[1024]; + +/* Hostname for prompt */ +char _hostname[256]; + +/* function to update the cached username */ +void getuser() { + char * tmp = getenv("USER"); + if (tmp) { + strcpy(username, tmp); + } else { + sprintf(username, "%d", getuid()); + } +} + +/* function to update the cached hostname */ +void gethost() { + struct utsname buf; + + uname(&buf); + + int len = strlen(buf.nodename); + memcpy(_hostname, buf.nodename, len+1); +} + +void print_extended_ps(char * format, char * buffer, int * display_width) { + /* Get the time */ + struct tm * timeinfo; + struct timeval now; + gettimeofday(&now, NULL); //time(NULL); + timeinfo = localtime((time_t *)&now.tv_sec); + + /* Format the date and time for prompt display */ + char date_buffer[80]; + strftime(date_buffer, 80, "%m/%d", timeinfo); + char time_buffer[80]; + strftime(time_buffer, 80, "%H:%M:%S", timeinfo); + + /* Collect the current working directory */ + getcwd(cwd, 512); + char _cwd[512]; + strcpy(_cwd, cwd); + + /* Collect the user's home directory and apply it to cwd */ + char * home = getenv("HOME"); + if (home && strstr(cwd, home) == cwd) { + char * c = cwd + strlen(home); + if (*c == '/' || *c == 0) { + sprintf(_cwd, "~%s", c); + } + } + + char ret[80] = {0}; + if (last_ret != 0) { + sprintf(ret, "%d ", last_ret); + } + + size_t offset = 0; + int is_visible = 1; + *display_width = 0; + + while (*format) { + if (*format == '\\') { + format++; + switch (*format) { + case '\\': + buffer[offset++] = *format; + (*display_width) += is_visible ? 1 : 0; + format++; + break; + case '[': + is_visible = 0; + format++; + break; + case ']': + is_visible = 1; + format++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int i = (*format) - '0'; + format++; + if (*format >= '0' && *format <= '7') { + i *= 8; + i += (*format) - '0'; + format++; + if (*format >= '0' && *format <= '7') { + i *= 8; + i += (*format) - '0'; + format++; + } + } + buffer[offset++] = i; + (*display_width) += is_visible ? 1 : 0; + } + break; + case 'e': + buffer[offset++] = '\033'; + (*display_width) += is_visible ? 1 : 0; + format++; + break; + case 'd': + { + int size = sprintf(buffer+offset, "%s", date_buffer); + offset += size; + (*display_width) += is_visible ? size : 0; + } + format++; + break; + case 't': + { + int size = sprintf(buffer+offset, "%s", time_buffer); + offset += size; + (*display_width) += is_visible ? size : 0; + } + format++; + break; + case 'h': + { + int size = sprintf(buffer+offset, "%s", _hostname); + offset += size; + (*display_width) += is_visible ? size : 0; + } + format++; + break; + case 'u': + { + int size = sprintf(buffer+offset, "%s", username); + offset += size; + (*display_width) += is_visible ? size : 0; + } + format++; + break; + case 'w': + { + int size = sprintf(buffer+offset, "%s", _cwd); + offset += size; + (*display_width) += is_visible ? size : 0; + } + format++; + break; + case '$': + buffer[offset++] = (getuid() == 0 ? '#' : '$'); + (*display_width) += is_visible ? 1 : 0; + format++; + break; + case 'U': /* prompt color string */ + { + int size = sprintf(buffer+offset, "%s", getuid() == 0 ? "\033[1;38;5;196m" : "\033[1;38;5;47m"); + offset += size; + /* Does not affect size */ + } + format++; + break; + case 'r': + { + int size = sprintf(buffer+offset, "%s", ret); + offset += size; + (*display_width) += is_visible ? size : 0; + } + format++; + break; + default: + { + int size = sprintf(buffer+offset, "\\%c", *format); + offset += size; + (*display_width) += is_visible ? size : 0; + } + format++; + break; + } + } else { + buffer[offset++] = *format; + (*display_width) += is_visible ? 1 : 0; + format++; + } + } + + buffer[offset] = '\0'; +} + +#define FALLBACK_PS1 "\\u@\\h \\w\\$ " + +/* Draw the user prompt */ +void draw_prompt(void) { + char * ps1 = getenv("PS1"); + char buf[1024]; + int display_width; + print_extended_ps(ps1 ? ps1 : FALLBACK_PS1, buf, &display_width); + fprintf(stdout, "%s", buf); + fflush(stdout); +} + +volatile int break_while = 0; +uint32_t child = 0; + +void sig_pass(int sig) { + /* Interrupt handler */ + if (child) { + kill(child, sig); + } + break_while = sig; +} + +void redraw_prompt_func(rline_context_t * context) { + draw_prompt(); +} + +void draw_prompt_c() { + char * ps2 = getenv("PS2"); + if (ps2) { + char buf[1024]; + int display_width; + print_extended_ps(ps2, buf, &display_width); + fprintf(stdout, "%s", buf); + } else { + printf("> "); + } + fflush(stdout); +} +void redraw_prompt_func_c(rline_context_t * context) { + draw_prompt_c(); +} + +void tab_complete_func(rline_context_t * c) { + char * dup = malloc(LINE_LEN); + + memcpy(dup, c->buffer, LINE_LEN); + + char *pch, *save; + char *argv[1024]; + int argc = 0; + int cursor = 0; + + pch = strtok_r(dup, " ", &save); + + if (!pch) { + argv[0] = ""; + argc = 0; + } + + while (pch != NULL) { + if (pch - dup <= c->offset) cursor = argc; + argv[argc] = pch; + ++argc; + pch = strtok_r(NULL, " ", &save); + } + argv[argc] = NULL; + + if (c->offset && c->buffer[c->offset-1] == ' ' && argc) { + cursor++; + } + + char * word = argv[cursor]; + int word_offset = word ? (c->offset - (argv[cursor] - dup)) : 0; + + char * prefix = malloc(word_offset + 1); + if (word) memcpy(prefix, word, word_offset); + prefix[word_offset] = '\0'; + + /* Complete file path */ + list_t * matches = list_create(); + char * match = NULL; + int free_matches = 0; + int no_space_if_only = 0; + + /* TODO custom auto-complete as a configuration file? */ +#define COMPLETE_FILE 1 +#define COMPLETE_COMMAND 2 +#define COMPLETE_CUSTOM 3 +#define COMPLETE_VARIABLE 4 + int complete_mode = COMPLETE_FILE; + int with_dollar = 0; + + int command_adj = 0; + int cursor_adj = cursor; + + /* sudo should shift commands */ + if (cursor_adj > command_adj && (!strcmp(argv[command_adj], "sudo") || !strcmp(argv[command_adj], "gsudo"))) { + cursor_adj -= 1; + command_adj += 1; + } + + /* initial tab completion should be commands, unless typing a file path */ + if (cursor_adj == 0 && !strchr(prefix,'/')) { + complete_mode = COMPLETE_COMMAND; + } + + if (cursor_adj >= 1 && !strcmp(argv[command_adj], "toggle-abs-mouse")) { + complete_mode = COMPLETE_CUSTOM; + } + + if (cursor_adj >= 1 && !strcmp(argv[command_adj], "unset")) { + complete_mode = COMPLETE_VARIABLE; + } + + /* complete variable names */ + if (*prefix == '$') { + complete_mode = COMPLETE_VARIABLE; + with_dollar = 1; + } + + if (complete_mode == COMPLETE_COMMAND) { + /* Complete a command name */ + + for (int i = 0; i < shell_commands_len; ++i) { + if (strstr(shell_commands[i], prefix) == shell_commands[i]) { + list_insert(matches, shell_commands[i]); + match = shell_commands[i]; + } + } + } else if (complete_mode == COMPLETE_FILE) { + /* Complete a file path */ + + free_matches = 1; + char * tmp = strdup(prefix); + char * last_slash = strrchr(tmp, '/'); + DIR * dirp; + char * compare = prefix; + if (last_slash) { + *last_slash = '\0'; + word = word + (last_slash - tmp) + 1; + word_offset = word_offset - (last_slash - tmp + 1); + compare = word; + if (last_slash == tmp) { + dirp = opendir("/"); + } else { + dirp = opendir(tmp); + } + } else { + dirp = opendir("."); + } + + if (!dirp) { + free(tmp); + goto finish_tab; + } + + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (ent->d_name[0] != '.' || compare[0] == '.') { + if (!word || strstr(ent->d_name, compare) == ent->d_name) { + struct stat statbuf; + /* stat it */ + if (last_slash) { + char * x = malloc(strlen(tmp) + 1 + strlen(ent->d_name) + 1); + sprintf(x,"%s/%s",tmp,ent->d_name); + lstat(x, &statbuf); + free(x); + } else { + lstat(ent->d_name, &statbuf); + } + char * s; + if (S_ISDIR(statbuf.st_mode)) { + s = malloc(strlen(ent->d_name) + 2); + sprintf(s,"%s/", ent->d_name); + no_space_if_only = 1; + } else { + s = strdup(ent->d_name); + } + list_insert(matches, s); + match = s; + } + } + ent = readdir(dirp); + } + closedir(dirp); + + free(tmp); + } else if (complete_mode == COMPLETE_CUSTOM) { + + char ** completions = NULL; + char * toggle_abs_mouse_completions[] = {"relative","absolute",NULL}; + + if (!strcmp(argv[command_adj],"toggle-abs-mouse")) { + completions = toggle_abs_mouse_completions; + } + + while (*completions) { + if (strstr(*completions, prefix) == *completions) { + list_insert(matches, *completions); + match = *completions; + } + completions++; + } + + } else if (complete_mode == COMPLETE_VARIABLE) { + + char ** envvar = environ; + free_matches = 1; + + while (*envvar) { + char * tmp = strdup(*envvar); + char * c = strchr(tmp, '='); + *c = '\0'; + if (strstr(tmp, prefix+with_dollar) == tmp) { + char * m = malloc(strlen(tmp)+1+with_dollar); + sprintf(m, "%s%s", with_dollar ? "$" : "", tmp); + list_insert(matches, m); + match = m; + } + free(tmp); + envvar++; + } + + } + + if (matches->length == 1) { + /* Insert */ + rline_insert(c, &match[word_offset]); + if (word && word_offset == (int)strlen(word) && !no_space_if_only) { + rline_insert(c, " "); + } + rline_redraw(c); + } else if (matches->length > 1) { + if (!c->tabbed) { + /* see if there is a minimum subset we can fill in */ + size_t j = word_offset; + do { + char d = match[j]; + int diff = 0; + foreach(node, matches) { + char * match = (char *)node->value; + if (match[j] != d || match[j] == '\0') diff = 1; + } + if (diff) break; + j++; + } while (j < (size_t)c->requested); + if (j > (size_t)word_offset) { + char * tmp = strdup(match); + tmp[j] = '\0'; + rline_insert(c, &tmp[word_offset]); + rline_redraw(c); + free(tmp); + } else { + c->tabbed = 1; + } + } else { + /* Print matches */ + fprintf(stderr,"\n\033[0m"); + size_t j = 0; + foreach(node, matches) { + char * match = (char *)node->value; + fprintf(stderr, "%s", match); + ++j; + if (j < matches->length) { + fprintf(stderr, ", "); + } + } + fprintf(stderr,"\n"); + c->callbacks->redraw_prompt(c); + fprintf(stderr, "\033[s"); + rline_redraw(c); + } + } + +finish_tab: + if (free_matches) list_destroy(matches); + list_free(matches); + free(prefix); + free(dup); + +} + +void add_argument(list_t * argv, char * buf) { + char * c = malloc(strlen(buf) + 1); + memcpy(c, buf, strlen(buf) + 1); + + list_insert(argv, c); +} + +int read_entry(char * buffer) { + if (experimental_rline) { + char lprompt[1024], rprompt[1024]; + int lwidth, rwidth; + + char * ps1 = getenv("PS1_LEFT"); + print_extended_ps(ps1 ? ps1 : FALLBACK_PS1, lprompt, &lwidth); + + char * ps1r = getenv("PS1_RIGHT"); + print_extended_ps(ps1r ? ps1r : "", rprompt, &rwidth); + + rline_exit_string="exit"; + rline_exp_set_syntax("esh"); + rline_exp_set_prompts(lprompt, rprompt, lwidth, rwidth); + rline_exp_set_shell_commands(shell_commands, shell_commands_len); + rline_exp_set_tab_complete_func(tab_complete_func); + return rline_experimental(buffer, LINE_LEN); + } else { + rline_callbacks_t callbacks = { + tab_complete_func, redraw_prompt_func, NULL, + NULL, NULL, NULL, NULL, NULL + }; + draw_prompt(); + return rline((char *)buffer, LINE_LEN, &callbacks); + } +} + +int read_entry_continued(char * buffer) { + if (experimental_rline) { + rline_exit_string="exit"; + rline_exp_set_syntax("esh"); + rline_exp_set_prompts("> ", "", 2, 0); + rline_exp_set_shell_commands(shell_commands, shell_commands_len); + rline_exp_set_tab_complete_func(tab_complete_func); + return rline_experimental(buffer, LINE_LEN); + } else { + rline_callbacks_t callbacks = { + tab_complete_func, redraw_prompt_func_c, NULL, + NULL, NULL, NULL, NULL, NULL + }; + draw_prompt_c(); + return rline((char *)buffer, LINE_LEN, &callbacks); + } +} + +int variable_char(uint8_t c) { + if (c >= 'A' && c <= 'Z') return 1; + if (c >= 'a' && c <= 'z') return 1; + if (c >= '0' && c <= '9') return 1; + if (c == '_') return 1; + if (c == '?') return 1; + return 0; +} + +struct alternative { + const char * command; + const char * replacement; + const char * description; +}; + +#define ALT_BIM "bim", "vi-like text editor" +#define ALT_FETCH "fetch", "URL downloader" +#define ALT_NETIF "cat /proc/netif", "to see network configuration" + +static struct alternative cmd_alternatives[] = { + /* Propose bim as an alternative for common text editors */ + {"vim", ALT_BIM}, + {"vi", ALT_BIM}, + {"emacs", ALT_BIM}, + {"nano", ALT_BIM}, + + /* Propose fetch for some common URL-getting tools */ + {"curl", ALT_FETCH}, + {"wget", ALT_FETCH}, + + /* We don't have ip or ifconfig commands, suggest cat /proc/netif */ + {"ifconfig", ALT_NETIF}, + {"ipconfig", ALT_NETIF}, + {"ip", ALT_NETIF}, + + /* Some random other stuff */ + {"grep", "fgrep", "non-regex-capable grep"}, + {"more", "bim -", "paging to a text editor"}, + {"less", "bim -", "paging to a text editor"}, + + {NULL, NULL, NULL}, +}; + +void run_cmd(char ** args) { + int i = execvp(*args, args); + shell_command_t func = shell_find(*args); + if (func) { + int argc = 0; + while (args[argc]) { + argc++; + } + i = func(argc, args); + } else { + if (i != 0) { + fprintf(stderr, "%s: Command not found\n", *args); + for (struct alternative * alt = cmd_alternatives; alt->command; alt++) { + if (!strcmp(*args, alt->command)) { + fprintf(stderr, "Consider this alternative:\n\n\t%s -- \033[3m%s\033[0m\n\n", + alt->replacement, + alt->description); + break; + } + } + i = 127; + } + } + exit(i); +} + +int is_number(const char * c) { + while (*c) { + if (!isdigit(*c)) return 0; + c++; + } + return 1; +} + +/** + * Prints "Segmentation fault", etc. + */ +static void handle_status(int ret_code) { + if (WIFSIGNALED(ret_code)) { + char str[256] = {0}; + + switch (WTERMSIG(ret_code)) { + case SIGILL: + sprintf(str, "Illegal instruction"); + break; + case SIGSEGV: + sprintf(str, "Segmentation fault"); + break; + case SIGINT: + /* Do nothing */ + return; + case SIGPIPE: + /* Do nothing */ + return; + default: + sprintf(str, "Killed by unhandled signal %d",WTERMSIG(ret_code)); + break; + } + + if (shell_interactive == 1) { + fprintf(stderr, "%s\n", str); + } else if (shell_interactive == 2) { + fprintf(stderr, "%s: line %d: %s\n", current_file, current_line, str); + } + } +} + +int shell_exec(char * buffer, size_t size, FILE * file, char ** out_buffer) { + + *out_buffer = NULL; + + /* Read previous history entries */ + if (buffer[0] == '!') { + int x = atoi((char *)((uintptr_t)buffer + 1)); + if (x > 0 && x <= rline_history_count) { + buffer = rline_history_get(x - 1); + } else { + fprintf(stderr, "esh: !%d: event not found\n", x); + return 0; + } + } + + char * argv[1024]; + int tokenid = 0; + + char quoted = 0; + char backtick = 0; + char buffer_[512] = {0}; + int collected = 0; + int force_collected = 0; + + list_t * args = list_create(); + int have_star = 0; + + while (1) { + + char * p = buffer; + + while (*p) { + switch (*p) { + case '$': + if (quoted == '\'') { + goto _just_add; + } else { + if (backtick) { + goto _just_add; + } + p++; + char var[100]; + int coll = 0; + if (*p == '{') { + p++; + while (*p != '}' && *p != '\0' && (coll < 100)) { + var[coll] = *p; + coll++; + var[coll] = '\0'; + p++; + } + if (*p == '}') { + p++; + } + } else { + while (*p != '\0' && variable_char(*p) && (coll < 100)) { + var[coll] = *p; + coll++; + var[coll] = '\0'; + if (coll == 0 && (isdigit(*p) || *p == '?')) { + p++; + break; /* Don't let these keep going */ + } + p++; + } + } + /* Special cases */ + char *c = NULL; + char tmp[128]; + if (!strcmp(var, "?")) { + sprintf(tmp,"%d",last_ret); + c = tmp; + } else if (is_number(var)) { + int a = atoi(var); + if (a >= 0 && a < shell_argc) { + c = shell_argv[a]; + } + } else { + c = getenv(var); + } + + if (c) { + backtick = 0; + for (int i = 0; i < (int)strlen(c); ++i) { + if (c[i] == ' ' && !quoted) { + /* If we are not quoted and we reach a space, it signals a new argument */ + if (collected || force_collected) { + buffer_[collected] = '\0'; + add_argument(args, buffer_); + buffer_[0] = '\0'; + have_star = 0; + collected = 0; + force_collected = 0; + } + } else { + buffer_[collected] = c[i]; + collected++; + } + } + buffer_[collected] = '\0'; + } + continue; + } + case '\"': + force_collected = 1; + if (quoted == '\"') { + if (backtick) { + goto _just_add; + } + quoted = 0; + goto _next; + } else if (!quoted) { + if (backtick) { + goto _just_add; + } + quoted = *p; + goto _next; + } + goto _just_add; + case '\'': + force_collected = 1; + if (quoted == '\'') { + if (backtick) { + goto _just_add; + } + quoted = 0; + goto _next; + } else if (!quoted) { + if (backtick) { + goto _just_add; + } + quoted = *p; + goto _next; + } + goto _just_add; + case '*': + if (quoted) { + goto _just_add; + } + if (backtick) { + goto _just_add; + } + if (have_star) { + goto _just_add; /* TODO multiple globs */ + } + have_star = 1; + collected += sprintf(&buffer_[collected], STAR_TOKEN); + goto _next; + case '\\': + if (quoted == '\'') { + goto _just_add; + } + if (backtick) { + goto _just_add; + } + backtick = 1; + goto _next; + case ' ': + if (backtick) { + goto _just_add; + } + if (!quoted) { + goto _new_arg; + } + goto _just_add; + case '\n': + if (!quoted) { + goto _done; + } + goto _just_add; + case '|': + if (!quoted && !backtick) { + if (collected || force_collected) { + add_argument(args, buffer_); + } + force_collected = 0; + collected = sprintf(buffer_, "%s", PIPE_TOKEN); + goto _new_arg; + } + goto _just_add; + case '>': + if (!quoted && !backtick) { + if (collected || force_collected) { + add_argument(args, buffer_); + } + force_collected = 0; + collected = sprintf(buffer_, "%s", WRITE_TOKEN); + goto _new_arg; + } + goto _just_add; + case ';': + if (!quoted && !backtick) { + *out_buffer = ++p; + goto _done; + } + case '#': + if (!quoted && !backtick) { + goto _done; /* Support comments; must not be part of an existing arg */ + } + goto _just_add; + default: + if (backtick) { + buffer_[collected] = '\\'; + collected++; + buffer_[collected] = '\0'; + } +_just_add: + backtick = 0; + buffer_[collected] = *p; + collected++; + buffer_[collected] = '\0'; + goto _next; + } + +_new_arg: + backtick = 0; + if (collected || force_collected) { + add_argument(args, buffer_); + buffer_[0] = '\0'; + have_star = 0; + collected = 0; + force_collected = 0; + } + +_next: + p++; + } + +_done: + + if (quoted || backtick) { + backtick = 0; + if (shell_interactive == 1) { + read_entry_continued(buffer); + rline_history_append_line(buffer); + continue; + } else if (shell_interactive == 2) { + fgets(buffer, size, file); + continue; + } else { + fprintf(stderr, "Syntax error: Unterminated quoted string.\n"); + return 127; + } + } + + if (collected || force_collected) { + add_argument(args, buffer_); + break; + } + + break; + } + + int cmdi = 0; + char ** arg_starts[100] = { &argv[0], NULL }; + char * output_files[100] = { NULL }; + int file_args[100] = {0}; + int argcs[100] = {0}; + int next_is_file = 0; + + int i = 0; + foreach(node, args) { + char * c = node->value; + + if (next_is_file) { + if (next_is_file == 1 && !strcmp(c, WRITE_TOKEN)) { + next_is_file = 2; + file_args[cmdi] = O_WRONLY | O_CREAT | O_APPEND; + continue; + } + output_files[cmdi] = c; + continue; + } + + if (!strcmp(c, WRITE_TOKEN)) { + next_is_file = 1; + file_args[cmdi] = O_WRONLY | O_CREAT | O_TRUNC; + continue; + } + + if (!strcmp(c, PIPE_TOKEN)) { + if (arg_starts[cmdi] == &argv[i]) { + fprintf(stderr, "Syntax error: Unexpected pipe token\n"); + return 2; + } + argv[i] = 0; + i++; + cmdi++; + arg_starts[cmdi] = &argv[i]; + continue; + } + + char * glob = strstr(c, STAR_TOKEN); + if (glob) { + /* Globbing */ + glob[0] = '\0'; + glob[1] = '\0'; + + char * before = c; + char * after = &glob[8]; + char * dir = NULL; + + int has_before = !!strlen(before); + int has_after = !!strlen(after); + + if (1) { + /* read current directory, add all */ + DIR * dirp; + char * prepend = ""; + if (has_before) { + dir = strrchr(before,'/'); + + if (!dir) { + dirp = opendir("."); + } else if (dir == before) { + dirp = opendir("/"); + prepend = before; + before++; + } else { + *dir = '\0'; + dirp = opendir(before); + prepend = before; + before = dir+1; + } + } else { + dirp = opendir("."); + } + + int before_i = i; + if (dirp) { + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (ent->d_name[0] != '.') { + char * s = malloc(sizeof(char) * (strlen(ent->d_name) + 1)); + memcpy(s, ent->d_name, strlen(ent->d_name) + 1); + + char * t = s; + + if (has_before) { + if (strstr(s,before) != s) { + free(s); + goto _nope; + } + t = &s[strlen(before)]; + } + if (has_after) { + if (strlen(t) >= strlen(after)) { + if (!strcmp(after,&t[strlen(t)-strlen(after)])) { + char * out = malloc(strlen(s) + 2 + strlen(prepend)); + sprintf(out,"%s%s%s", prepend, !!*prepend ? "/" : "", s); + argv[i] = out; + i++; + argcs[cmdi]++; + } + } + } else { + char * out = malloc(strlen(s) + 2 + strlen(prepend)); + sprintf(out,"%s%s%s", prepend, !!*prepend ? "/" : "", s); + argv[i] = out; + i++; + argcs[cmdi]++; + } + free(s); + } +_nope: + ent = readdir(dirp); + } + closedir(dirp); + } + + if (before_i == i) { + /* no matches */ + glob[0] = '*'; + if (dir) { + *dir = '/'; + } + memmove(&glob[1], after, strlen(after)+1); + argv[i] = c; + i++; + argcs[cmdi]++; + } else { + free(c); + } + } + } else { + argv[i] = c; + i++; + argcs[cmdi]++; + } + } + argv[i] = NULL; + + if (i == 0) { + return -1; + } + + list_free(args); + + if (!*arg_starts[cmdi]) { + fprintf(stderr, "Syntax error: Unexpected end of input\n"); + return 2; + } + + char * cmd = *arg_starts[0]; + tokenid = i; + + unsigned int child_pid; + int last_child; + + int nowait = (!strcmp(argv[tokenid-1],"&")); + if (nowait) { + argv[tokenid-1] = NULL; + } + + if (cmdi > 0) { + int last_output[2]; + pipe(last_output); + child_pid = fork(); + if (!child_pid) { + dup2(last_output[1], STDOUT_FILENO); + close(last_output[0]); + run_cmd(arg_starts[0]); + } + + for (int j = 1; j < cmdi; ++j) { + int tmp_out[2]; + pipe(tmp_out); + if (!fork()) { + dup2(tmp_out[1], STDOUT_FILENO); + dup2(last_output[0], STDIN_FILENO); + close(tmp_out[0]); + close(last_output[1]); + run_cmd(arg_starts[j]); + } + close(last_output[0]); + close(last_output[1]); + last_output[0] = tmp_out[0]; + last_output[1] = tmp_out[1]; + } + + last_child = fork(); + if (!last_child) { + if (output_files[cmdi]) { + int fd = open(output_files[cmdi], file_args[cmdi], 0666); + if (fd < 0) { + fprintf(stderr, "sh: %s: %s\n", output_files[cmdi], strerror(errno)); + return -1; + } else { + dup2(fd, STDOUT_FILENO); + } + } + dup2(last_output[0], STDIN_FILENO); + close(last_output[1]); + run_cmd(arg_starts[cmdi]); + } + close(last_output[0]); + close(last_output[1]); + + /* Now execute the last piece and wait on all of them */ + } else { + shell_command_t func = shell_find(*arg_starts[0]); + if (func) { + return func(argcs[0], arg_starts[0]); + } else { + child_pid = fork(); + if (!child_pid) { + if (output_files[cmdi]) { + int fd = open(output_files[cmdi], file_args[cmdi], 0666); + if (fd < 0) { + fprintf(stderr, "sh: %s: %s\n", output_files[cmdi], strerror(errno)); + return -1; + } else { + dup2(fd, STDOUT_FILENO); + } + } + run_cmd(arg_starts[0]); + } + last_child = child_pid; + } + } + + tcsetpgrp(STDIN_FILENO, child_pid); + int ret_code = 0; + if (!nowait) { + child = child_pid; + int pid; + int tmp; + do { + pid = waitpid(-1, &tmp, 0); + if (pid == last_child) ret_code = tmp; + } while (pid != -1 || (pid == -1 && errno != ECHILD)); + child = 0; + } + tcsetpgrp(STDIN_FILENO, getpid()); + free(cmd); + + handle_status(ret_code); + return WEXITSTATUS(ret_code); +} + +void add_path_contents(char * path) { + DIR * dirp = opendir(path); + + if (!dirp) return; /* Failed to load directly */ + + struct dirent * ent = readdir(dirp); + while (ent != NULL) { + if (ent->d_name[0] != '.') { + char * s = malloc(sizeof(char) * (strlen(ent->d_name) + 1)); + memcpy(s, ent->d_name, strlen(ent->d_name) + 1); + shell_install_command(s, NULL, NULL); + } + + ent = readdir(dirp); + } + closedir(dirp); + +} + +struct command { + char * string; + void * func; + char * desc; +}; + +static int comp_shell_commands(const void *p1, const void *p2) { + return strcmp(((struct command *)p1)->string, ((struct command *)p2)->string); +} + +void sort_commands() { + struct command commands[SHELL_COMMANDS]; + for (int i = 0; i < shell_commands_len; ++i) { + commands[i].string = shell_commands[i]; + commands[i].func = shell_pointers[i]; + commands[i].desc = shell_descript[i]; + } + qsort(&commands, shell_commands_len, sizeof(struct command), comp_shell_commands); + for (int i = 0; i < shell_commands_len; ++i) { + shell_commands[i] = commands[i].string; + shell_pointers[i] = commands[i].func; + shell_descript[i] = commands[i].desc; + } +} + +void show_version(void) { + printf("esh 1.3.0\n"); +} + +void show_usage(int argc, char * argv[]) { + printf( + "Esh: The Experimental Shell\n" + "\n" + "usage: %s [-lha] [path]\n" + "\n" + " -c \033[4mcmd\033[0m \033[3mparse and execute cmd\033[0m\n" + //-c cmd \033[... + " -R \033[3mdisable experimental line editor\033[0m\n" + " -v \033[3mshow version information\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); +} + +void add_path(void) { + + char * envvar = getenv("PATH"); + + if (!envvar) { + add_path_contents("/bin"); + return; + } + + char * tmp = strdup(envvar); + + do { + char * end = strstr(tmp,":"); + if (end) { + *end = '\0'; + end++; + } + add_path_contents(tmp); + tmp = end; + } while (tmp); + + free(tmp); +} + +int run_script(FILE * f) { + current_line = 1; + while (!feof(f)) { + char buf[LINE_LEN] = {0}; + fgets(buf, LINE_LEN, f); + int ret; + char * out = NULL; + char * b = buf; + do { + ret = shell_exec(b, LINE_LEN, f, &out); + b = out; + } while (b); + current_line++; + if (ret >= 0) last_ret = ret; + } + + fclose(f); + + return last_ret; +} + +void source_eshrc(void) { + char * home = getenv("HOME"); + + if (!home) return; + + char tmp[512]; + sprintf(tmp, "%s/.eshrc", home); + + FILE * f = fopen(tmp, "r"); + if (!f) return; + + current_file = tmp; + run_script(f); +} + +int main(int argc, char ** argv) { + + pid = getpid(); + + signal(SIGINT, sig_pass); + signal(SIGWINCH, sig_pass); + + getuser(); + gethost(); + + install_commands(); + /* Parse $PATH to add contents */ + add_path(); + sort_commands(); + + if (argc > 1) { + int c; + while ((c = getopt(argc, argv, "Rc:v?")) != -1) { + switch (c) { + case 'R': + experimental_rline = 0; + break; + case 'c': + shell_interactive = 0; + { + char * out = NULL; + do { + last_ret = shell_exec(optarg, strlen(optarg), NULL, &out); + optarg = out; + } while (optarg); + } + return (last_ret == -1) ? 0 : last_ret; + case 'v': + show_version(); + return 0; + case '?': + show_usage(argc, argv); + return 0; + } + } + } + + if (optind < argc) { + shell_interactive = 2; + FILE * f = fopen(argv[optind],"r"); + + if (!f) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + return 1; + } + + shell_argc = argc - 1; + shell_argv = &argv[optind]; + current_file = argv[optind]; + + return run_script(f); + } + + shell_interactive = 1; + + source_eshrc(); + + while (1) { + char buffer[LINE_LEN] = {0}; + + read_entry(buffer); + + char * history = malloc(strlen(buffer) + 1); + memcpy(history, buffer, strlen(buffer) + 1); + + if (buffer[0] != ' ' && buffer[0] != '\n' && buffer[0] != '!') { + rline_history_insert(history); + } else { + free(history); + } + + int ret; + char * out = NULL; + char * b = buffer; + do { + ret = shell_exec(b, LINE_LEN, stdin, &out); + b = out; + } while (b); + if (ret >= 0) last_ret = ret; + rline_scroll = 0; + } + + return 0; +} + +/* + * cd [path] + */ +uint32_t shell_cmd_cd(int argc, char * argv[]) { + if (argc > 1) { + if (chdir(argv[1])) { + goto cd_error; + } /* else success */ + } else /* argc < 2 */ { + char * home = getenv("HOME"); + if (home) { + if (chdir(home)) { + goto cd_error; + } + } else { + char home_path[512]; + sprintf(home_path, "/home/%s", username); + if (chdir(home_path)) { + goto cd_error; + } + } + } + return 0; +cd_error: + fprintf(stderr, "%s: could not cd '%s': no such file or directory\n", argv[0], argv[1]); + return 1; +} + +/* + * history + */ +uint32_t shell_cmd_history(int argc, char * argv[]) { + for (int i = 0; i < rline_history_count; ++i) { + printf("%d\t%s\n", i + 1, rline_history_get(i)); + } + return 0; +} + +uint32_t shell_cmd_export(int argc, char * argv[]) { + if (argc > 1) { + putenv(argv[1]); + } + return 0; +} + +uint32_t shell_cmd_exit(int argc, char * argv[]) { + if (argc > 1) { + exit(atoi(argv[1])); + } else { + exit(0); + } + return -1; +} + +uint32_t shell_cmd_help(int argc, char * argv[]) { + show_version(); + printf("\nThis shell is not POSIX-compliant, please be careful.\n\n"); + printf("Built-in commands:\n"); + + /* First, determine max width of command names */ + unsigned int max_len = 0; + for (int i = 0; i < shell_commands_len; ++i) { + if (!shell_descript[i]) continue; + if (strlen(shell_commands[i]) > max_len) { + max_len = strlen(shell_commands[i]); + } + } + + /* Then print the commands their help text */ + for (int i = 0; i < shell_commands_len; ++i) { + if (!shell_descript[i]) continue; + printf(" %-*s - %s\n", max_len + 1, shell_commands[i], shell_descript[i]); + } + + return 0; +} + +uint32_t shell_cmd_if(int argc, char * argv[]) { + char ** if_args = &argv[1]; + char ** then_args = NULL; + char ** else_args = NULL; + + for (int i = 2; i < argc; ++i) { + if (!strcmp(argv[i],"then")) { + argv[i] = NULL; + then_args = &argv[i+1]; + } else if (!strcmp(argv[i],"else")) { + argv[i] = NULL; + else_args = &argv[i+1]; + } + } + + if (!then_args) { + fprintf(stderr, "%s: syntax error: expected 'then' clause\n", argv[0]); + return 1; + } + + if (else_args && else_args < then_args) { + fprintf(stderr, "%s: syntax error: 'else' clause before 'then' clase\n", argv[0]); + return 1; + } + + pid_t child_pid = fork(); + if (!child_pid) { + run_cmd(if_args); + } + tcsetpgrp(STDIN_FILENO, child_pid); + + child = child_pid; + + int pid, ret_code = 0; + do { + pid = waitpid(-1, &ret_code, 0); + } while (pid != -1 || (pid == -1 && errno != ECHILD)); + + child = 0; + + handle_status(ret_code); + + if (WEXITSTATUS(ret_code) == 0) { + shell_command_t func = shell_find(*then_args); + if (func) { + int argc = 0; + while (then_args[argc]) { + argc++; + } + return func(argc, then_args); + } else { + child_pid = fork(); + if (!child_pid) { + run_cmd(then_args); + } + tcsetpgrp(STDIN_FILENO, child_pid); + child = child_pid; + do { + pid = waitpid(-1, &ret_code, 0); + } while (pid != -1 || (pid == -1 && errno != ECHILD)); + child = 0; + tcsetpgrp(STDIN_FILENO, getpid()); + handle_status(ret_code); + return WEXITSTATUS(ret_code); + } + } else if (else_args) { + shell_command_t func = shell_find(*else_args); + if (func) { + int argc = 0; + while (else_args[argc]) { + argc++; + } + return func(argc, else_args); + } else { + child_pid = fork(); + if (!child_pid) { + run_cmd(else_args); + } + tcsetpgrp(STDIN_FILENO, child_pid); + child = child_pid; + do { + pid = waitpid(-1, &ret_code, 0); + } while (pid != -1 || (pid == -1 && errno != ECHILD)); + child = 0; + handle_status(ret_code); + return WEXITSTATUS(ret_code); + } + } + + tcsetpgrp(STDIN_FILENO, getpid()); + return 0; +} + +uint32_t shell_cmd_while(int argc, char * argv[]) { + char ** while_args = &argv[1]; + char ** do_args = NULL; + + for (int i = 2; i < argc; ++i) { + if (!strcmp(argv[i],"do")) { + argv[i] = NULL; + do_args = &argv[i+1]; + } + } + + if (!do_args) { + fprintf(stderr, "%s: syntax error: expected 'do' clause\n", argv[0]); + return 1; + } + + break_while = 0; + tcsetpgrp(STDIN_FILENO, getpid()); + + do { + pid_t child_pid = fork(); + if (!child_pid) { + run_cmd(while_args); + } + child = child_pid; + + int pid, ret_code = 0; + do { + pid = waitpid(-1, &ret_code, 0); + } while (pid != -1 || (pid == -1 && errno != ECHILD)); + child = 0; + + handle_status(ret_code); + if (WEXITSTATUS(ret_code) == 0) { + child_pid = fork(); + if (!child_pid) { + run_cmd(do_args); + } + child = child_pid; + do { + pid = waitpid(-1, &ret_code, 0); + } while (pid != -1 || (pid == -1 && errno != ECHILD)); + child = 0; + } else { + return WEXITSTATUS(ret_code); + } + } while (!break_while); + + return 127; +} + +uint32_t shell_cmd_export_cmd(int argc, char * argv[]) { + + if (argc < 3) { + fprintf(stderr, "%s: syntax error: not enough arguments\n", argv[0]); + return 1; + } + + int pipe_fds[2]; + pipe(pipe_fds); + pid_t child_pid = fork(); + if (!child_pid) { + dup2(pipe_fds[1], STDOUT_FILENO); + close(pipe_fds[0]); + run_cmd(&argv[2]); + } + + close(pipe_fds[1]); + + tcsetpgrp(STDIN_FILENO, child_pid); + char buf[1024]; + size_t accum = 0; + + do { + int r = read(pipe_fds[0], buf+accum, 1023-accum); + + if (r == 0) break; + if (r < 0) { + return -r; + } + + accum += r; + } while (accum < 1023); + + tcsetpgrp(STDIN_FILENO, getpid()); + + buf[accum] = '\0'; + + if (accum && buf[accum-1] == '\n') { + buf[accum-1] = '\0'; + } + + setenv(argv[1], buf, 1); + return 0; +} + +uint32_t shell_cmd_empty(int argc, char * argv[]) { + + for (int i = 1; i < argc; i++) { + if (argv[i] && *argv[i]) return 1; + } + + return 0; +} + +uint32_t shell_cmd_equals(int argc, char * argv[]) { + + if (argc < 3) return 1; + + return strcmp(argv[1], argv[2]); +} + +uint32_t shell_cmd_return(int argc, char * argv[]) { + if (argc < 2) return 0; + + return atoi(argv[1]); +} + +uint32_t shell_cmd_source(int argc, char * argv[]) { + if (argc < 2) return 0; + + FILE * f = fopen(argv[1], "r"); + + if (!f) { + fprintf(stderr, "%s: %s: %s", argv[0], argv[1], strerror(errno)); + } + + current_file = argv[1]; + return run_script(f); +} + +uint32_t shell_cmd_exec(int argc, char * argv[]) { + if (argc < 2) return 1; + return execvp(argv[1], &argv[1]); +} + +uint32_t shell_cmd_not(int argc, char * argv[]) { + if (argc < 2) { + fprintf(stderr, "%s: expected command argument\n", argv[0]); + return 1; + } + int ret_code = 0; + pid_t child_pid = fork(); + if (!child_pid) { + run_cmd(&argv[1]); + } + tcsetpgrp(STDIN_FILENO, child_pid); + child = child_pid; + do { + pid = waitpid(-1, &ret_code, 0); + } while (pid != -1 || (pid == -1 && errno != ECHILD)); + child = 0; + tcsetpgrp(STDIN_FILENO, getpid()); + handle_status(ret_code); + return !WEXITSTATUS(ret_code); +} + +uint32_t shell_cmd_unset(int argc, char * argv[]) { + if (argc < 2) { + fprintf(stderr, "%s: expected command argument\n", argv[0]); + return 1; + } + + return unsetenv(argv[1]); +} + +void install_commands() { + shell_commands = malloc(sizeof(char *) * SHELL_COMMANDS); + shell_pointers = malloc(sizeof(shell_command_t) * SHELL_COMMANDS); + shell_descript = malloc(sizeof(char *) * SHELL_COMMANDS); + + shell_install_command("cd", shell_cmd_cd, "change directory"); + shell_install_command("exit", shell_cmd_exit, "exit the shell"); + shell_install_command("export", shell_cmd_export, "set environment variables: export VAR=value"); + shell_install_command("help", shell_cmd_help, "display this help text"); + shell_install_command("history", shell_cmd_history, "list command history"); + shell_install_command("if", shell_cmd_if, "if ... then ... [else ...]"); + shell_install_command("while", shell_cmd_while, "while ... do ..."); + shell_install_command("empty?", shell_cmd_empty, "empty? args..."); + shell_install_command("equals?", shell_cmd_equals, "equals? arg1 arg2"); + shell_install_command("return", shell_cmd_return, "return status code"); + shell_install_command("export-cmd", shell_cmd_export_cmd, "set variable to result of command: export-cmd VAR command..."); + shell_install_command("source", shell_cmd_source, "run a shell script in the context of this shell"); + shell_install_command("exec", shell_cmd_exec, "replace shell (or subshell) with command"); + shell_install_command("not", shell_cmd_not, "invert status of command"); + shell_install_command("unset", shell_cmd_unset, "unset variable"); +} diff --git a/userspace/core/sleep.c b/apps/sleep.c similarity index 67% rename from userspace/core/sleep.c rename to apps/sleep.c index a715237a..383b3cd6 100644 --- a/userspace/core/sleep.c +++ b/apps/sleep.c @@ -1,13 +1,14 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * Sleep + * Copyright (C) 2013 K. Lange + * + * sleep - Do nothing, efficiently. */ #include #include #include +#include int main(int argc, char ** argv) { int ret = 0; @@ -24,8 +25,3 @@ int main(int argc, char ** argv) { return ret; } -/* - * vim:tabstop=4 - * vim:noexpandtab - * vim:shiftwidth=4 - */ diff --git a/apps/sort.c b/apps/sort.c new file mode 100644 index 00000000..970b638d --- /dev/null +++ b/apps/sort.c @@ -0,0 +1,100 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * sort - Sort standard in or files. + * + * Currently implemented with a naive insertion sort. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +int compare(const char * a, const char * b) { + while (1) { + while (*a == *b || tolower(*a) == tolower(*b)) { + if (!*a) return 0; + a++; + b++; + } + + while (*a && !isalnum(*a)) a++; + while (*b && !isalnum(*b)) b++; + + if (tolower(*a) == tolower(*b)) continue; + + if (tolower(*a) < tolower(*b)) return -1; + return 1; + } +} + +int main(int argc, char * argv[]) { + int reverse = 0; + int opt; + + list_t * lines = list_create(); + list_t * files = list_create(); + + while ((opt = getopt(argc, argv, "r")) != -1) { + switch (opt) { + case 'r': + reverse = 1; + break; + } + } + + if (optind == argc) { + /* No arguments */ + list_insert(files, stdin); + } else { + while (optind < argc) { + FILE * f = fopen(argv[optind], "r"); + if (!f) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + } else { + list_insert(files, f); + } + optind++; + } + } + + char line_buf[4096] = {0}; + foreach (node, files) { + FILE * f = node->value; + while (!feof(f)) { + if (!fgets(line_buf, 4096, f)) { + break; + } + if (!strchr(line_buf,'\n')) { + fprintf(stderr, "%s: oversized line\n", argv[0]); + } + char * line = strdup(line_buf); + node_t * next = NULL; + foreach (lnode, lines) { + char * cmp = lnode->value; + if (reverse ? (compare(cmp, line) < 0) : (compare(line, cmp) < 0)) { + next = lnode; + break; + } + } + if (next) { + list_insert_before(lines, next, line); + } else { + list_insert(lines, line); + } + } + } + + foreach (lnode, lines) { + char * line = lnode->value; + fprintf(stdout, "%s", line); + } + + return 0; +} diff --git a/apps/stat.c b/apps/stat.c new file mode 100644 index 00000000..4b7b3e1d --- /dev/null +++ b/apps/stat.c @@ -0,0 +1,92 @@ +/* vim: ts=4 sw=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * stat + * + * Display file status. + */ +#include +#include +#include +#include + +#include +#include + +static void show_usage(int argc, char * argv[]) { + printf( + "stat - display file status\n" + "\n" + "usage: %s [-Lq] PATH\n" + "\n" + " -L \033[3mdereference symlinks\033[0m\n" + " -q \033[3mdon't print anything, just return 0 if file exists\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); +} + +int main(int argc, char ** argv) { + int dereference = 0, quiet = 0; + char * file; + int opt; + + while ((opt = getopt(argc, argv, "?Lq")) != -1) { + switch (opt) { + case 'L': + dereference = 1; + break; + case 'q': + quiet = 1; + break; + case '?': + show_usage(argc,argv); + return 1; + } + } + + if (optind >= argc) { + show_usage(argc, argv); + return 1; + } + + file = argv[optind]; + + struct stat _stat; + if (dereference) { + if (stat(file, &_stat) < 0) return 1; + } else { + if (lstat(file, &_stat) < 0) return 1; + } + + if (quiet) return 0; + + printf("0x%x bytes\n", (unsigned int)_stat.st_size); + + if (S_ISDIR(_stat.st_mode)) { + printf("Is a directory.\n"); + } else if (S_ISFIFO(_stat.st_mode)) { + printf("Is a pipe.\n"); + } else if (S_ISLNK(_stat.st_mode)) { + printf("Is a symlink.\n"); + } else if (_stat.st_mode & 0111) { + printf("Is executable.\n"); + } + + struct stat * f = &_stat; + + printf("st_dev 0x%x %d\n", (unsigned int)f->st_dev , (unsigned int)sizeof(f->st_dev )); + printf("st_ino 0x%x %d\n", (unsigned int)f->st_ino , (unsigned int)sizeof(f->st_ino )); + printf("st_mode 0x%x %d\n", (unsigned int)f->st_mode , (unsigned int)sizeof(f->st_mode )); + printf("st_nlink 0x%x %d\n", (unsigned int)f->st_nlink , (unsigned int)sizeof(f->st_nlink )); + printf("st_uid 0x%x %d\n", (unsigned int)f->st_uid , (unsigned int)sizeof(f->st_uid )); + printf("st_gid 0x%x %d\n", (unsigned int)f->st_gid , (unsigned int)sizeof(f->st_gid )); + printf("st_rdev 0x%x %d\n", (unsigned int)f->st_rdev , (unsigned int)sizeof(f->st_rdev )); + printf("st_size 0x%x %d\n", (unsigned int)f->st_size , (unsigned int)sizeof(f->st_size )); + + printf("0x%x\n", (unsigned int)((uint32_t *)f)[0]); + + return 0; +} + diff --git a/apps/stty.c b/apps/stty.c new file mode 100644 index 00000000..4648568a --- /dev/null +++ b/apps/stty.c @@ -0,0 +1,330 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + */ +#include +#include +#include +#include +#include +#include +#include + +static int hide_defaults = 1; +static int printed = 0; + +static void print_cc(struct termios * t, const char * lbl, int val, int def) { + int c = t->c_cc[val]; + if (hide_defaults && c == def) return; + if (!c) { + fprintf(stdout, "%s = ; ", lbl); + } else if (c < 32) { + fprintf(stdout, "%s = ^%c; ", lbl, '@' + c); + } else { + fprintf(stdout, "%s = %c; ", lbl, c); + } + printed = 1; +} + +static void print_(int flags, const char * lbl, int val, int def) { + int c = !!(flags & val); + if (!hide_defaults || c != def) { + fprintf(stdout, "%s%s ", c ? "" : "-", lbl); + printed = 1; + } +} + +#define print_cflag(lbl,val,def) print_(t.c_cflag, lbl, val, def) +#define print_iflag(lbl,val,def) print_(t.c_iflag, lbl, val, def) +#define print_oflag(lbl,val,def) print_(t.c_oflag, lbl, val, def) +#define print_lflag(lbl,val,def) print_(t.c_lflag, lbl, val, def) + +static void set_char_(struct termios *t, const char * lbl, int val, const char * cmp, const char * arg, int * i) { + if (!strcmp(cmp, lbl)) { + if (!arg) { + fprintf(stderr, "%s: expected argument\n", lbl); + exit(1); + } + /* Parse arg */ + if (strlen(arg) == 1) { + /* Assume raw character */ + t->c_cc[val] = *arg; + } else if (*arg == '^') { /* ^c, etc. */ + int v = toupper(arg[1]); + t->c_cc[val] = v - '@'; + } else { + /* Assume decimal for now */ + int v = atoi(arg); + t->c_cc[val] = v; + } + (*i)++; + } +} + +#define set_char(lbl,val) set_char_(&t, lbl, val, argv[i], argv[i+1], &i) + +static void setunset_flag(tcflag_t * flag, const char * lbl, int val, const char * cmp) { + if (*cmp == '-') { + if (!strcmp(cmp+1, lbl)) { + (*flag) = (*flag) & (~val); + } + } else { + if (!strcmp(cmp, lbl)) { + (*flag) = (*flag) | (val); + } + } +} + +#define set_cflag(lbl,val) setunset_flag(&(t.c_cflag), lbl, val, argv[i]) +#define set_iflag(lbl,val) setunset_flag(&(t.c_iflag), lbl, val, argv[i]) +#define set_oflag(lbl,val) setunset_flag(&(t.c_oflag), lbl, val, argv[i]) +#define set_lflag(lbl,val) setunset_flag(&(t.c_lflag), lbl, val, argv[i]) + +static void set_toggle_(tcflag_t * flag, const char * lbl, int base, int val, const char * cmp) { + if (!strcmp(cmp, lbl)) { + (*flag) = (*flag) & ~(base); + (*flag) = (*flag) | (val); + } +} + +#define set_ctoggle(lbl,base,val) set_toggle_(&(t.c_cflag), lbl, base, val, argv[i]) +#define set_otoggle(lbl,base,val) set_toggle_(&(t.c_oflag), lbl, base, val, argv[i]) + +static int show_settings(int all) { + /* Size */ + struct winsize w; + ioctl(STDERR_FILENO, TIOCGWINSZ, &w); + fprintf(stdout, "rows %d; columns %d; ypixels %d; xpixels %d;\n", w.ws_row, w.ws_col, w.ws_ypixel, w.ws_xpixel); + printed = 0; + + struct termios t; + tcgetattr(STDERR_FILENO, &t); + + /* Keys */ + print_cc(&t, "intr", VINTR, 3); + print_cc(&t, "quit", VQUIT, 28); + print_cc(&t, "erase", VERASE, '\b'); + print_cc(&t, "kill", VKILL, 21); + print_cc(&t, "eof", VEOF, 4); + print_cc(&t, "eol", VEOL, 0); + if (printed) { fprintf(stdout, "\n"); printed = 0; } + + print_cc(&t, "start", VSTART, 17); + print_cc(&t, "stop", VSTOP, 19); + print_cc(&t, "susp", VSUSP, 26); + + /* MIN, TIME */ + if (!hide_defaults || t.c_cc[VMIN] != 1) { fprintf(stdout, "min = %d; ", t.c_cc[VMIN]); printed = 1; } + if (!hide_defaults || t.c_cc[VTIME] != 0) { fprintf(stdout, "time = %d; ", t.c_cc[VTIME]); printed = 1; } + if (printed) { fprintf(stdout, "\n"); printed = 0; } + + switch ((t.c_cflag & CSIZE)) { + case CS5: fprintf(stdout, "cs5 "); printed = 1; break; + case CS6: fprintf(stdout, "cs6 "); printed = 1; break; + case CS7: fprintf(stdout, "cs7 "); printed = 1; break; + case CS8: if (!hide_defaults) { fprintf(stdout, "cs8 "); printed = 1; } break; + } + + print_cflag("cstopb", CSTOPB, 0); + print_cflag("cread", CREAD, 1); + print_cflag("parenb", PARENB, 0); + print_cflag("parodd", PARODD, 0); + print_cflag("hupcl", HUPCL, 0); + print_cflag("clocal", CLOCAL, 0); + if (printed) { fprintf(stdout, "\n"); printed = 0; } + + print_iflag("brkint", BRKINT, 1); + print_iflag("icrnl", ICRNL, 1); + print_iflag("ignbrk", IGNBRK, 0); + print_iflag("igncr", IGNCR, 0); + print_iflag("ignpar", IGNPAR, 0); + print_iflag("inlcr", INLCR, 0); + print_iflag("inpck", INPCK, 0); + print_iflag("istrip", ISTRIP, 0); + print_iflag("ixany", IXANY, 0); + print_iflag("ixoff", IXOFF, 0); + print_iflag("ixon", IXON, 0); + print_iflag("parmrk", PARMRK, 0); + if (printed) { fprintf(stdout, "\n"); printed = 0; } + + print_oflag("opost", OPOST, 1); + print_oflag("olcuc", OLCUC, 0); + print_oflag("onlcr", ONLCR, 1); + print_oflag("ocrnl", OCRNL, 0); + print_oflag("onocr", ONOCR, 0); + print_oflag("onlret", ONLRET, 0); + print_oflag("ofill", OFILL, 0); + print_oflag("ofdel", OFDEL, 0); + + switch ((t.c_oflag & CRDLY)) { + case CR0: if (!hide_defaults) { fprintf(stdout, "cr0 "); printed = 1; } break; + case CR1: fprintf(stdout, "cr1 "); printed = 1; break; + case CR2: fprintf(stdout, "cr2 "); printed = 1; break; + case CR3: fprintf(stdout, "cr3 "); printed = 1; break; + } + + switch ((t.c_oflag & NLDLY)) { + case NL0: if (!hide_defaults) { fprintf(stdout, "nl0 "); printed = 1; } break; + case NL1: fprintf(stdout, "nl1 "); printed = 1; break; + } + + switch ((t.c_oflag & TABDLY)) { + case TAB0: if (!hide_defaults) { fprintf(stdout, "tab0 "); printed = 1; } break; + case TAB1: fprintf(stdout, "tab1 "); printed = 1; break; + case TAB2: fprintf(stdout, "tab2 "); printed = 1; break; + case TAB3: fprintf(stdout, "tab3 "); printed = 1; break; + } + + switch ((t.c_oflag & BSDLY)) { + case BS0: if (!hide_defaults) { fprintf(stdout, "bs0 "); printed = 1; } break; + case BS1: fprintf(stdout, "bs1 "); printed = 1; break; + } + + switch ((t.c_oflag & FFDLY)) { + case FF0: if (!hide_defaults) { fprintf(stdout, "ff0 "); printed = 1; } break; + case FF1: fprintf(stdout, "ff1 "); printed = 1; break; + } + + switch ((t.c_oflag & VTDLY)) { + case VT0: if (!hide_defaults) { fprintf(stdout, "vt0"); printed = 1; } break; + case VT1: fprintf(stdout, "vt1"); printed = 1; break; + } + if (printed) { fprintf(stdout, "\n"); printed = 0; } + + print_lflag("isig", ISIG, 1); + print_lflag("icanon", ICANON, 1); + print_lflag("xcase", XCASE, 0); + print_lflag("echo", ECHO, 1); + print_lflag("echoe", ECHOE, 1); + print_lflag("echok", ECHOK, 1); + print_lflag("echonl", ECHONL, 0); + print_lflag("noflsh", NOFLSH, 0); + print_lflag("tostop", TOSTOP, 0); + print_lflag("iexten", IEXTEN, 1); + if (printed) { fprintf(stdout, "\n"); printed = 0; } + + return 0; +} + +int main(int argc, char * argv[]) { + + int i = 1; + + if (i < argc && !strcmp(argv[i], "-a")) { + hide_defaults = 0; + i++; + } + + if (i == argc) { + return show_settings(0); + } + + struct termios t; + tcgetattr(STDERR_FILENO, &t); + + while (i < argc) { + + if (!strcmp(argv[i], "sane")) { + t.c_iflag = ICRNL | BRKINT; + t.c_oflag = ONLCR | OPOST; + t.c_lflag = ECHO | ECHOE | ECHOK | ICANON | ISIG | IEXTEN; + t.c_cflag = CREAD | CS8; + t.c_cc[VEOF] = 4; /* ^D */ + t.c_cc[VEOL] = 0; /* Not set */ + t.c_cc[VERASE] = '\b'; + t.c_cc[VINTR] = 3; /* ^C */ + t.c_cc[VKILL] = 21; /* ^U */ + t.c_cc[VMIN] = 1; + t.c_cc[VQUIT] = 28; /* ^\ */ + t.c_cc[VSTART] = 17; /* ^Q */ + t.c_cc[VSTOP] = 19; /* ^S */ + t.c_cc[VSUSP] = 26; /* ^Z */ + t.c_cc[VTIME] = 0; + } + + set_char("eof", VEOF); + set_char("eol", VEOL); + set_char("erase", VERASE); + set_char("intr", VINTR); + set_char("kill", VKILL); + set_char("quit", VQUIT); + set_char("start", VSTART); + set_char("stop", VSTOP); + set_char("susp", VSUSP); + + + set_cflag("parenb", PARENB); + set_cflag("parodd", PARODD); + set_cflag("hupcl", HUPCL); + set_cflag("hup", HUPCL); /* alias */ + set_cflag("cstopb", CSTOPB); + set_cflag("cread", CREAD); + set_cflag("clocal", CLOCAL); + + set_ctoggle("cs5", CSIZE, CS5); + set_ctoggle("cs6", CSIZE, CS6); + set_ctoggle("cs7", CSIZE, CS7); + set_ctoggle("cs8", CSIZE, CS8); + + set_iflag("ignbrk", IGNBRK); + set_iflag("brkint", BRKINT); + set_iflag("ignpar", IGNPAR); + set_iflag("parmrk", PARMRK); + set_iflag("inpck", INPCK); + set_iflag("istrip", ISTRIP); + set_iflag("inlcr", INLCR); + set_iflag("igncr", IGNCR); + set_iflag("icrnl", ICRNL); + set_iflag("ixon", IXON); + set_iflag("ixany", IXANY); + set_iflag("ixoff", IXOFF); + + set_oflag("olcuc", OLCUC); + set_oflag("opost", OPOST); + set_oflag("onlcr", ONLCR); + set_oflag("ocrnl", OCRNL); + set_oflag("onocr", ONOCR); + set_oflag("onlret", ONLRET); + set_oflag("ofill", OFILL); + set_oflag("ofdel", OFDEL); + + set_otoggle("cr0", CRDLY, CR0); + set_otoggle("cr1", CRDLY, CR1); + set_otoggle("cr2", CRDLY, CR2); + set_otoggle("cr3", CRDLY, CR3); + + set_otoggle("nl0", NLDLY, NL0); + set_otoggle("nl1", NLDLY, NL1); + + set_otoggle("tab0", TABDLY, TAB0); + set_otoggle("tab1", TABDLY, TAB1); + set_otoggle("tab2", TABDLY, TAB2); + set_otoggle("tab3", TABDLY, TAB3); + + set_otoggle("bs0", BSDLY, BS0); + set_otoggle("bs1", BSDLY, BS1); + + set_otoggle("ff0", FFDLY, FF0); + set_otoggle("ff1", FFDLY, FF1); + + set_otoggle("vt0", VTDLY, VT0); + set_otoggle("vt1", VTDLY, VT1); + + set_lflag("isig", ISIG); + set_lflag("icanon", ICANON); + set_lflag("iexten", IEXTEN); + set_lflag("echo", ECHO); + set_lflag("echoe", ECHOE); + set_lflag("echok", ECHOK); + set_lflag("echonl", ECHONL); + set_lflag("noflsh", NOFLSH); + set_lflag("tostop", TOSTOP); + + i++; + } + + tcsetattr(STDERR_FILENO, TCSAFLUSH, &t); + + return 0; +} diff --git a/userspace/core/sudo.c b/apps/sudo.c similarity index 90% rename from userspace/core/sudo.c rename to apps/sudo.c index 98b467ef..49f2775d 100644 --- a/userspace/core/sudo.c +++ b/apps/sudo.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014 K. Lange * * sudo * @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -19,8 +18,7 @@ #include #include #include - -#include "lib/toaru_auth.h" +#include uint32_t child = 0; @@ -73,8 +71,15 @@ int main(int argc, char ** argv) { continue; } + /* Set username to root */ + putenv("USER=root"); + + if (!strcmp(argv[1], "-s")) { + argv[1] = getenv("SHELL"); + } + char ** args = &argv[1]; - int i = execvp(args[0], args); + execvp(args[0], args); /* XXX: There are other things that can cause an exec to fail. */ fprintf(stderr, "%s: %s: command not found\n", argv[0], args[0]); diff --git a/userspace/core/sysfunc.c b/apps/sysfunc.c similarity index 69% rename from userspace/core/sysfunc.c rename to apps/sysfunc.c index c7165b48..17e8378a 100644 --- a/userspace/core/sysfunc.c +++ b/apps/sysfunc.c @@ -1,8 +1,7 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* vim:tabstop=4 shiftwidth=4 noexpandtab + * Copyright (C) 2013 K. Lange * * sysfunc * diff --git a/userspace/extra/sysinfo.c b/apps/sysinfo.c similarity index 80% rename from userspace/extra/sysinfo.c rename to apps/sysinfo.c index db0088f7..b627f108 100644 --- a/userspace/extra/sysinfo.c +++ b/apps/sysinfo.c @@ -1,19 +1,21 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Kevin Lange + * Copyright (C) 2015-2018 K. Lange * * sysinfo - visually based on screenfetch * * Displays system information in a visually-pleasing format. */ #include +#include +#include #include #include -#include "lib/graphics.h" +#include +#include -#include "gui/terminal/lib/termemu.h" #include "toaru_logo.h" #define NUM_DATA_LINES 30 @@ -39,6 +41,8 @@ int main(int argc, char * argv[]) { /* Prepare data */ char * user = getenv("USER"); char * wm_theme = getenv("WM_THEME"); + char * term = getenv("TERM"); + int term_is_toaru = term && !strcmp(term,"toaru"); int i = 0; prog_lines[i] = "hostname"; @@ -55,8 +59,10 @@ int main(int argc, char * argv[]) { sprintf(data_lines[i++], C_A "Resolution: " C_O); sprintf(data_lines[i++], C_A "WM: " C_O "Yutani"); sprintf(data_lines[i++], C_A "WM Theme: " C_O "%s", wm_theme); +#if 0 prog_lines[i] = "yutani-query -m"; sprintf(data_lines[i++], C_A "Font: " C_O); +#endif //sprintf(data_lines[i++], C_A "CPU: " C_O "(query cpudet)"); //sprintf(data_lines[i++], C_A "GPU: " C_O "(hell if I know!)"); prog_lines[i] = "free -ut"; @@ -88,10 +94,17 @@ int main(int argc, char * argv[]) { rgba(0,0,0,TERM_DEFAULT_OPAC), premultiply(rgba(r_b, g_b, b_b, a_b))); - /* Print half block */ - printf("\033[38;6;%d;%d;%d;%dm\033[48;6;%d;%d;%d;%dm▄", - _RED(back), _GRE(back), _BLU(back), _ALP(back), - _RED(out), _GRE(out), _BLU(out), _ALP(out)); + if (term_is_toaru) { + + /* Print half block */ + printf("\033[38;6;%d;%d;%d;%dm\033[48;6;%d;%d;%d;%dm▄", + (int)_RED(back), (int)_GRE(back), (int)_BLU(back), (int)_ALP(back), + (int)_RED(out), (int)_GRE(out), (int)_BLU(out), (int)_ALP(out)); + } else { + printf("\033[38;2;%d;%d;%dm\033[48;2;%d;%d;%dm▄", + (int)_RED(back), (int)_GRE(back), (int)_BLU(back), + (int)_RED(out), (int)_GRE(out), (int)_BLU(out)); + } } if (j < i) { @@ -103,7 +116,7 @@ int main(int argc, char * argv[]) { } while (j < i) { - for (int x = 0; x < gimp_image.width; x++) { + for (int x = 0; x < (int)gimp_image.width; x++) { printf(" "); } print_thing(j); diff --git a/apps/tee.c b/apps/tee.c new file mode 100644 index 00000000..3e9b985c --- /dev/null +++ b/apps/tee.c @@ -0,0 +1,62 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * tee - copy stdin to stdout and to specified files + */ +#include +#include +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + int append = 0; + int ret_val = 0; + int opt; + + while ((opt = getopt(argc, argv, "ai")) != -1) { + switch (opt) { + case 'a': + append = 1; + break; + case 'i': + signal(SIGINT, SIG_IGN); + break; + } + } + + int file_count = argc - optind; + FILE ** files = malloc(sizeof(FILE *) * file_count); + + for (int i = 0, j = optind; j < argc && i < file_count; j++) { + files[i] = fopen(argv[j], append ? "a" : "w"); + if (!files[i]) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[j], strerror(errno)); + ret_val = 1; + file_count--; + continue; + } else { + i++; + } + } + + while (!feof(stdin)) { + int c = fgetc(stdin); + if (c >= 0) { + fputc(c, stdout); + + for (int i = 0; i < file_count; ++i) { + fputc(c, files[i]); + } + } + } + + for (int i = 0; i < file_count; ++i) { + fclose(files[i]); + } + + return ret_val; +} diff --git a/apps/terminal-font.h b/apps/terminal-font.h new file mode 100644 index 00000000..27030e87 Binary files /dev/null and b/apps/terminal-font.h differ diff --git a/userspace/gui/terminal/terminal-palette.h b/apps/terminal-palette.h similarity index 89% rename from userspace/gui/terminal/terminal-palette.h rename to apps/terminal-palette.h index f33192d8..801bae46 100644 --- a/userspace/gui/terminal/terminal-palette.h +++ b/apps/terminal-palette.h @@ -1,11 +1,19 @@ -/* - * Terminal palette +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2012-2018 K. Lange + * + * terminal-palette.h - Terminal color palette + * + * Provides the color table for both the basic 16 colors (here, + * chosen from the Tango design documents), as well as the other + * colors making up the basic 256 color palette derived from xterm. */ #define PALETTE_COLORS 256 uint32_t term_colors[PALETTE_COLORS] = { - /* black */ 0x2e3436, + /* black */ 0x000000, /* red */ 0xcc0000, /* green */ 0x3e9a06, /* brown */ 0xc4a000, diff --git a/userspace/gui/terminal/terminal-vga.c b/apps/terminal-vga.c similarity index 61% rename from userspace/gui/terminal/terminal-vga.c rename to apps/terminal-vga.c index 399989be..b4b48797 100644 --- a/userspace/gui/terminal/terminal-vga.c +++ b/apps/terminal-vga.c @@ -1,14 +1,13 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * Terminal Emulator - VGA */ #include #include -#include #include #include #include @@ -21,15 +20,18 @@ #include #include #include +#include +#include #include -#include "lib/utf8decode.h" -#include "lib/kbd.h" -#include "lib/graphics.h" +#include +#include +#include +#include +#include -#include "gui/terminal/vga-palette.h" -#include "gui/terminal/lib/termemu.h" +#include "vga-palette.h" #define USE_BELL 0 @@ -51,6 +53,13 @@ uint8_t _hold_out = 0; /* state indicator on last cell ignore \n */ uint64_t mouse_ticks = 0; +int selection = 0; +int selection_start_x = 0; +int selection_start_y = 0; +int selection_end_x = 0; +int selection_end_y = 0; +char * selection_text = NULL; + #define char_width 1 #define char_height 1 @@ -59,9 +68,6 @@ term_state_t * ansi_state = NULL; void reinit(); /* Defined way further down */ void term_redraw_cursor(); -/* Cursor bink timer */ -static unsigned int timer_tick = 0; - void term_clear(); void dump_buffer(); @@ -109,6 +115,7 @@ static uint32_t vga_base_colors[] = { 0xFFFFFF, }; +#if 0 static int is_gray(uint32_t a) { int a_r = (a & 0xFF0000) >> 16; int a_g = (a & 0xFF00) >> 8; @@ -116,12 +123,12 @@ static int is_gray(uint32_t a) { return (a_r == a_g && a_g == a_b); } +#endif static int best_match(uint32_t a) { int best_distance = INT32_MAX; int best_index = 0; for (int j = 0; j < 16; ++j) { - if (is_gray(a) && !is_gray(vga_base_colors[j])); int distance = color_distance(a, vga_base_colors[j]); if (distance < best_distance) { best_index = j; @@ -134,10 +141,6 @@ static int best_match(uint32_t a) { volatile int exit_application = 0; -static void set_term_font_size(float s) { - /* do nothing */ -} - /* Returns the lower of two shorts */ uint16_t min(uint16_t a, uint16_t b) { return (a < b) ? a : b; @@ -152,6 +155,234 @@ void set_title(char * c) { /* Do nothing */ } +static void cell_redraw(uint16_t x, uint16_t y); +static void cell_redraw_inverted(uint16_t x, uint16_t y); + +void iterate_selection(void (*func)(uint16_t x, uint16_t y)) { + if (selection_end_y < selection_start_y) { + for (int x = selection_end_x; x < term_width; ++x) { + func(x, selection_end_y); + } + for (int y = selection_end_y + 1; y < selection_start_y; ++y) { + for (int x = 0; x < term_width; ++x) { + func(x, y); + } + } + for (int x = 0; x <= selection_start_x; ++x) { + func(x, selection_start_y); + } + } else if (selection_start_y == selection_end_y) { + if (selection_start_x > selection_end_x) { + for (int x = selection_end_x; x <= selection_start_x; ++x) { + func(x, selection_start_y); + } + } else { + for (int x = selection_start_x; x <= selection_end_x; ++x) { + func(x, selection_start_y); + } + } + } else { + for (int x = selection_start_x; x < term_width; ++x) { + func(x, selection_start_y); + } + for (int y = selection_start_y + 1; y < selection_end_y; ++y) { + for (int x = 0; x < term_width; ++x) { + func(x, y); + } + } + for (int x = 0; x <= selection_end_x; ++x) { + func(x, selection_end_y); + } + } + +} + +void redraw_selection(void) { + iterate_selection(cell_redraw_inverted); +} + +static void redraw_new_selection(int old_x, int old_y) { + if (selection_end_y == selection_start_y && old_y != selection_start_y) { + int a, b; + a = selection_end_x; + b = selection_end_y; + selection_end_x = old_x; + selection_end_y = old_y; + iterate_selection(cell_redraw); + selection_end_x = a; + selection_end_y = b; + iterate_selection(cell_redraw_inverted); + } else { + int a, b; + a = selection_start_x; + b = selection_start_y; + + selection_start_x = old_x; + selection_start_y = old_y; + + /* Figure out direction */ + if (old_y < b) { + /* Backwards */ + if (selection_end_y < old_y || (selection_end_y == old_y && selection_end_x < old_x)) { + /* Selection extended */ + iterate_selection(cell_redraw_inverted); + } else { + /* Selection got smaller */ + iterate_selection(cell_redraw); + } + } else if (old_y == b) { + /* Was a single line */ + if (selection_end_y == b) { + /* And still is */ + if (old_x < a) { + /* Backwards */ + if (selection_end_x < old_x) { + iterate_selection(cell_redraw_inverted); + } else { + iterate_selection(cell_redraw); + } + } else { + if (selection_end_x < old_x) { + iterate_selection(cell_redraw); + } else { + iterate_selection(cell_redraw_inverted); + } + } + } else if (selection_end_y < b) { + /* Moved up */ + if (old_x <= a) { + /* Should be fine with just append */ + iterate_selection(cell_redraw_inverted); + } else { + /* Need to erase first */ + iterate_selection(cell_redraw); + selection_start_x = a; + selection_start_y = b; + iterate_selection(cell_redraw_inverted); + } + } else if (selection_end_y > b) { + if (old_x >= a) { + /* Should be fine with just append */ + iterate_selection(cell_redraw_inverted); + } else { + /* Need to erase first */ + iterate_selection(cell_redraw); + selection_start_x = a; + selection_start_y = b; + iterate_selection(cell_redraw_inverted); + } + } + } else { + /* Forward */ + if (selection_end_y < old_y || (selection_end_y == old_y && selection_end_x < old_x)) { + /* Selection got smaller */ + iterate_selection(cell_redraw); + } else { + /* Selection extended */ + iterate_selection(cell_redraw_inverted); + } + } + + cell_redraw_inverted(a,b); + cell_redraw_inverted(selection_end_x, selection_end_y); + + /* Restore */ + selection_start_x = a; + selection_start_y = b; + } +} + +static int _selection_count = 0; +static int _selection_i = 0; + +static int to_eight(uint32_t codepoint, char * out) { + memset(out, 0x00, 7); + + if (codepoint < 0x0080) { + out[0] = (char)codepoint; + } else if (codepoint < 0x0800) { + out[0] = 0xC0 | (codepoint >> 6); + out[1] = 0x80 | (codepoint & 0x3F); + } else if (codepoint < 0x10000) { + out[0] = 0xE0 | (codepoint >> 12); + out[1] = 0x80 | ((codepoint >> 6) & 0x3F); + out[2] = 0x80 | (codepoint & 0x3F); + } else if (codepoint < 0x200000) { + out[0] = 0xF0 | (codepoint >> 18); + out[1] = 0x80 | ((codepoint >> 12) & 0x3F); + out[2] = 0x80 | ((codepoint >> 6) & 0x3F); + out[3] = 0x80 | ((codepoint) & 0x3F); + } else if (codepoint < 0x4000000) { + out[0] = 0xF8 | (codepoint >> 24); + out[1] = 0x80 | (codepoint >> 18); + out[2] = 0x80 | ((codepoint >> 12) & 0x3F); + out[3] = 0x80 | ((codepoint >> 6) & 0x3F); + out[4] = 0x80 | ((codepoint) & 0x3F); + } else { + out[0] = 0xF8 | (codepoint >> 30); + out[1] = 0x80 | ((codepoint >> 24) & 0x3F); + out[2] = 0x80 | ((codepoint >> 18) & 0x3F); + out[3] = 0x80 | ((codepoint >> 12) & 0x3F); + out[4] = 0x80 | ((codepoint >> 6) & 0x3F); + out[5] = 0x80 | ((codepoint) & 0x3F); + } + + return strlen(out); +} + +void count_selection(uint16_t x, uint16_t y) { + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + if (((uint32_t *)cell)[0] != 0x00000000) { + char tmp[7]; + _selection_count += to_eight(cell->c, tmp); + } + if (x == term_width - 1) { + _selection_count++; + } +} + +void write_selection(uint16_t x, uint16_t y) { + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + if (((uint32_t *)cell)[0] != 0x00000000) { + char tmp[7]; + int count = to_eight(cell->c, tmp); + for (int i = 0; i < count; ++i) { + selection_text[_selection_i] = tmp[i]; + _selection_i++; + } + } + if (x == term_width - 1) { + selection_text[_selection_i] = '\n';; + _selection_i++; + } +} + + +char * copy_selection(void) { + _selection_count = 0; + iterate_selection(count_selection); + + if (selection_text) { + free(selection_text); + } + + if (_selection_count == 0) { + return NULL; + } + + selection_text = malloc(_selection_count + 1); + selection_text[_selection_count] = '\0'; + _selection_i = 0; + iterate_selection(write_selection); + + if (selection_text[_selection_count-1] == '\n') { + /* Don't end on a line feed */ + selection_text[_selection_count-1] = '\0'; + } + + return selection_text; +} + void input_buffer_stuff(char * str) { size_t s = strlen(str) + 1; write(fd_master, str, s); @@ -393,6 +624,7 @@ static void cell_redraw_inverted(uint16_t x, uint16_t y) { } } +#if 0 static void cell_redraw_box(uint16_t x, uint16_t y) { if (x >= term_width || y >= term_height) return; term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); @@ -402,14 +634,17 @@ static void cell_redraw_box(uint16_t x, uint16_t y) { term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags | ANSI_BORDER); } } +#endif void render_cursor() { cell_redraw_inverted(csr_x, csr_y); } +static uint8_t cursor_flipped = 0; void draw_cursor() { if (!cursor_on) return; mouse_ticks = get_ticks(); + cursor_flipped = 0; render_cursor(); } @@ -486,15 +721,6 @@ void term_write(char c) { draw_cursor(); } else if (c == '\007') { /* bell */ -#if USE_BELL - for (int i = 0; i < term_height; ++i) { - for (int j = 0; j < term_width; ++j) { - cell_redraw_inverted(j, i); - } - } - syscall_nanosleep(0,10); - term_redraw_all(); -#endif } else if (c == '\b') { if (csr_x > 0) { --csr_x; @@ -547,6 +773,9 @@ int term_get_csr_y() { void term_set_csr_show(int on) { cursor_on = on; + if (on) { + draw_cursor(); + } } void term_set_colors(uint32_t fg, uint32_t bg) { @@ -561,7 +790,6 @@ void term_redraw_cursor() { } void flip_cursor() { - static uint8_t cursor_flipped = 0; if (cursor_flipped) { cell_redraw(csr_x, csr_y); } else { @@ -617,7 +845,7 @@ void clear_input() { input_collected = 0; } -uint32_t child_pid = 0; +pid_t child_pid = 0; void handle_input(char c) { write(fd_master, &c, 1); @@ -629,6 +857,25 @@ void handle_input_s(char * c) { void key_event(int ret, key_event_t * event) { if (ret) { + /* Special keys */ + if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) && + (event->modifiers & KEY_MOD_LEFT_CTRL || event->modifiers & KEY_MOD_RIGHT_CTRL) && + (event->keycode == 'c')) { + if (selection) { + /* Copy selection */ + copy_selection(); + } + return; + } + if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) && + (event->modifiers & KEY_MOD_LEFT_CTRL || event->modifiers & KEY_MOD_RIGHT_CTRL) && + (event->keycode == 'v')) { + /* Paste selection */ + if (selection_text) { + handle_input_s(selection_text); + } + return; + } if (event->modifiers & KEY_MOD_LEFT_ALT || event->modifiers & KEY_MOD_RIGHT_ALT) { handle_input('\033'); } @@ -675,21 +922,67 @@ void key_event(int ret, key_event_t * event) { handle_input_s("\033[23~"); break; case KEY_F12: - /* XXX This is for testing only */ - handle_input_s("テスト"); - //handle_input_s("\033[24~"); + handle_input_s("\033[24~"); break; case KEY_ARROW_UP: - handle_input_s("\033[A"); + if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[6A"); + } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[5A"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[4A"); + } else if (event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[3A"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + handle_input_s("\033[2A"); + } else { + handle_input_s("\033[A"); + } break; case KEY_ARROW_DOWN: - handle_input_s("\033[B"); + if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[6B"); + } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[5B"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[4B"); + } else if (event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[3B"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + handle_input_s("\033[2B"); + } else { + handle_input_s("\033[B"); + } break; case KEY_ARROW_RIGHT: - handle_input_s("\033[C"); + if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[6C"); + } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[5C"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[4C"); + } else if (event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[3C"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + handle_input_s("\033[2C"); + } else { + handle_input_s("\033[C"); + } break; case KEY_ARROW_LEFT: - handle_input_s("\033[D"); + if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[6D"); + } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[5D"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[4D"); + } else if (event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[3D"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + handle_input_s("\033[2D"); + } else { + handle_input_s("\033[D"); + } break; case KEY_PAGE_UP: handle_input_s("\033[5~"); @@ -698,10 +991,10 @@ void key_event(int ret, key_event_t * event) { handle_input_s("\033[6~"); break; case KEY_HOME: - handle_input_s("\033OH"); + handle_input_s("\033[H"); break; case KEY_END: - handle_input_s("\033OF"); + handle_input_s("\033[F"); break; case KEY_DEL: handle_input_s("\033[3~"); @@ -735,12 +1028,12 @@ term_callbacks_t term_callbacks = { term_scroll, term_redraw_cursor, input_buffer_stuff, - set_term_font_size, set_title, unsupported, unsupported_int, unsupported_int, term_set_csr_show, + NULL, }; void reinit(int send_sig) { @@ -768,7 +1061,7 @@ void maybe_flip_cursor(void) { void check_for_exit(void) { if (exit_application) return; - int pid = waitpid(-1, NULL, WNOHANG); + pid_t pid = waitpid(-1, NULL, WNOHANG); if (pid != child_pid) return; @@ -779,6 +1072,76 @@ void check_for_exit(void) { write(fd_slave, exit_message, sizeof(exit_message)); } +static int mouse_x = 0; +static int mouse_y = 0; +static int last_mouse_buttons = 0; +static int mouse_is_dragging = 0; + +#define MOUSE_X_R 820 +#define MOUSE_Y_R 2621 + +static int old_x = 0; +static int old_y = 0; + +void handle_mouse_event(mouse_device_packet_t * packet) { + if (mouse_is_dragging) { + if (packet->buttons & LEFT_CLICK) { + int old_end_x = selection_end_x; + int old_end_y = selection_end_y; + selection_end_x = mouse_x; + selection_end_y = mouse_y; + redraw_new_selection(old_end_x, old_end_y); + } else { + mouse_is_dragging = 0; + } + } else { + if (packet->buttons & LEFT_CLICK) { + term_redraw_all(); + selection_start_x = mouse_x; + selection_start_y = mouse_y; + selection_end_x = mouse_x; + selection_end_y = mouse_y; + selection = 1; + redraw_selection(); + mouse_is_dragging = 1; + } else { + cell_redraw(old_x, old_y); + cell_redraw_inverted(mouse_x, mouse_y); + old_x = mouse_x; + old_y = mouse_y; + } + } + + +} + +static int rel_mouse_x = 0; +static int rel_mouse_y = 0; + +void handle_mouse(mouse_device_packet_t * packet) { + rel_mouse_x += packet->x_difference; + rel_mouse_y -= packet->y_difference; + + mouse_x = rel_mouse_x / 20; + mouse_y = rel_mouse_y / 40; + + if (mouse_x < 0) mouse_x = 0; + if (mouse_y < 0) mouse_y = 0; + if (mouse_x >= term_width) mouse_x = term_width - 1; + if (mouse_y >= term_height) mouse_y = term_height - 1; + handle_mouse_event(packet); +} + +void handle_mouse_abs(mouse_device_packet_t * packet) { + mouse_x = packet->x_difference / MOUSE_X_R; + mouse_y = packet->y_difference / MOUSE_Y_R; + + rel_mouse_x = mouse_x * 20; + rel_mouse_y = mouse_y * 40; + + handle_mouse_event(packet); +} + int main(int argc, char ** argv) { @@ -793,11 +1156,6 @@ int main(int argc, char ** argv) { /* Read some arguments */ int index, c; while ((c = getopt_long(argc, argv, "hl", long_opts, &index)) != -1) { - if (!c) { - if (long_opts[index].flag == 0) { - c = long_opts[index].val; - } - } switch (c) { case 'l': _login_shell = 1; @@ -815,7 +1173,7 @@ int main(int argc, char ** argv) { putenv("TERM=toaru"); - syscall_openpty(&fd_master, &fd_slave, NULL, NULL, NULL); + openpty(&fd_master, &fd_slave, NULL, NULL, NULL); terminal = fdopen(fd_slave, "w"); @@ -842,17 +1200,19 @@ int main(int argc, char ** argv) { if (argv[optind] != NULL) { char * tokens[] = {argv[optind], NULL}; - int i = execvp(tokens[0], tokens); + execvp(tokens[0], tokens); fprintf(stderr, "Failed to launch requested startup application.\n"); } else { if (_login_shell) { - char * tokens[] = {"/bin/login",NULL}; - int i = execvp(tokens[0], tokens); + char * tokens[] = {"/bin/login-loop",NULL}; + execvp(tokens[0], tokens); + exit(1); } else { char * shell = getenv("SHELL"); if (!shell) shell = "/bin/sh"; /* fallback */ char * tokens[] = {shell,NULL}; - int i = execvp(tokens[0], tokens); + execvp(tokens[0], tokens); + exit(1); } } @@ -866,30 +1226,39 @@ int main(int argc, char ** argv) { int kfd = open("/dev/kbd", O_RDONLY); key_event_t event; char c; + int vmmouse = 0; + mouse_device_packet_t packet; + + int mfd = open("/dev/mouse", O_RDONLY); + int amfd = open("/dev/absmouse", O_RDONLY); + if (amfd == -1) { + amfd = open("/dev/vmmouse", O_RDONLY); + vmmouse = 1; + } key_event_state_t kbd_state = {0}; /* Prune any keyboard input we got before the terminal started. */ struct stat s; fstat(kfd, &s); - for (int i = 0; i < s.st_size; i++) { + for (unsigned int i = 0; i < s.st_size; i++) { char tmp[1]; read(kfd, tmp, 1); } - int fds[2] = {fd_master, kfd}; + int fds[] = {fd_master, kfd, mfd, amfd}; unsigned char buf[1024]; while (!exit_application) { - int index = syscall_fswait2(2,fds,200); + int index = fswait2(amfd == -1 ? 3 : 4,fds,200); check_for_exit(); if (index == 0) { maybe_flip_cursor(); int r = read(fd_master, buf, 1024); - for (uint32_t i = 0; i < r; ++i) { + for (int i = 0; i < r; ++i) { ansi_put(ansi_state, buf[i]); } } else if (index == 1) { @@ -900,6 +1269,25 @@ int main(int argc, char ** argv) { key_event(ret, &event); } } else if (index == 2) { + /* mouse event */ + int r = read(mfd, (char *)&packet, sizeof(mouse_device_packet_t)); + if (r > 0) { + last_mouse_buttons = packet.buttons; + handle_mouse(&packet); + } + } else if (amfd != -1 && index == 3) { + int r = read(amfd, (char *)&packet, sizeof(mouse_device_packet_t)); + if (r > 0) { + if (!vmmouse) { + packet.buttons = last_mouse_buttons & 0xF; + } else { + last_mouse_buttons = packet.buttons; + } + handle_mouse_abs(&packet); + } + continue; + + } else { maybe_flip_cursor(); } } diff --git a/apps/terminal.c b/apps/terminal.c new file mode 100644 index 00000000..e18d51ac --- /dev/null +++ b/apps/terminal.c @@ -0,0 +1,2412 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * Terminal Emulator + * + * Graphical terminal emulator. + * + * Provides a number of features: + * - Windowed and full screen modes + * - Antialiased fonts + * - Built-in fallback bitmap font + * - ANSI escape support + * - 256 colors + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define TRACE_APP_NAME "terminal" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 16- and 256-color palette */ +#include "terminal-palette.h" +/* Bitmap font */ +#include "terminal-font.h" + +/* Show help text */ +static void usage(char * argv[]) { + printf( + "Terminal Emulator\n" + "\n" + "usage: %s [-Fbxn] [-s SCALE] [-g WIDTHxHEIGHT] [COMMAND...]\n" + "\n" + " -F --fullscreen \033[3mRun in fullscreen (background) mode.\033[0m\n" + " -b --bitmap \033[3mUse the integrated bitmap font.\033[0m\n" + " -s --scale \033[3mScale the font in antialiased mode by a given amount.\033[0m\n" + " -h --help \033[3mShow this help message.\033[0m\n" + " -x --grid \033[3mMake resizes round to nearest match for character cell size.\033[0m\n" + " -n --no-frame \033[3mDisable decorations.\033[0m\n" + " -g --geometry \033[3mSet requested terminal size WIDTHxHEIGHT\033[0m\n" + " -f --no-ft \033[3mForce disable the freetype backend.\033[0m\n" + "\n" + " This terminal emulator provides basic support for VT220 escapes and\n" + " XTerm extensions, including 256 color support and font effects.\n", + argv[0]); +} + +/* master and slave pty descriptors */ +static int fd_master, fd_slave; +static FILE * terminal; +static pid_t child_pid = 0; + +static int scale_fonts = 0; /* Whether fonts should be scaled */ +static float font_scaling = 1.0; /* How much they should be scaled by */ +static float font_gamma = 1.7; /* Gamma to use for SDF library */ +static uint16_t term_width = 0; /* Width of the terminal (in cells) */ +static uint16_t term_height = 0; /* Height of the terminal (in cells) */ +static uint16_t font_size = 16; /* Font size according to SDF library */ +static uint16_t char_width = 9; /* Width of a cell in pixels */ +static uint16_t char_height = 17; /* Height of a cell in pixels */ +static uint16_t char_offset = 0; /* Offset of the font within the cell */ +static int csr_x = 0; /* Cursor X */ +static int csr_y = 0; /* Cursor Y */ +static uint32_t current_fg = 7; /* Current foreground color */ +static uint32_t current_bg = 0; /* Current background color */ + +static term_cell_t * term_buffer = NULL; /* The terminal cell buffer */ +static term_cell_t * term_buffer_a = NULL; +static term_cell_t * term_buffer_b = NULL; +static term_state_t * ansi_state = NULL; /* ANSI parser library state */ +static int active_buffer = 0; +static int _orig_x = 0; +static int _orig_y = 0; +static uint32_t _orig_fg = 7; +static uint32_t _orig_bg = 0; + +static bool cursor_on = 1; /* Whether or not the cursor should be rendered */ +static bool _fullscreen = 0; /* Whether or not we are running in fullscreen mode (GUI only) */ +static bool _no_frame = 0; /* Whether to disable decorations or not */ +static bool _use_aa = 1; /* Whether or not to use best-available anti-aliased renderer */ +static bool _have_freetype = 0; /* Whether freetype is available */ +static bool _force_no_ft = 0; /* Whether to force disable the freetype backend */ +static bool _hold_out = 0; /* state indicator on last cell ignore \n */ +static bool _free_size = 1; /* Disable rounding when resized */ + +/** Freetype extension renderer functions */ +static void (*freetype_set_font_face)(int face) = NULL; +static void (*freetype_set_font_size)(int size) = NULL; +static void (*freetype_draw_char)(gfx_context_t * ctx, int x, int y, uint32_t fg, uint32_t codepoint) = NULL; + +static list_t * images_list = NULL; + +static int menu_bar_height = 24; + +/* Text selection information */ +static int selection = 0; +static int selection_start_x = 0; +static int selection_start_y = 0; +static int selection_end_x = 0; +static int selection_end_y = 0; +static char * selection_text = NULL; +static int _selection_count = 0; +static int _selection_i = 0; + +/* Mouse state */ +static int last_mouse_x = -1; +static int last_mouse_y = -1; +static int button_state = 0; +static unsigned long long mouse_ticks = 0; + +static yutani_window_t * window = NULL; /* GUI window */ +static yutani_t * yctx = NULL; + +/* Window flip bounds */ +static int32_t l_x = INT32_MAX; +static int32_t l_y = INT32_MAX; +static int32_t r_x = -1; +static int32_t r_y = -1; + +static uint32_t window_width = 640; +static uint32_t window_height = 480; +#define TERMINAL_TITLE_SIZE 512 +static char terminal_title[TERMINAL_TITLE_SIZE]; +static size_t terminal_title_length = 0; +static gfx_context_t * ctx; +static struct MenuList * menu_right_click = NULL; + +static void render_decors(void); +static void term_clear(); +static void reinit(); +static void term_redraw_cursor(); + +static int decor_left_width = 0; +static int decor_top_height = 0; +static int decor_right_width = 0; +static int decor_bottom_height = 0; +static int decor_width = 0; +static int decor_height = 0; + +struct scrollback_row { + unsigned short width; + term_cell_t cells[]; +}; + +#define MAX_SCROLLBACK 10240 +static list_t * scrollback_list = NULL; +static int scrollback_offset = 0; + +/* Menu bar entries */ +struct menu_bar terminal_menu_bar = {0}; +struct menu_bar_entries terminal_menu_entries[] = { + {"File", "file"}, + {"Edit", "edit"}, + {"View", "view"}, + {"Help", "help"}, + {NULL, NULL}, +}; + +/* Trigger to exit the terminal when the child process dies or + * we otherwise receive an exit signal */ +static volatile int exit_application = 0; + +static void cell_redraw(uint16_t x, uint16_t y); +static void cell_redraw_inverted(uint16_t x, uint16_t y); + +static uint64_t get_ticks(void) { + struct timeval now; + gettimeofday(&now, NULL); + + return (uint64_t)now.tv_sec * 1000000LL + (uint64_t)now.tv_usec; +} + +static void display_flip(void) { + if (l_x != INT32_MAX && l_y != INT32_MAX) { + flip(ctx); + yutani_flip_region(yctx, window, l_x, l_y, r_x - l_x, r_y - l_y); + l_x = INT32_MAX; + l_y = INT32_MAX; + r_x = -1; + r_y = -1; + } +} + +/* Returns the lower of two shorts */ +static int32_t min(int32_t a, int32_t b) { + return (a < b) ? a : b; +} + +/* Returns the higher of two shorts */ +static int32_t max(int32_t a, int32_t b) { + return (a > b) ? a : b; +} + +/* + * Convert codepoint to UTF-8 + * + * Returns length of byte sequence written. + */ +static int to_eight(uint32_t codepoint, char * out) { + memset(out, 0x00, 7); + + if (codepoint < 0x0080) { + out[0] = (char)codepoint; + } else if (codepoint < 0x0800) { + out[0] = 0xC0 | (codepoint >> 6); + out[1] = 0x80 | (codepoint & 0x3F); + } else if (codepoint < 0x10000) { + out[0] = 0xE0 | (codepoint >> 12); + out[1] = 0x80 | ((codepoint >> 6) & 0x3F); + out[2] = 0x80 | (codepoint & 0x3F); + } else if (codepoint < 0x200000) { + out[0] = 0xF0 | (codepoint >> 18); + out[1] = 0x80 | ((codepoint >> 12) & 0x3F); + out[2] = 0x80 | ((codepoint >> 6) & 0x3F); + out[3] = 0x80 | ((codepoint) & 0x3F); + } else if (codepoint < 0x4000000) { + out[0] = 0xF8 | (codepoint >> 24); + out[1] = 0x80 | (codepoint >> 18); + out[2] = 0x80 | ((codepoint >> 12) & 0x3F); + out[3] = 0x80 | ((codepoint >> 6) & 0x3F); + out[4] = 0x80 | ((codepoint) & 0x3F); + } else { + out[0] = 0xF8 | (codepoint >> 30); + out[1] = 0x80 | ((codepoint >> 24) & 0x3F); + out[2] = 0x80 | ((codepoint >> 18) & 0x3F); + out[3] = 0x80 | ((codepoint >> 12) & 0x3F); + out[4] = 0x80 | ((codepoint >> 6) & 0x3F); + out[5] = 0x80 | ((codepoint) & 0x3F); + } + + return strlen(out); +} + +/* Set the terminal title string */ +static void set_title(char * c) { + int len = min(TERMINAL_TITLE_SIZE, strlen(c)+1); + memcpy(terminal_title, c, len); + terminal_title[len-1] = '\0'; + terminal_title_length = len - 1; + render_decors(); +} + +/* Call a function for each selected cell */ +static void iterate_selection(void (*func)(uint16_t x, uint16_t y)) { + if (selection_end_y < selection_start_y) { + for (int x = selection_end_x; x < term_width; ++x) { + func(x, selection_end_y); + } + for (int y = selection_end_y + 1; y < selection_start_y; ++y) { + for (int x = 0; x < term_width; ++x) { + func(x, y); + } + } + for (int x = 0; x <= selection_start_x; ++x) { + func(x, selection_start_y); + } + } else if (selection_start_y == selection_end_y) { + if (selection_start_x > selection_end_x) { + for (int x = selection_end_x; x <= selection_start_x; ++x) { + func(x, selection_start_y); + } + } else { + for (int x = selection_start_x; x <= selection_end_x; ++x) { + func(x, selection_start_y); + } + } + } else { + for (int x = selection_start_x; x < term_width; ++x) { + func(x, selection_start_y); + } + for (int y = selection_start_y + 1; y < selection_end_y; ++y) { + for (int x = 0; x < term_width; ++x) { + func(x, y); + } + } + for (int x = 0; x <= selection_end_x; ++x) { + func(x, selection_end_y); + } + } + +} + +/* Redraw the selection with the selection hint (inversion) */ +static void redraw_selection(void) { + iterate_selection(cell_redraw_inverted); +} + +static void redraw_new_selection(int old_x, int old_y) { + if (selection_end_y == selection_start_y && old_y != selection_start_y) { + int a, b; + a = selection_end_x; + b = selection_end_y; + selection_end_x = old_x; + selection_end_y = old_y; + iterate_selection(cell_redraw); + selection_end_x = a; + selection_end_y = b; + iterate_selection(cell_redraw_inverted); + } else { + int a, b; + a = selection_start_x; + b = selection_start_y; + + selection_start_x = old_x; + selection_start_y = old_y; + + /* Figure out direction */ + if (old_y < b) { + /* Backwards */ + if (selection_end_y < old_y || (selection_end_y == old_y && selection_end_x < old_x)) { + /* Selection extended */ + iterate_selection(cell_redraw_inverted); + } else { + /* Selection got smaller */ + iterate_selection(cell_redraw); + } + } else if (old_y == b) { + /* Was a single line */ + if (selection_end_y == b) { + /* And still is */ + if (old_x < a) { + /* Backwards */ + if (selection_end_x < old_x) { + iterate_selection(cell_redraw_inverted); + } else { + iterate_selection(cell_redraw); + } + } else { + if (selection_end_x < old_x) { + iterate_selection(cell_redraw); + } else { + iterate_selection(cell_redraw_inverted); + } + } + } else if (selection_end_y < b) { + /* Moved up */ + if (old_x <= a) { + /* Should be fine with just append */ + iterate_selection(cell_redraw_inverted); + } else { + /* Need to erase first */ + iterate_selection(cell_redraw); + selection_start_x = a; + selection_start_y = b; + iterate_selection(cell_redraw_inverted); + } + } else if (selection_end_y > b) { + if (old_x >= a) { + /* Should be fine with just append */ + iterate_selection(cell_redraw_inverted); + } else { + /* Need to erase first */ + iterate_selection(cell_redraw); + selection_start_x = a; + selection_start_y = b; + iterate_selection(cell_redraw_inverted); + } + } + } else { + /* Forward */ + if (selection_end_y < old_y || (selection_end_y == old_y && selection_end_x < old_x)) { + /* Selection got smaller */ + iterate_selection(cell_redraw); + } else { + /* Selection extended */ + iterate_selection(cell_redraw_inverted); + } + } + + cell_redraw_inverted(a,b); + cell_redraw_inverted(selection_end_x, selection_end_y); + + /* Restore */ + selection_start_x = a; + selection_start_y = b; + } +} + +/* Figure out how long the UTF-8 selection string should be. */ +static void count_selection(uint16_t x, uint16_t y) { + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + if (!(cell->flags & ANSI_EXT_IMG)) { + if (((uint32_t *)cell)[0] != 0x00000000) { + char tmp[7]; + _selection_count += to_eight(cell->c, tmp); + } + } + if (x == term_width - 1) { + _selection_count++; + } +} + +/* Fill the selection text buffer with the selected text. */ +void write_selection(uint16_t x, uint16_t y) { + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + if (!(cell->flags & ANSI_EXT_IMG)) { + if (((uint32_t *)cell)[0] != 0x00000000) { + char tmp[7]; + int count = to_eight(cell->c, tmp); + for (int i = 0; i < count; ++i) { + selection_text[_selection_i] = tmp[i]; + _selection_i++; + } + } + } + if (x == term_width - 1) { + selection_text[_selection_i] = '\n';; + _selection_i++; + } +} + +/* Copy the selection text to the clipboard. */ +static char * copy_selection(void) { + _selection_count = 0; + iterate_selection(count_selection); + + fprintf(stderr, "Selection length is %d\n", _selection_count); + + if (selection_text) { + free(selection_text); + } + + if (_selection_count == 0) { + return NULL; + } + + selection_text = malloc(_selection_count + 1); + selection_text[_selection_count] = '\0'; + _selection_i = 0; + iterate_selection(write_selection); + + if (selection_text[_selection_count-1] == '\n') { + /* Don't end on a line feed */ + selection_text[_selection_count-1] = '\0'; + } + + yutani_set_clipboard(yctx, selection_text); + + return selection_text; +} + +/* Stuffs a string into the stdin of the terminal's child process + * Useful for things like the ANSI DSR command. */ +static void input_buffer_stuff(char * str) { + size_t s = strlen(str) + 1; + write(fd_master, str, s); +} + +/* Redraw the decorations */ +static void render_decors(void) { + /* Don't draw decorations or bother advertising the window if in "fullscreen mode" */ + if (_fullscreen) return; + + if (!_no_frame) { + /* Draw the decorations */ + render_decorations(window, ctx, terminal_title_length ? terminal_title : "Terminal"); + /* Update menu bar position and size */ + terminal_menu_bar.x = decor_left_width; + terminal_menu_bar.y = decor_top_height; + terminal_menu_bar.width = window_width; + terminal_menu_bar.window = window; + /* Redraw the menu bar */ + menu_bar_render(&terminal_menu_bar, ctx); + } + + /* Advertise the window icon to the panel. */ + yutani_window_advertise_icon(yctx, window, terminal_title_length ? terminal_title : "Terminal", "utilities-terminal"); + + /* + * Flip the whole window + * We do this regardless of whether we drew decorations to catch + * a case where decorations are toggled. + */ + l_x = 0; l_y = 0; + r_x = window->width; + r_y = window->height; + display_flip(); +} + +/* Set a pixel in the terminal cell area */ +static inline void term_set_point(uint16_t x, uint16_t y, uint32_t color ) { + if (_fullscreen) { + /* In full screen mode, pre-blend the color over black. */ + color = alpha_blend_rgba(premultiply(rgba(0,0,0,0xFF)), color); + } + if (!_no_frame) { + GFX(ctx, (x+decor_left_width),(y+decor_top_height+menu_bar_height)) = color; + } else { + GFX(ctx, x,y) = color; + } +} + +/* Draw a partial block character. */ +static void draw_semi_block(int c, int x, int y, uint32_t fg, uint32_t bg) { + int height; + bg = premultiply(bg); + fg = premultiply(fg); + if (c == 0x2580) { + uint32_t t = bg; + bg = fg; + fg = t; + c = 0x2584; + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + term_set_point(x+j,y+i,bg); + } + } + } + c -= 0x2580; + height = char_height - ((c * char_height) / 8); + for (uint8_t i = height; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + term_set_point(x+j, y+i,fg); + } + } +} + +/* Convert unicode codepoint to fallback codepage codepoint */ +static uint32_t ununicode(uint32_t c) { + switch (c) { + case L'☺': return 1; + case L'☻': return 2; + case L'♥': return 3; + case L'♦': return 4; + case L'♣': return 5; + case L'♠': return 6; + case L'•': return 7; + case L'◘': return 8; + case L'○': return 9; + case L'◙': return 10; + case L'♂': return 11; + case L'♀': return 12; + case L'♪': return 13; + case L'♫': return 14; + case L'☼': return 15; + case L'►': return 16; + case L'◄': return 17; + case L'↕': return 18; + case L'‼': return 19; + case L'¶': return 20; + case L'§': return 21; + case L'▬': return 22; + case L'↨': return 23; + case L'↑': return 24; + case L'↓': return 25; + case L'→': return 26; + case L'←': return 27; + case L'∟': return 28; + case L'↔': return 29; + case L'▲': return 30; + case L'▼': return 31; + /* ASCII text */ + case L'⌂': return 127; + case L'Ç': return 128; + case L'ü': return 129; + case L'é': return 130; + case L'â': return 131; + case L'ä': return 132; + case L'à': return 133; + case L'å': return 134; + case L'ç': return 135; + case L'ê': return 136; + case L'ë': return 137; + case L'è': return 138; + case L'ï': return 139; + case L'î': return 140; + case L'ì': return 141; + case L'Ä': return 142; + case L'Å': return 143; + case L'É': return 144; + case L'æ': return 145; + case L'Æ': return 146; + case L'ô': return 147; + case L'ö': return 148; + case L'ò': return 149; + case L'û': return 150; + case L'ù': return 151; + case L'ÿ': return 152; + case L'Ö': return 153; + case L'Ü': return 154; + case L'¢': return 155; + case L'£': return 156; + case L'¥': return 157; + case L'₧': return 158; + case L'ƒ': return 159; + case L'á': return 160; + case L'í': return 161; + case L'ó': return 162; + case L'ú': return 163; + case L'ñ': return 164; + case L'Ñ': return 165; + case L'ª': return 166; + case L'º': return 167; + case L'¿': return 168; + case L'⌐': return 169; + case L'¬': return 170; + case L'½': return 171; + case L'¼': return 172; + case L'¡': return 173; + case L'«': return 174; + case L'»': return 175; + case L'░': return 176; + case L'▒': return 177; + case L'▓': return 178; + case L'│': return 179; + case L'┤': return 180; + case L'╡': return 181; + case L'╢': return 182; + case L'╖': return 183; + case L'╕': return 184; + case L'╣': return 185; + case L'║': return 186; + case L'╗': return 187; + case L'╝': return 188; + case L'╜': return 189; + case L'╛': return 190; + case L'┐': return 191; + case L'└': return 192; + case L'┴': return 193; + case L'┬': return 194; + case L'├': return 195; + case L'─': return 196; + case L'┼': return 197; + case L'╞': return 198; + case L'╟': return 199; + case L'╚': return 200; + case L'╔': return 201; + case L'╩': return 202; + case L'╦': return 203; + case L'╠': return 204; + case L'═': return 205; + case L'╬': return 206; + case L'╧': return 207; + case L'╨': return 208; + case L'╤': return 209; + case L'╥': return 210; + case L'╙': return 211; + case L'╘': return 212; + case L'╒': return 213; + case L'╓': return 214; + case L'╫': return 215; + case L'╪': return 216; + case L'┘': return 217; + case L'┌': return 218; + case L'█': return 219; + case L'▄': return 220; + case L'▌': return 221; + case L'▐': return 222; + case L'▀': return 223; + case L'α': return 224; + case L'ß': return 225; + case L'Γ': return 226; + case L'π': return 227; + case L'Σ': return 228; + case L'σ': return 229; + case L'µ': return 230; + case L'τ': return 231; + case L'Φ': return 232; + case L'Θ': return 233; + case L'Ω': return 234; + case L'δ': return 235; + case L'∞': return 236; + case L'φ': return 237; + case L'ε': return 238; + case L'∩': return 239; + case L'≡': return 240; + case L'±': return 241; + case L'≥': return 242; + case L'≤': return 243; + case L'⌠': return 244; + case L'⌡': return 245; + case L'÷': return 246; + case L'≈': return 247; + case L'°': return 248; + case L'∙': return 249; + case L'·': return 250; + case L'√': return 251; + case L'ⁿ': return 252; + case L'²': return 253; + case L'■': return 254; + } + return 4; +} + +/* Write a character to the window. */ +static void term_write_char(uint32_t val, uint16_t x, uint16_t y, uint32_t fg, uint32_t bg, uint8_t flags) { + uint32_t _fg, _bg; + + /* Select foreground color from palette. */ + if (fg < PALETTE_COLORS) { + _fg = term_colors[fg]; + _fg |= 0xFF << 24; + } else { + _fg = fg; + } + + /* Select background color from aplette. */ + if (bg < PALETTE_COLORS) { + _bg = term_colors[bg]; + if (flags & ANSI_SPECBG) { + _bg |= 0xFF << 24; + } else { + _bg |= TERM_DEFAULT_OPAC << 24; + } + } else { + _bg = bg; + } + + /* Draw block characters */ + if (val >= 0x2580 && val <= 0x2588) { + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + term_set_point(x+j,y+i,premultiply(_bg)); + } + } + draw_semi_block(val, x, y, _fg, _bg); + goto _extra_stuff; + } + + /* Draw glyphs */ + if (_use_aa && !_have_freetype) { + /* Convert other unicode characters. */ + if (val > 128) { + val = ununicode(val); + } + /* Draw using the Toaru SDF rendering library */ + char tmp[2] = {val,0}; + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + term_set_point(x+j,y+i,_bg); + } + } + if (val != 0 && val != ' ' && _fg != _bg) { + int _font = SDF_FONT_MONO; + if (flags & ANSI_BOLD && flags & ANSI_ITALIC) { + _font = SDF_FONT_MONO_BOLD_OBLIQUE; + } else if (flags & ANSI_BOLD) { + _font = SDF_FONT_MONO_BOLD; + } else if (flags & ANSI_ITALIC) { + _font = SDF_FONT_MONO_OBLIQUE; + } + if (_no_frame) { + draw_sdf_string_gamma(ctx, x-1, y, tmp, font_size, _fg, _font, font_gamma); + } else { + draw_sdf_string_gamma(ctx, x+decor_left_width-1, y+decor_top_height+menu_bar_height, tmp, font_size, _fg, _font, font_gamma); + } + } + } else if (_use_aa && _have_freetype) { + /* Draw using freetype extension */ + if (val == 0xFFFF) { return; } /* Unicode, do not redraw here */ + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + term_set_point(x+j,y+i,_bg); + } + } + if (flags & ANSI_WIDE) { + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = char_width; j < 2 * char_width; ++j) { + term_set_point(x+j,y+i,_bg); + } + } + } + if (val < 32 || val == ' ') { + goto _extra_stuff; + } + +#define FONT_MONOSPACE 4 +#define FONT_MONOSPACE_BOLD 5 +#define FONT_MONOSPACE_ITALIC 6 +#define FONT_MONOSPACE_BOLD_ITALIC 7 + int _font = FONT_MONOSPACE; + if (flags & ANSI_BOLD && flags & ANSI_ITALIC) { + _font = FONT_MONOSPACE_BOLD_ITALIC; + } else if (flags & ANSI_ITALIC) { + _font = FONT_MONOSPACE_ITALIC; + } else if (flags & ANSI_BOLD) { + _font = FONT_MONOSPACE_BOLD; + } + freetype_set_font_face(_font); + freetype_set_font_size(font_size); + if (_no_frame) { + freetype_draw_char(ctx, x, y + char_offset, _fg, val); + } else { + freetype_draw_char(ctx, x + decor_left_width, y + char_offset + decor_top_height + menu_bar_height, _fg, val); + } + } else { + /* Convert other unicode characters. */ + if (val > 128) { + val = ununicode(val); + } + /* Draw using the bitmap font. */ + uint16_t * c = large_font[val]; + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + if (c[i] & (1 << (15-j))) { + term_set_point(x+j,y+i,_fg); + } else { + term_set_point(x+j,y+i,_bg); + } + } + } + } + + /* Draw additional text elements, like underlines and cross-outs. */ +_extra_stuff: + if (flags & ANSI_UNDERLINE) { + for (uint8_t i = 0; i < char_width; ++i) { + term_set_point(x + i, y + char_height - 1, _fg); + } + } + if (flags & ANSI_CROSS) { + for (uint8_t i = 0; i < char_width; ++i) { + term_set_point(x + i, y + char_height - 7, _fg); + } + } + if (flags & ANSI_BORDER) { + for (uint8_t i = 0; i < char_height; ++i) { + term_set_point(x , y + i, _fg); + term_set_point(x + (char_width - 1), y + i, _fg); + } + for (uint8_t j = 0; j < char_width; ++j) { + term_set_point(x + j, y, _fg); + term_set_point(x + j, y + (char_height - 1), _fg); + } + } + + /* Calculate the bounds of the updated region of the window */ + if (!_no_frame) { + l_x = min(l_x, decor_left_width + x); + l_y = min(l_y, decor_top_height+menu_bar_height + y); + + if (flags & ANSI_WIDE) { + r_x = max(r_x, decor_left_width + x + char_width * 2); + r_y = max(r_y, decor_top_height+menu_bar_height + y + char_height * 2); + } else { + r_x = max(r_x, decor_left_width + x + char_width); + r_y = max(r_y, decor_top_height+menu_bar_height + y + char_height); + } + } else { + l_x = min(l_x, x); + l_y = min(l_y, y); + + if (flags & ANSI_WIDE) { + r_x = max(r_x, x + char_width * 2); + r_y = max(r_y, y + char_height * 2); + } else { + r_x = max(r_x, x + char_width); + r_y = max(r_y, y + char_height); + } + } +} + +/* Set a terminal cell */ +static void cell_set(uint16_t x, uint16_t y, uint32_t c, uint32_t fg, uint32_t bg, uint32_t flags) { + /* Avoid setting cells out of range. */ + if (x >= term_width || y >= term_height) return; + + /* Calculate the cell position in the terminal buffer */ + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + + /* Set cell attributes */ + cell->c = c; + cell->fg = fg; + cell->bg = bg; + cell->flags = flags; +} + +/* Redraw an embedded image cell */ +static void redraw_cell_image(uint16_t x, uint16_t y, term_cell_t * cell) { + /* Avoid setting cells out of range. */ + if (x >= term_width || y >= term_height) return; + + /* Draw the image data */ + uint32_t * data = (uint32_t *)cell->fg; + for (uint32_t yy = 0; yy < char_height; ++yy) { + for (uint32_t xx = 0; xx < char_width; ++xx) { + term_set_point(x * char_width + xx, y * char_height + yy, *data); + data++; + } + } + + /* Update bounds */ + if (!_no_frame) { + l_x = min(l_x, decor_left_width + x * char_width); + l_y = min(l_y, decor_top_height+menu_bar_height + y * char_height); + r_x = max(r_x, decor_left_width + x * char_width + char_width); + r_y = max(r_y, decor_top_height+menu_bar_height + y * char_height + char_height); + } else { + l_x = min(l_x, x * char_width); + l_y = min(l_y, y * char_height); + r_x = max(r_x, x * char_width + char_width); + r_y = max(r_y, y * char_height + char_height); + } +} + +/* Redraw a text cell normally. */ +static void cell_redraw(uint16_t x, uint16_t y) { + /* Avoid cells out of range. */ + if (x >= term_width || y >= term_height) return; + + /* Calculate the cell position in the terminal buffer */ + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + + /* If it's an image cell, redraw the image data. */ + if (cell->flags & ANSI_EXT_IMG) { + redraw_cell_image(x,y,cell); + return; + } + + /* Special case empty cells. */ + if (((uint32_t *)cell)[0] == 0x00000000) { + term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); + } else { + term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags); + } +} + +/* Redraw text cell inverted. */ +static void cell_redraw_inverted(uint16_t x, uint16_t y) { + /* Avoid cells out of range. */ + if (x >= term_width || y >= term_height) return; + + /* Calculate the cell position in the terminal buffer */ + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + + /* If it's an image cell, redraw the image data. */ + if (cell->flags & ANSI_EXT_IMG) { + redraw_cell_image(x,y,cell); + return; + } + + /* Special case empty cells. */ + if (((uint32_t *)cell)[0] == 0x00000000) { + term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_BG, TERM_DEFAULT_FG, TERM_DEFAULT_FLAGS | ANSI_SPECBG); + } else { + term_write_char(cell->c, x * char_width, y * char_height, cell->bg, cell->fg, cell->flags | ANSI_SPECBG); + } +} + +/* Redraw text cell with a surrounding box (used by cursor) */ +static void cell_redraw_box(uint16_t x, uint16_t y) { + /* Avoid cells out of range. */ + if (x >= term_width || y >= term_height) return; + + /* Calculate the cell position in the terminal buffer */ + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + + /* If it's an image cell, redraw the image data. */ + if (cell->flags & ANSI_EXT_IMG) { + redraw_cell_image(x,y,cell); + return; + } + + /* Special case empty cells. */ + if (((uint32_t *)cell)[0] == 0x00000000) { + term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS | ANSI_BORDER); + } else { + term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags | ANSI_BORDER); + } +} + +/* Draw the cursor cell */ +static void render_cursor() { + if (!window->focused) { + /* An unfocused terminal should draw an unfilled box. */ + cell_redraw_box(csr_x, csr_y); + } else { + /* A focused terminal draws a solid box. */ + cell_redraw_inverted(csr_x, csr_y); + } +} + +static uint8_t cursor_flipped = 0; +/* A soft request to draw the cursor. */ +static void draw_cursor() { + if (!cursor_on) return; + mouse_ticks = get_ticks(); + cursor_flipped = 0; + render_cursor(); +} + +/* Timer callback to flip (flash) the cursor */ +static void maybe_flip_cursor(void) { + uint64_t ticks = get_ticks(); + if (ticks > mouse_ticks + 600000LL) { + mouse_ticks = ticks; + if (scrollback_offset != 0) { + return; /* Don't flip cursor while drawing scrollback */ + } + if (window->focused && cursor_flipped) { + cell_redraw(csr_x, csr_y); + } else { + render_cursor(); + } + display_flip(); + cursor_flipped = 1 - cursor_flipped; + } +} + +/* Draw all cells. Duplicates code from cell_redraw to avoid unecessary bounds checks. */ +static void term_redraw_all() { + for (int i = 0; i < term_height; i++) { + for (int x = 0; x < term_width; ++x) { + /* Calculate the cell position in the terminal buffer */ + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (i * term_width + x) * sizeof(term_cell_t)); + /* If it's an image cell, redraw the image data. */ + if (cell->flags & ANSI_EXT_IMG) { + redraw_cell_image(x,i,cell); + continue; + } + + /* Special case empty cells. */ + if (((uint32_t *)cell)[0] == 0x00000000) { + term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); + } else { + term_write_char(cell->c, x * char_width, i * char_height, cell->fg, cell->bg, cell->flags); + } + } + } +} + +/* Remove no-longer-visible image cell data. */ +static void flush_unused_images(void) { + list_t * tmp = list_create(); + for (int y = 0; y < term_height; ++y) { + for (int x = 0; x < term_width; ++x) { + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + if (cell->flags & ANSI_EXT_IMG) { + list_insert(tmp, (void *)cell->fg); + } + } + } + foreach(node, images_list) { + if (!list_find(tmp, node->value)) { + free(node->value); + } + } + + list_free(images_list); + images_list = tmp; +} + +/* Scroll the terminal up or down. */ +static void term_scroll(int how_much) { + + /* A large scroll request should just clear the screen. */ + if (how_much >= term_height || -how_much >= term_height) { + term_clear(); + return; + } + + /* A request to scroll 0... is a request not to scroll. */ + if (how_much == 0) { + return; + } + + /* Redraw the cursor before continuing. */ + cell_redraw(csr_x, csr_y); + + if (how_much > 0) { + /* Scroll up */ + memmove(term_buffer, (void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width), sizeof(term_cell_t) * term_width * (term_height - how_much)); + /* Reset the "new" row to clean cells */ + memset((void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width * (term_height - how_much)), 0x0, sizeof(term_cell_t) * term_width * how_much); + /* In graphical modes, we will shift the graphics buffer up as necessary */ + uintptr_t dst, src; + size_t siz = char_height * (term_height - how_much) * GFX_W(ctx) * GFX_B(ctx); + if (!_no_frame) { + /* Must include decorations */ + dst = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * (decor_top_height+menu_bar_height)) * GFX_B(ctx); + src = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * (decor_top_height+menu_bar_height + char_height * how_much)) * GFX_B(ctx); + } else { + /* Can skip decorations */ + dst = (uintptr_t)ctx->backbuffer; + src = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * char_height * how_much) * GFX_B(ctx); + } + /* Perform the shift */ + memmove((void *)dst, (void *)src, siz); + /* And redraw the new rows */ + for (int i = 0; i < how_much; ++i) { + for (uint16_t x = 0; x < term_width; ++x) { + cell_set(x,term_height - how_much,' ', current_fg, current_bg, ansi_state->flags); + cell_redraw(x, term_height - how_much); + } + } + } else { + how_much = -how_much; + /* Scroll down */ + memmove((void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width), term_buffer, sizeof(term_cell_t) * term_width * (term_height - how_much)); + /* Reset the "new" row to clean cells */ + memset(term_buffer, 0x0, sizeof(term_cell_t) * term_width * how_much); + uintptr_t dst, src; + size_t siz = char_height * (term_height - how_much) * GFX_W(ctx) * GFX_B(ctx); + if (!_no_frame) { + src = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * (decor_top_height+menu_bar_height)) * GFX_B(ctx); + dst = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * (decor_top_height+menu_bar_height + char_height * how_much)) * GFX_B(ctx); + } else { + src = (uintptr_t)ctx->backbuffer; + dst = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * char_height * how_much) * GFX_B(ctx); + } + /* Perform the shift */ + memmove((void *)dst, (void *)src, siz); + /* And redraw the new rows */ + for (int i = 0; i < how_much; ++i) { + for (uint16_t x = 0; x < term_width; ++x) { + cell_redraw(x, i); + } + } + } + + /* Remove image data for image cells that are no longer on screen. */ + flush_unused_images(); + + /* Flip the entire window. */ + yutani_flip(yctx, window); +} + +/* Is this a wide character? (does wcwidth == 2) */ +static int is_wide(uint32_t codepoint) { + if (codepoint < 256) return 0; + return wcwidth(codepoint) == 2; +} + +/* Save the row that is about to be scrolled offscreen into the scrollback buffer. */ +static void save_scrollback(void) { + + /* If the scrollback is already full, remove the oldest element. */ + if (scrollback_list->length == MAX_SCROLLBACK) { + free(list_dequeue(scrollback_list)); + } + + struct scrollback_row * row = malloc(sizeof(struct scrollback_row) + sizeof(term_cell_t) * term_width + 20); + row->width = term_width; + for (int i = 0; i < term_width; ++i) { + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (i) * sizeof(term_cell_t)); + memcpy(&row->cells[i], cell, sizeof(term_cell_t)); + } + + list_insert(scrollback_list, row); +} + +/* Draw the scrollback. */ +static void redraw_scrollback(void) { + if (!scrollback_offset) { + term_redraw_all(); + display_flip(); + return; + } + if (scrollback_offset < term_height) { + for (int i = scrollback_offset; i < term_height; i++) { + int y = i - scrollback_offset; + for (int x = 0; x < term_width; ++x) { + term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); + if (cell->flags & ANSI_EXT_IMG) { redraw_cell_image(x,i,cell); continue; } + if (((uint32_t *)cell)[0] == 0x00000000) { + term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); + } else { + term_write_char(cell->c, x * char_width, i * char_height, cell->fg, cell->bg, cell->flags); + } + } + } + + node_t * node = scrollback_list->tail; + for (int i = 0; i < scrollback_offset; ++i) { + struct scrollback_row * row = (struct scrollback_row *)node->value; + + int y = scrollback_offset - 1 - i; + int width = row->width; + if (width > term_width) { + width = term_width; + } else { + for (int x = row->width; x < term_width; ++x) { + term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); + } + } + for (int x = 0; x < width; ++x) { + term_cell_t * cell = &row->cells[x]; + if (((uint32_t *)cell)[0] == 0x00000000) { + term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); + } else { + term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags); + } + } + + node = node->prev; + } + } else { + node_t * node = scrollback_list->tail; + for (int i = 0; i < scrollback_offset - term_height; ++i) { + node = node->prev; + } + for (int i = scrollback_offset - term_height; i < scrollback_offset; ++i) { + struct scrollback_row * row = (struct scrollback_row *)node->value; + + int y = scrollback_offset - 1 - i; + int width = row->width; + if (width > term_width) { + width = term_width; + } else { + for (int x = row->width; x < term_width; ++x) { + term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); + } + } + for (int x = 0; x < width; ++x) { + term_cell_t * cell = &row->cells[x]; + if (((uint32_t *)cell)[0] == 0x00000000) { + term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); + } else { + term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags); + } + } + + node = node->prev; + } + } + display_flip(); +} + +/* + * ANSI callback for writing characters. + * Parses some things (\n\r, etc.) itself that should probably + * be moved into the ANSI library. + */ +static void term_write(char c) { + static uint32_t unicode_state = 0; + static uint32_t codepoint = 0; + + cell_redraw(csr_x, csr_y); + + if (!decode(&unicode_state, &codepoint, (uint8_t)c)) { + uint32_t o = codepoint; + codepoint = 0; + if (c == '\r') { + csr_x = 0; + return; + } + if (csr_x < 0) csr_x = 0; + if (csr_y < 0) csr_y = 0; + if (csr_x == term_width) { + csr_x = 0; + ++csr_y; + } + if (csr_y == term_height) { + save_scrollback(); + term_scroll(1); + csr_y = term_height - 1; + } + if (c == '\n') { + if (csr_x == 0 && _hold_out) { + _hold_out = 0; + return; + } + ++csr_y; + if (csr_y == term_height) { + save_scrollback(); + term_scroll(1); + csr_y = term_height - 1; + } + draw_cursor(); + } else if (c == '\007') { + /* bell */ + /* XXX play sound */ + } else if (c == '\b') { + if (csr_x > 0) { + --csr_x; + } + cell_redraw(csr_x, csr_y); + draw_cursor(); + } else if (c == '\t') { + csr_x += (8 - csr_x % 8); + draw_cursor(); + } else { + int wide = is_wide(o); + uint8_t flags = ansi_state->flags; + if (wide && csr_x == term_width - 1) { + csr_x = 0; + ++csr_y; + } + if (wide) { + flags = flags | ANSI_WIDE; + } + cell_set(csr_x,csr_y, o, current_fg, current_bg, flags); + cell_redraw(csr_x,csr_y); + csr_x++; + if (wide && csr_x != term_width) { + cell_set(csr_x, csr_y, 0xFFFF, current_fg, current_bg, ansi_state->flags); + cell_redraw(csr_x,csr_y); + cell_redraw(csr_x-1,csr_y); + csr_x++; + } + } + } else if (unicode_state == UTF8_REJECT) { + unicode_state = 0; + codepoint = 0; + } + draw_cursor(); +} + +/* ANSI callback to set cursor position */ +static void term_set_csr(int x, int y) { + cell_redraw(csr_x,csr_y); + csr_x = x; + csr_y = y; + draw_cursor(); +} + +/* ANSI callback to get cursor x position */ +static int term_get_csr_x(void) { + return csr_x; +} + +/* ANSI callback to get cursor y position */ +static int term_get_csr_y(void) { + return csr_y; +} + +/* ANSI callback to set cell image data. */ +static void term_set_cell_contents(int x, int y, char * data) { + char * cell_data = malloc(char_width * char_height * sizeof(uint32_t)); + memcpy(cell_data, data, char_width * char_height * sizeof(uint32_t)); + list_insert(images_list, cell_data); + cell_set(x, y, ' ', (uint32_t)cell_data, 0, ANSI_EXT_IMG); +} + +/* ANSI callback to get character cell width */ +static int term_get_cell_width(void) { + return char_width; +} + +/* ANSI callback to get character cell height */ +static int term_get_cell_height(void) { + return char_height; +} + +/* ANSI callback to set cursor visibility */ +static void term_set_csr_show(int on) { + cursor_on = on; + if (on) { + draw_cursor(); + } +} + +/* ANSI callback to set the foreground/background colors. */ +static void term_set_colors(uint32_t fg, uint32_t bg) { + current_fg = fg; + current_bg = bg; +} + +/* ANSI callback to force the cursor to draw */ +static void term_redraw_cursor() { + if (term_buffer) { + draw_cursor(); + } +} + +/* ANSI callback to set a cell to a codepoint (only ever used to set spaces) */ +static void term_set_cell(int x, int y, uint32_t c) { + cell_set(x, y, c, current_fg, current_bg, ansi_state->flags); + cell_redraw(x, y); +} + +/* ANSI callback to clear the terminal. */ +static void term_clear(int i) { + if (i == 2) { + /* Clear all */ + csr_x = 0; + csr_y = 0; + memset((void *)term_buffer, 0x00, term_width * term_height * sizeof(term_cell_t)); + if (!_no_frame) { + render_decors(); + } + term_redraw_all(); + } else if (i == 0) { + /* Clear after cursor */ + for (int x = csr_x; x < term_width; ++x) { + term_set_cell(x, csr_y, ' '); + } + for (int y = csr_y + 1; y < term_height; ++y) { + for (int x = 0; x < term_width; ++x) { + term_set_cell(x, y, ' '); + } + } + } else if (i == 1) { + /* Clear before cursor */ + for (int y = 0; y < csr_y; ++y) { + for (int x = 0; x < term_width; ++x) { + term_set_cell(x, y, ' '); + } + } + for (int x = 0; x < csr_x; ++x) { + term_set_cell(x, csr_y, ' '); + } + } + flush_unused_images(); +} + + +#define SWAP(T,a,b) do { T _a = a; a = b; b = _a; } while(0); + +static void term_switch_buffer(int buffer) { + if (buffer != 0 && buffer != 1) return; + if (buffer != active_buffer) { + active_buffer = buffer; + term_buffer = active_buffer == 0 ? term_buffer_a : term_buffer_b; + + SWAP(int, csr_x, _orig_x); + SWAP(int, csr_y, _orig_y); + SWAP(uint32_t, current_fg, _orig_fg); + SWAP(uint32_t, current_bg, _orig_bg); + + term_redraw_all(); + display_flip(); + } + +} + +/* ANSI callbacks */ +term_callbacks_t term_callbacks = { + term_write, + term_set_colors, + term_set_csr, + term_get_csr_x, + term_get_csr_y, + term_set_cell, + term_clear, + term_scroll, + term_redraw_cursor, + input_buffer_stuff, + set_title, + term_set_cell_contents, + term_get_cell_width, + term_get_cell_height, + term_set_csr_show, + term_switch_buffer, +}; + +/* Write data into the PTY */ +static void handle_input(char c) { + write(fd_master, &c, 1); + display_flip(); +} + +/* Write a string into the PTY */ +static void handle_input_s(char * c) { + write(fd_master, c, strlen(c)); + display_flip(); +} + +/* Scroll the view up (scrollback) */ +static void scroll_up(int amount) { + int i = 0; + while (i < amount && scrollback_list && scrollback_offset < (int)scrollback_list->length) { + scrollback_offset ++; + i++; + } + redraw_scrollback(); +} + +/* Scroll the view down (scrollback) */ +void scroll_down(int amount) { + int i = 0; + while (i < amount && scrollback_list && scrollback_offset != 0) { + scrollback_offset -= 1; + i++; + } + redraw_scrollback(); +} + +/* Handle a key press from Yutani */ +static void key_event(int ret, key_event_t * event) { + if (ret) { + /* Ctrl-Shift-C - Copy selection */ + if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) && + (event->modifiers & KEY_MOD_LEFT_CTRL || event->modifiers & KEY_MOD_RIGHT_CTRL) && + (event->keycode == 'c')) { + if (selection) { + /* Copy selection */ + copy_selection(); + } + return; + } + + /* Ctrl-Shift-V - Paste selection */ + if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) && + (event->modifiers & KEY_MOD_LEFT_CTRL || event->modifiers & KEY_MOD_RIGHT_CTRL) && + (event->keycode == 'v')) { + /* Paste selection */ + yutani_special_request(yctx, NULL, YUTANI_SPECIAL_REQUEST_CLIPBOARD); + return; + } + + /* Left alt */ + if (event->modifiers & KEY_MOD_LEFT_ALT || event->modifiers & KEY_MOD_RIGHT_ALT) { + handle_input('\033'); + } + + /* Shift-Tab */ + if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) && + event->key == '\t') { + handle_input_s("\033[Z"); + return; + } + + /* Pass key value to PTY */ + handle_input(event->key); + } else { + /* Special keys without ->key values */ + + /* Only trigger on key down */ + if (event->action == KEY_ACTION_UP) return; + + switch (event->keycode) { + case KEY_F1: + handle_input_s("\033OP"); + break; + case KEY_F2: + handle_input_s("\033OQ"); + break; + case KEY_F3: + handle_input_s("\033OR"); + break; + case KEY_F4: + handle_input_s("\033OS"); + break; + case KEY_F5: + handle_input_s("\033[15~"); + break; + case KEY_F6: + handle_input_s("\033[17~"); + break; + case KEY_F7: + handle_input_s("\033[18~"); + break; + case KEY_F8: + handle_input_s("\033[19~"); + break; + case KEY_F9: + handle_input_s("\033[20~"); + break; + case KEY_F10: + handle_input_s("\033[21~"); + break; + case KEY_F11: + handle_input_s("\033[23~"); + break; + case KEY_F12: + /* Toggle decorations */ + if (!_fullscreen) { + _no_frame = !_no_frame; + window_width = window->width - decor_width * (!_no_frame); + window_height = window->height - (decor_height + menu_bar_height) * (!_no_frame); + reinit(1); + } + break; + case KEY_ARROW_UP: + if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[6A"); + } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[5A"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[4A"); + } else if (event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[3A"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + handle_input_s("\033[2A"); + } else { + handle_input_s("\033[A"); + } + break; + case KEY_ARROW_DOWN: + if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[6B"); + } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[5B"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[4B"); + } else if (event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[3B"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + handle_input_s("\033[2B"); + } else { + handle_input_s("\033[B"); + } + break; + case KEY_ARROW_RIGHT: + if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[6C"); + } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[5C"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[4C"); + } else if (event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[3C"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + handle_input_s("\033[2C"); + } else { + handle_input_s("\033[C"); + } + break; + case KEY_ARROW_LEFT: + if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[6D"); + } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { + handle_input_s("\033[5D"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[4D"); + } else if (event->modifiers & KEY_MOD_LEFT_ALT) { + handle_input_s("\033[3D"); + } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + handle_input_s("\033[2D"); + } else { + handle_input_s("\033[D"); + } + break; + case KEY_PAGE_UP: + if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + scroll_up(term_height/2); + } else { + handle_input_s("\033[5~"); + } + break; + case KEY_PAGE_DOWN: + if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + scroll_down(term_height/2); + } else { + handle_input_s("\033[6~"); + } + break; + case KEY_HOME: + if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + if (scrollback_list) { + scrollback_offset = scrollback_list->length; + redraw_scrollback(); + } + } else { + handle_input_s("\033[H"); + } + break; + case KEY_END: + if (event->modifiers & KEY_MOD_LEFT_SHIFT) { + scrollback_offset = 0; + redraw_scrollback(); + } else { + handle_input_s("\033[F"); + } + break; + case KEY_DEL: + handle_input_s("\033[3~"); + break; + case KEY_INSERT: + handle_input_s("\033[2~"); + break; + } + } +} + +/* Check if the Terminal should close. */ +static void check_for_exit(void) { + + /* If something has set exit_application, we should exit. */ + if (exit_application) return; + + pid_t pid = waitpid(-1, NULL, WNOHANG); + + /* If the child has exited, we should exit. */ + if (pid != child_pid) return; + + /* Clean up */ + exit_application = 1; + + /* Write [Process terminated] */ + char exit_message[] = "[Process terminated]\n"; + write(fd_slave, exit_message, sizeof(exit_message)); +} + +static term_cell_t * copy_terminal(int old_width, int old_height, term_cell_t * term_buffer) { + term_cell_t * new_term_buffer = malloc(sizeof(term_cell_t) * term_width * term_height); + + memset(new_term_buffer, 0x0, sizeof(term_cell_t) * term_width * term_height); + + int offset = 0; + if (term_height < old_height) { + while (csr_y >= term_height) { + offset++; + old_height--; + csr_y--; + } + } + for (int row = 0; row < min(old_height, term_height); ++row) { + for (int col = 0; col < min(old_width, term_width); ++col) { + term_cell_t * old_cell = (term_cell_t *)((uintptr_t)term_buffer + ((row + offset) * old_width + col) * sizeof(term_cell_t)); + term_cell_t * new_cell = (term_cell_t *)((uintptr_t)new_term_buffer + (row * term_width + col) * sizeof(term_cell_t)); + *new_cell = *old_cell; + } + } + if (csr_x >= term_width) { + csr_x = term_width-1; + } + + return new_term_buffer; +} + +/* Reinitialize the terminal after a resize. */ +static void reinit(int send_sig) { + + /* Figure out character sizes if fonts have changed. */ + if (_use_aa && !_have_freetype) { + char_width = 9; + char_height = 17; + font_size = 16; + if (scale_fonts) { + font_size *= font_scaling; + char_height *= font_scaling; + char_width *= font_scaling; + } + } else if (_use_aa && _have_freetype) { + font_size = 13; + char_height = 17; + char_width = 8; + char_offset = 13; + + if (scale_fonts) { + /* Recalculate scaling */ + font_size *= font_scaling; + char_height *= font_scaling; + char_width *= font_scaling; + char_offset *= font_scaling; + } + } else { + char_width = 9; + char_height = 20; + } + + int old_width = term_width; + int old_height = term_height; + + /* Resize the terminal buffer */ + term_width = window_width / char_width; + term_height = window_height / char_height; + if (term_buffer) { + term_cell_t * new_a = copy_terminal(old_width, old_height, term_buffer_a); + term_cell_t * new_b = copy_terminal(old_width, old_height, term_buffer_b); + free(term_buffer_a); + term_buffer_a = new_a; + free(term_buffer_b); + term_buffer_b = new_b; + if (active_buffer == 0) { + term_buffer = new_a; + } else { + term_buffer = new_b; + } + } else { + term_buffer_a = malloc(sizeof(term_cell_t) * term_width * term_height); + memset(term_buffer_a, 0x0, sizeof(term_cell_t) * term_width * term_height); + + term_buffer_b = malloc(sizeof(term_cell_t) * term_width * term_height); + memset(term_buffer_b, 0x0, sizeof(term_cell_t) * term_width * term_height); + + term_buffer = term_buffer_a; + } + + /* Reset the ANSI library, ensuring we keep certain values */ + int old_mouse_state = 0; + if (ansi_state) old_mouse_state = ansi_state->mouse_on; + ansi_state = ansi_init(ansi_state, term_width, term_height, &term_callbacks); + ansi_state->mouse_on = old_mouse_state; + + /* Redraw the window */ + draw_fill(ctx, rgba(0,0,0, TERM_DEFAULT_OPAC)); + render_decors(); + term_redraw_all(); + display_flip(); + + /* Send window size change ioctl */ + struct winsize w; + w.ws_row = term_height; + w.ws_col = term_width; + w.ws_xpixel = term_width * char_width; + w.ws_ypixel = term_height * char_height; + ioctl(fd_master, TIOCSWINSZ, &w); + + /* If requested, send a signal to the application. */ + if (send_sig) { + kill(child_pid, SIGWINCH); + } +} + +static void update_bounds(void) { + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); + + decor_left_width = bounds.left_width; + decor_top_height = bounds.top_height; + decor_right_width = bounds.right_width; + decor_bottom_height = bounds.bottom_height; + decor_width = bounds.width; + decor_height = bounds.height; +} + +/* Handle window resize event. */ +static void resize_finish(int width, int height) { + static int resize_attempts = 0; + + int extra_x = 0; + int extra_y = 0; + + /* Calculate window size */ + if (!_no_frame) { + update_bounds(); + + extra_x = decor_width; + extra_y = decor_height + menu_bar_height; + } + + int t_window_width = width - extra_x; + int t_window_height = height - extra_y; + + /* Prevent the terminal from becoming too small. */ + if (t_window_width < char_width * 20 || t_window_height < char_height * 10) { + resize_attempts++; + int n_width = extra_x + max(char_width * 20, t_window_width); + int n_height = extra_y + max(char_height * 10, t_window_height); + yutani_window_resize_offer(yctx, window, n_width, n_height); + return; + } + + /* If requested, ensure the terminal resizes to a fixed size based on the cell size. */ + if (!_free_size && ((t_window_width % char_width != 0 || t_window_height % char_height != 0) && resize_attempts < 3)) { + resize_attempts++; + int n_width = extra_x + t_window_width - (t_window_width % char_width); + int n_height = extra_y + t_window_height - (t_window_height % char_height); + yutani_window_resize_offer(yctx, window, n_width, n_height); + return; + } + + resize_attempts = 0; + + /* Accept new window size */ + yutani_window_resize_accept(yctx, window, width, height); + window_width = window->width - extra_x; + window_height = window->height - extra_y; + + /* Reinitialize the graphics library */ + reinit_graphics_yutani(ctx, window); + + /* Reinitialize the terminal buffer and ANSI library */ + reinit(1); + + /* We are done resizing. */ + yutani_window_resize_done(yctx, window); + yutani_flip(yctx, window); +} + +/* Insert a mouse event sequence into the PTY */ +static void mouse_event(int button, int x, int y) { + char buf[7]; + sprintf(buf, "\033[M%c%c%c", button + 32, x + 33, y + 33); + handle_input_s(buf); +} + +/* Handle Yutani messages */ +static void * handle_incoming(void) { + + yutani_msg_t * m = yutani_poll(yctx); + while (m) { + if (menu_process_event(yctx, m)) { + render_decors(); + } + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + int ret = (ke->event.action == KEY_ACTION_DOWN) && (ke->event.key); + key_event(ret, &ke->event); + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * wf = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + if (win == window) { + win->focused = wf->focused; + render_decors(); + } + } + break; + case YUTANI_MSG_WINDOW_CLOSE: + { + struct yutani_msg_window_close * wc = (void*)m->data; + if (wc->wid == window->wid) { + kill(child_pid, SIGKILL); + exit_application = 1; + } + } + break; + case YUTANI_MSG_SESSION_END: + { + kill(child_pid, SIGKILL); + exit_application = 1; + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + resize_finish(wr->width, wr->height); + } + break; + case YUTANI_MSG_CLIPBOARD: + { + struct yutani_msg_clipboard * cb = (void *)m->data; + if (selection_text) { + free(selection_text); + } + if (*cb->content == '\002') { + int size = atoi(&cb->content[2]); + FILE * clipboard = yutani_open_clipboard(yctx); + selection_text = malloc(size + 1); + fread(selection_text, 1, size, clipboard); + selection_text[size] = '\0'; + fclose(clipboard); + } else { + selection_text = malloc(cb->size+1); + memcpy(selection_text, cb->content, cb->size); + selection_text[cb->size] = '\0'; + } + handle_input_s(selection_text); + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + if (me->wid != window->wid) break; + if (!_no_frame) { + int decor_response = decor_handle_event(yctx, m); + + switch (decor_response) { + case DECOR_CLOSE: + kill(child_pid, SIGKILL); + exit_application = 1; + break; + case DECOR_RIGHT: + /* right click in decoration, show appropriate menu */ + decor_show_default_menu(window, window->x + me->new_x, window->y + me->new_y); + break; + default: + break; + } + + menu_bar_mouse_event(yctx, window, &terminal_menu_bar, me, me->new_x, me->new_y); + } + + if (me->new_x < 0 || me->new_y < 0) break; + if (!_no_frame) { + if (me->new_x >= (int)window_width + (int)decor_width) break; + if (me->new_y < (int)decor_top_height+menu_bar_height) break; + if (me->new_y >= (int)(window_height + decor_top_height+menu_bar_height)) break; + if (me->new_x < (int)decor_left_width) break; + if (me->new_x >= (int)(window_width + decor_left_width)) break; + } else { + if (me->new_x >= (int)window_width) break; + if (me->new_y >= (int)window_height) break; + } + + int new_x = me->new_x; + int new_y = me->new_y; + if (!_no_frame) { + new_x -= decor_left_width; + new_y -= decor_top_height+menu_bar_height; + } + /* Convert from coordinate to cell positon */ + new_x /= char_width; + new_y /= char_height; + + if (new_x < 0 || new_y < 0) break; + if (new_x > term_width || new_y > term_height) break; + + /* Map Cursor Action */ + if (ansi_state->mouse_on) { + + if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { + mouse_event(32+32, new_x, new_y); + } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { + mouse_event(32+32+1, new_x, new_y); + } + + if (me->buttons != button_state) { + /* Figure out what changed */ + if (me->buttons & YUTANI_MOUSE_BUTTON_LEFT && + !(button_state & YUTANI_MOUSE_BUTTON_LEFT)) + mouse_event(0, new_x, new_y); + if (me->buttons & YUTANI_MOUSE_BUTTON_MIDDLE && + !(button_state & YUTANI_MOUSE_BUTTON_MIDDLE)) + mouse_event(1, new_x, new_y); + if (me->buttons & YUTANI_MOUSE_BUTTON_RIGHT && + !(button_state & YUTANI_MOUSE_BUTTON_RIGHT)) + mouse_event(2, new_x, new_y); + if (!(me->buttons & YUTANI_MOUSE_BUTTON_LEFT) && + button_state & YUTANI_MOUSE_BUTTON_LEFT) + mouse_event(3, new_x, new_y); + if (!(me->buttons & YUTANI_MOUSE_BUTTON_MIDDLE) && + button_state & YUTANI_MOUSE_BUTTON_MIDDLE) + mouse_event(3, new_x, new_y); + if (!(me->buttons & YUTANI_MOUSE_BUTTON_RIGHT) && + button_state & YUTANI_MOUSE_BUTTON_RIGHT) + mouse_event(3, new_x, new_y); + last_mouse_x = new_x; + last_mouse_y = new_y; + button_state = me->buttons; + } else if (ansi_state->mouse_on == 2) { + /* Report motion for pressed buttons */ + if (last_mouse_x == new_x && last_mouse_y == new_y) break; + if (button_state & YUTANI_MOUSE_BUTTON_LEFT) mouse_event(32, new_x, new_y); + if (button_state & YUTANI_MOUSE_BUTTON_MIDDLE) mouse_event(33, new_x, new_y); + if (button_state & YUTANI_MOUSE_BUTTON_RIGHT) mouse_event(34, new_x, new_y); + last_mouse_x = new_x; + last_mouse_y = new_y; + } + } else { + if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { + term_redraw_all(); + selection_start_x = new_x; + selection_start_y = new_y; + selection_end_x = new_x; + selection_end_y = new_y; + selection = 1; + redraw_selection(); + display_flip(); + } + if (me->command == YUTANI_MOUSE_EVENT_DRAG && me->buttons & YUTANI_MOUSE_BUTTON_LEFT ){ + int old_end_x = selection_end_x; + int old_end_y = selection_end_y; + selection_end_x = new_x; + selection_end_y = new_y; + redraw_new_selection(old_end_x, old_end_y); + display_flip(); + } + if (me->command == YUTANI_MOUSE_EVENT_RAISE) { + if (me->new_x == me->old_x && me->new_y == me->old_y) { + selection = 0; + term_redraw_all(); + display_flip(); + } /* else selection */ + } + if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { + scroll_up(5); + } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { + scroll_down(5); + } else if (me->buttons & YUTANI_MOUSE_BUTTON_RIGHT) { + if (!menu_right_click->window) { + menu_show(menu_right_click, yctx); + if (window->x + me->new_x + menu_right_click->window->width > yctx->display_width) { + yutani_window_move(yctx, menu_right_click->window, window->x + me->new_x - menu_right_click->window->width, window->y + me->new_y); + } else { + yutani_window_move(yctx, menu_right_click->window, window->x + me->new_x, window->y + me->new_y); + } + } + } + } + } + break; + default: + break; + } + free(m); + m = yutani_poll_async(yctx); + } + + return NULL; +} + +/* + * Menu Actions + */ + +/* File > Exit */ +static void _menu_action_exit(struct MenuEntry * self) { + kill(child_pid, SIGKILL); + exit_application = 1; +} + +/* We need to track these so we can retitle both of them */ +static struct MenuEntry * _menu_toggle_borders_context = NULL; +static struct MenuEntry * _menu_toggle_borders_bar = NULL; + +static void _menu_action_hide_borders(struct MenuEntry * self) { + _no_frame = !(_no_frame); + window_width = window->width - decor_width * (!_no_frame); + window_height = window->height - (decor_height + menu_bar_height) * (!_no_frame); + menu_update_title(_menu_toggle_borders_context, _no_frame ? "Show borders" : "Hide borders"); + menu_update_title(_menu_toggle_borders_bar, _no_frame ? "Show borders" : "Hide borders"); + reinit(1); +} + +static void _menu_action_toggle_sdf(struct MenuEntry * self) { + _use_aa = !(_use_aa); + menu_update_title(self, _use_aa ? "Bitmap font" : "Anti-aliased font"); + reinit(1); +} + +static void _menu_action_show_about(struct MenuEntry * self) { + char about_cmd[1024] = "\0"; + strcat(about_cmd, "about \"About Terminal\" /usr/share/icons/48/utilities-terminal.bmp \"ToaruOS Terminal\" \"(C) 2013-2018 K. Lange\n-\nPart of ToaruOS, which is free software\nreleased under the NCSA/University of Illinois\nlicense.\n-\n%https://toaruos.org\n%https://gitlab.com/toaruos\" "); + char coords[100]; + sprintf(coords, "%d %d &", (int)window->x + (int)window->width / 2, (int)window->y + (int)window->height / 2); + strcat(about_cmd, coords); + system(about_cmd); + render_decors(); +} + +static void _menu_action_show_help(struct MenuEntry * self) { + system("help-browser terminal.trt &"); + render_decors(); +} + +static void _menu_action_copy(struct MenuEntry * self) { + copy_selection(); +} + +static void _menu_action_paste(struct MenuEntry * self) { + yutani_special_request(yctx, NULL, YUTANI_SPECIAL_REQUEST_CLIPBOARD); +} + +static void _menu_action_set_scale(struct MenuEntry * self) { + struct MenuEntry_Normal * _self = (struct MenuEntry_Normal *)self; + if (!_self->action) { + scale_fonts = 0; + font_scaling = 1.0; + } else { + scale_fonts = 1; + font_scaling = atof(_self->action); + } + reinit(1); +} + +int main(int argc, char ** argv) { + + window_width = char_width * 80; + window_height = char_height * 24; + + static struct option long_opts[] = { + {"fullscreen", no_argument, 0, 'F'}, + {"bitmap", no_argument, 0, 'b'}, + {"scale", required_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"grid", no_argument, 0, 'x'}, + {"no-frame", no_argument, 0, 'n'}, + {"geometry", required_argument, 0, 'g'}, + {"no-ft", no_argument, 0, 'f'}, + {0,0,0,0} + }; + + /* Read some arguments */ + int index, c; + while ((c = getopt_long(argc, argv, "bhxnfFls:g:", long_opts, &index)) != -1) { + if (!c) { + if (long_opts[index].flag == 0) { + c = long_opts[index].val; + } + } + switch (c) { + case 'x': + _free_size = 0; + break; + case 'n': + _no_frame = 1; + break; + case 'f': + _force_no_ft = 1; + break; + case 'F': + _fullscreen = 1; + _no_frame = 1; + break; + case 'b': + _use_aa = 0; + break; + case 'h': + usage(argv); + return 0; + break; + case 's': + scale_fonts = 1; + font_scaling = atof(optarg); + break; + case 'g': + { + char * c = strstr(optarg, "x"); + if (c) { + *c = '\0'; + c++; + window_width = atoi(optarg); + window_height = atoi(c); + } + } + break; + case '?': + break; + default: + break; + } + } + + if (!_force_no_ft) { + void * freetype = dlopen("libtoaru_ext_freetype_fonts.so", 0); + if (freetype) { + _have_freetype = 1; + freetype_set_font_face = dlsym(freetype, "freetype_set_font_face"); + freetype_set_font_size = dlsym(freetype, "freetype_set_font_size"); + freetype_draw_char = dlsym(freetype, "freetype_draw_char"); + } + } + + /* Initialize the windowing library */ + yctx = yutani_init(); + + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } + + /* Full screen mode forces window size to be that the display server */ + if (_fullscreen) { + window_width = yctx->display_width; + window_height = yctx->display_height; + } + + if (_no_frame) { + window = yutani_window_create(yctx, window_width, window_height); + } else { + init_decorations(); + struct decor_bounds bounds; + decor_get_bounds(NULL, &bounds); + window = yutani_window_create(yctx, window_width + bounds.width, window_height + bounds.height + menu_bar_height); + update_bounds(); + } + + if (_fullscreen) { + /* If fullscreen, assume we're always focused and put us on the bottom. */ + yutani_set_stack(yctx, window, YUTANI_ZORDER_BOTTOM); + window->focused = 1; + } else { + window->focused = 0; + } + + /* Set up menus */ + terminal_menu_bar.entries = terminal_menu_entries; + terminal_menu_bar.redraw_callback = render_decors; + + struct MenuEntry * _menu_exit = menu_create_normal("exit","exit","Exit", _menu_action_exit); + struct MenuEntry * _menu_copy = menu_create_normal(NULL, NULL, "Copy", _menu_action_copy); + struct MenuEntry * _menu_paste = menu_create_normal(NULL, NULL, "Paste", _menu_action_paste); + + menu_right_click = menu_create(); + menu_insert(menu_right_click, _menu_copy); + menu_insert(menu_right_click, _menu_paste); + menu_insert(menu_right_click, menu_create_separator()); + _menu_toggle_borders_context = menu_create_normal(NULL, NULL, _no_frame ? "Show borders" : "Hide borders", _menu_action_hide_borders); + menu_insert(menu_right_click, _menu_toggle_borders_context); + menu_insert(menu_right_click, menu_create_separator()); + menu_insert(menu_right_click, _menu_exit); + + /* Menu Bar menus */ + terminal_menu_bar.set = menu_set_create(); + struct MenuList * m; + m = menu_create(); /* File */ + menu_insert(m, _menu_exit); + menu_set_insert(terminal_menu_bar.set, "file", m); + + m = menu_create(); + menu_insert(m, _menu_copy); + menu_insert(m, _menu_paste); + menu_set_insert(terminal_menu_bar.set, "edit", m); + + m = menu_create(); + menu_insert(m, menu_create_normal(NULL, "0.75", "75%", _menu_action_set_scale)); + menu_insert(m, menu_create_normal(NULL, NULL, "100%", _menu_action_set_scale)); + menu_insert(m, menu_create_normal(NULL, "1.5", "150%", _menu_action_set_scale)); + menu_insert(m, menu_create_normal(NULL, "2.0", "200%", _menu_action_set_scale)); + menu_set_insert(terminal_menu_bar.set, "zoom", m); + + m = menu_create(); + _menu_toggle_borders_bar = menu_create_normal(NULL, NULL, _no_frame ? "Show borders" : "Hide borders", _menu_action_hide_borders); + menu_insert(m, _menu_toggle_borders_bar); + menu_insert(m, menu_create_submenu(NULL,"zoom","Set zoom...")); + menu_insert(m, menu_create_normal(NULL, NULL, _use_aa ? "Bitmap font" : "Anti-aliased font", _menu_action_toggle_sdf)); + menu_set_insert(terminal_menu_bar.set, "view", m); + + m = menu_create(); + menu_insert(m, menu_create_normal("help","help","Contents", _menu_action_show_help)); + menu_insert(m, menu_create_separator()); + menu_insert(m, menu_create_normal("star","star","About Terminal", _menu_action_show_about)); + menu_set_insert(terminal_menu_bar.set, "help", m); + + scrollback_list = list_create(); + images_list = list_create(); + + /* Initialize the graphics context */ + ctx = init_graphics_yutani_double_buffer(window); + + /* Clear to black */ + draw_fill(ctx, rgba(0,0,0,0)); + + /* Move window to screen center (XXX maybe remove this and do better window placement elsewhere */ + yutani_window_move(yctx, window, yctx->display_width / 2 - window->width / 2, yctx->display_height / 2 - window->height / 2); + + /* Open a PTY */ + openpty(&fd_master, &fd_slave, NULL, NULL, NULL); + terminal = fdopen(fd_slave, "w"); + + /* Initialize the terminal buffer and ANSI library for the first time. */ + reinit(0); + + /* Make sure we're not passing anything to stdin on the child */ + fflush(stdin); + + /* Fork off child */ + child_pid = fork(); + + if (!child_pid) { + /* Prepare stdin/out/err */ + dup2(fd_slave, 0); + dup2(fd_slave, 1); + dup2(fd_slave, 2); + + /* Set the TERM environment variable. */ + putenv("TERM=toaru"); + + /* Execute requested initial process */ + if (argv[optind] != NULL) { + /* Run something specified by the terminal startup */ + char * tokens[] = {argv[optind], NULL}; + execvp(tokens[0], tokens); + fprintf(stderr, "Failed to launch requested startup application.\n"); + } else { + /* Run the user's shell */ + char * shell = getenv("SHELL"); + if (!shell) shell = "/bin/sh"; /* fallback */ + char * tokens[] = {shell,NULL}; + execvp(tokens[0], tokens); + exit(1); + } + + /* Failed to start */ + exit_application = 1; + return 1; + } else { + + /* Set up fswait to check Yutani and the PTY master */ + int fds[2] = {fileno(yctx->sock), fd_master}; + + /* PTY read buffer */ + unsigned char buf[1024]; + + while (!exit_application) { + + /* Wait for something to happen. */ + int index = fswait2(2,fds,200); + + /* Check if the child application has closed. */ + check_for_exit(); + + if (index == 1) { + /* Read from PTY */ + maybe_flip_cursor(); + int r = read(fd_master, buf, 1024); + for (int i = 0; i < r; ++i) { + ansi_put(ansi_state, buf[i]); + } + display_flip(); + } else if (index == 0) { + /* Handle Yutani events. */ + maybe_flip_cursor(); + handle_incoming(); + } else if (index == 2) { + /* Timeout, flip the cursor. */ + maybe_flip_cursor(); + } + } + } + + /* Windows will close automatically on exit. */ + return 0; +} diff --git a/apps/test-conf.c b/apps/test-conf.c new file mode 100644 index 00000000..9f0324ff --- /dev/null +++ b/apps/test-conf.c @@ -0,0 +1,25 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * test-conf - simple test app for confreader + */ +#include +#include +#include +#include + + +int main(int argc, char * argv[]) { + confreader_t * conf = confreader_load("/etc/demo.conf"); + + fprintf(stderr, "test 1\n"); + assert(confreader_get(conf, "", "test") != NULL); + assert(!strcmp(confreader_get(conf, "", "test"),"hello")); + + fprintf(stderr, "test 2\n"); + assert(!strcmp(confreader_get(conf,"sec","tion"),"test")); + + return 0; +} diff --git a/apps/test.sh b/apps/test.sh new file mode 100644 index 00000000..aea03646 --- /dev/null +++ b/apps/test.sh @@ -0,0 +1,5 @@ +#!/bin/sh +export-cmd UNAME uname +export-cmd DATE date +echo "This is a test shell script." +echo "This is $UNAME and it is $DATE" diff --git a/userspace/extra/toaru_logo.h b/apps/toaru_logo.h similarity index 95% rename from userspace/extra/toaru_logo.h rename to apps/toaru_logo.h index efca693b..89454823 100644 --- a/userspace/extra/toaru_logo.h +++ b/apps/toaru_logo.h @@ -1,4 +1,13 @@ -/* GIMP RGBA C-Source image dump (toaru_logo.c) */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2012 K. Lange + * + * toaru_logo.h - Generated by GIMP, ToaruOS logo + * + * Used by sysinfo. Can be used by other things as well. + * TODO: sysinfo should probably just load a bitmap? + */ static const struct { unsigned int width; diff --git a/apps/toggle-abs-mouse.c b/apps/toggle-abs-mouse.c new file mode 100644 index 00000000..93702eab --- /dev/null +++ b/apps/toggle-abs-mouse.c @@ -0,0 +1,48 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * toggle-abs-mouse - Toggle mouse modes + * + * Set the mouse mode under VirtualBox, VMware, or QEMU to either + * relative or absolute via ioctl to the relevant absolute mouse + * device driver interface. + */ +#include +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + if (argc < 2) { + fprintf(stderr, "%s: argument (relative or absolute) expected\n", argv[0]); + return 1; + } + + int fd = open("/dev/absmouse",O_WRONLY); + if (fd < 0) { + /* try vmmouse */ + fd = open("/dev/vmmouse",O_WRONLY); + if (fd < 0) { + fprintf(stderr, "%s: no valid mouse interface found.\n", argv[0]); + return 1; + } + } + + int flag = 0; + if (!strcmp(argv[1],"relative")) { + flag = 1; + } + if (!strcmp(argv[1],"absolute")) { + flag = 2; + } + + if (!flag) { + fprintf(stderr, "%s: invalid argument\n", argv[0]); + return 1; + } + + ioctl(fd, flag, NULL); +} diff --git a/apps/touch.c b/apps/touch.c new file mode 100644 index 00000000..999c1f7d --- /dev/null +++ b/apps/touch.c @@ -0,0 +1,30 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013 K. Lange + * + * touch - Create or update file timestamps + * + */ +#include +#include +#include + +int main(int argc, char * argv[]) { + if (argc < 2) { + fprintf(stderr, "%s: argument expected\n", argv[0]); + return 1; + } + + int out = 0; + for (int i = 1; i < argc; ++i) { + FILE * f = fopen(argv[i], "a"); + if (!f) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno)); + out = 1; + } + fclose(f); + } + + return out; +} diff --git a/apps/true.c b/apps/true.c new file mode 100644 index 00000000..db6d62ee --- /dev/null +++ b/apps/true.c @@ -0,0 +1,10 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * true - Return success code + */ +int main() { + return 0; +} diff --git a/apps/ttysize.c b/apps/ttysize.c new file mode 100644 index 00000000..1daa77a7 --- /dev/null +++ b/apps/ttysize.c @@ -0,0 +1,112 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * ttysize - Magically divine terminal size + * + * This is called by getty to determine the size of foreign + * terminals, such as ones attached over serial. + * + * It works by placing the cursor in the lower right of the + * screen and requesting its position. Note that typing things + * while this happens can cause problems. Maybe we can flush + * stdin before doing this to try to avoid any conflicting data? + */ +#include +#include +#include +#include +#include +#include +#include + +static struct termios old; + +static void set_unbuffered() { + tcgetattr(fileno(stdin), &old); + struct termios new = old; + new.c_lflag &= (~ICANON & ~ECHO); + tcsetattr(fileno(stdin), TCSAFLUSH, &new); +} + +static void set_buffered() { + tcsetattr(fileno(stdin), TCSAFLUSH, &old); +} + +static int getc_timeout(FILE * f, int timeout) { + int fds[1] = {fileno(f)}; + int index = fswait2(1,fds,timeout); + if (index == 0) { + return fgetc(f); + } else { + return -1; + } +} + +static void divine_size(int * width, int * height) { + set_unbuffered(); + + *width = 80; + *height = 24; + + fprintf(stderr, "\033[s\033[1000;1000H\033[6n\033[u"); + fflush(stderr); + + char buf[1024] = {0}; + size_t i = 0; + while (1) { + char c = getc_timeout(stdin, 200); + if (c == 'R') break; + if (c == -1) goto _done; + if (c == '\033') continue; + if (c == '[') continue; + buf[i++] = c; + } + + char * s = strstr(buf, ";"); + if (s) { + *(s++) = '\0'; + + *height = atoi(buf); + *width = atoi(s); + } + +_done: + fflush(stderr); + set_buffered(); +} + +int main(int argc, char * argv[]) { + int width, height; + int opt; + int quiet = 0; + + while ((opt = getopt(argc, argv, "q")) != -1) { + switch (opt) { + case 'q': + quiet = 1; + break; + } + } + + if (optind + 2 == argc) { + width = atoi(argv[optind]); + height = atoi(argv[optind+1]); + } else { + divine_size(&width, &height); + } + + struct winsize w; + w.ws_col = width; + w.ws_row = height; + w.ws_xpixel = 0; + w.ws_ypixel = 0; + ioctl(0, TIOCSWINSZ, &w); + + if (!quiet) { + fprintf(stderr, "%dx%d\n", width, height); + } + + return 0; +} diff --git a/userspace/core/uname.c b/apps/uname.c similarity index 55% rename from userspace/core/uname.c rename to apps/uname.c index 92d736b2..19d3eb09 100644 --- a/userspace/core/uname.c +++ b/apps/uname.c @@ -1,15 +1,18 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ /* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange * - * uname + * uname - Print kernel version information * - * Prints the kernel version information. + * Supports all the usual options (a,s,n,r,v,m,o) + * + * Note that o is hardcoded, which is also the situation in + * the coreutils implementation, so I don't see that being + * a problem. If you want to build this uname for Linux or + * something... you'll have to change that. */ #include -#include #include #include #include @@ -19,8 +22,9 @@ #define FLAG_RELEASE 0x04 #define FLAG_VERSION 0x08 #define FLAG_MACHINE 0x10 +#define FLAG_OSNAME 0x20 -#define FLAG_ALL (FLAG_SYSNAME|FLAG_NODENAME|FLAG_RELEASE|FLAG_VERSION|FLAG_MACHINE) +#define FLAG_ALL (FLAG_SYSNAME|FLAG_NODENAME|FLAG_RELEASE|FLAG_VERSION|FLAG_MACHINE|FLAG_OSNAME) #define _ITALIC "\033[3m" #define _END "\033[0m\n" @@ -29,7 +33,7 @@ void show_usage(int argc, char * argv[]) { fprintf(stderr, "uname - Print system version information.\n" "\n" - "usage: %s [-asnrvm]\n" + "usage: %s [-asnrvmp]\n" "\n" " -a " _ITALIC "Print the standard uname string we all love" _END " -s " _ITALIC "Print kernel name" _END @@ -37,6 +41,8 @@ void show_usage(int argc, char * argv[]) { " -r " _ITALIC "Print kernel version number" _END " -v " _ITALIC "Print the extra kernel version information" _END " -m " _ITALIC "Print the architecture name" _END + " -o " _ITALIC "Print operating system name" _END + " -p " _ITALIC "Alias to -m" _END "\n", argv[0]); exit(1); } @@ -44,34 +50,43 @@ void show_usage(int argc, char * argv[]) { int main(int argc, char * argv[]) { struct utsname u; - int c; int flags = 0; int space = 0; - while ((c = getopt(argc, argv, "ahmnrsv")) != -1) { - switch (c) { - case 'a': - flags |= FLAG_ALL; - break; - case 's': - flags |= FLAG_SYSNAME; - break; - case 'n': - flags |= FLAG_NODENAME; - break; - case 'r': - flags |= FLAG_RELEASE; - break; - case 'v': - flags |= FLAG_VERSION; - break; - case 'm': - flags |= FLAG_MACHINE; - break; - case 'h': - default: - show_usage(argc, argv); - break; + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + char *c = &argv[i][1]; + while (*c) { + switch (*c) { + case 'a': + flags |= FLAG_ALL; + break; + case 's': + flags |= FLAG_SYSNAME; + break; + case 'n': + flags |= FLAG_NODENAME; + break; + case 'r': + flags |= FLAG_RELEASE; + break; + case 'v': + flags |= FLAG_VERSION; + break; + case 'm': + case 'p': + flags |= FLAG_MACHINE; + break; + case 'o': + flags |= FLAG_OSNAME; + break; + case 'h': + default: + show_usage(argc, argv); + break; + } + c++; + } } } @@ -107,6 +122,11 @@ int main(int argc, char * argv[]) { printf("%s", u.machine); } + if (flags & FLAG_OSNAME) { + if (space++) printf(" "); + printf("%s", "ToaruOS"); + } + printf("\n"); return 0; diff --git a/userspace/core/uptime.c b/apps/uptime.c similarity index 70% rename from userspace/core/uptime.c rename to apps/uptime.c index 7da8628a..df5a19b4 100644 --- a/userspace/core/uptime.c +++ b/apps/uptime.c @@ -1,7 +1,15 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015-2018 K. Lange + * + * uptime - Print system uptime + */ #include #include +#include +#include #include -#include #include void print_time(void) { @@ -44,9 +52,16 @@ void print_uptime(void) { FILE * f = fopen("/proc/uptime", "r"); if (!f) return; - int seconds, subseconds; + int seconds; - fscanf(f, "%d.%2d", &seconds, &subseconds); + char buf[1024] = {0}; + fgets(buf, 1024, f); + char * dot = strchr(buf, '.'); + *dot = '\0'; + dot++; + dot[3] = '\0'; + + seconds = atoi(buf); printf("up "); @@ -66,18 +81,16 @@ void show_usage(int argc, char * argv[]) { int main(int argc, char * argv[]) { int just_pretty_uptime = 0; + int opt; - if (argc > 1) { - int index, c; - while ((c = getopt(argc, argv, "p?")) != -1) { - switch (c) { - case 'p': - just_pretty_uptime = 1; - break; - case '?': - show_usage(argc, argv); - return 0; - } + while ((opt = getopt(argc, argv, "?p")) != -1 ) { + switch (opt) { + case 'p': + just_pretty_uptime = 1; + break; + case '?': + show_usage(argc, argv); + return 0; } } diff --git a/userspace/gui/terminal/vga-palette.h b/apps/vga-palette.h similarity index 92% rename from userspace/gui/terminal/vga-palette.h rename to apps/vga-palette.h index ed4775f4..6e946c48 100644 --- a/userspace/gui/terminal/vga-palette.h +++ b/apps/vga-palette.h @@ -1,3 +1,16 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2012-2018 K. Lange + * + * vga-palette.h - 256-to-VGA palette + * + * Converts 256-color index values to closest matching 16-color + * value for the VGA terminal. Note that values here are terminal + * color codes, not the VGA color codes - the terminal converts + * them to VGA color codes later. This was automatically generated + * from a script, but I don't know where that script went. + */ #define PALETTE_COLORS 256 uint32_t vga_colors[PALETTE_COLORS] = { 0x0, diff --git a/apps/wc.c b/apps/wc.c new file mode 100644 index 00000000..511865cf --- /dev/null +++ b/apps/wc.c @@ -0,0 +1,131 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * wc - count bytes, characters, words, lines... + */ +#include +#include +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + int show_lines = 0; + int show_words = 0; + int show_chars = 0; + int show_bytes = 0; + + int opt; + + while ((opt = getopt(argc,argv,"cmlw")) != -1) { + switch (opt) { + case 'c': + show_bytes = 1; + break; + case 'm': + show_chars = 1; + break; + case 'l': + show_lines = 1; + break; + case 'w': + show_words = 1; + break; + } + } + + int retval = 0; + int total_lines = 0; + int total_chars = 0; + int total_words = 0; + int just_stdin = 0; + + if (optind == argc) { + argv[optind] = ""; + argc++; + just_stdin = 1; + } + + for (int i = optind; i < argc; ++i) { + if (!*argv[i] && !just_stdin) { + fprintf(stderr, "%s: invalid zero-length file name\n", argv[0]); + retval = 1; + continue; + } + FILE * f = (!strcmp(argv[i], "-") || just_stdin) ? stdin : fopen(argv[i], "r"); + if (!f) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno)); + retval = 1; + continue; + } + + int lines = 0; + int chars = 0; + int words = 0; + int ch; + uint32_t state, c; + int last_was_whitespace = 0; + + while (!feof(f)) { + ch = getc(f); + if (ch < 0) break; + + if (show_chars) { + if (!decode(&state, &c, ch)) { + } else if (state == UTF8_REJECT) { + state = 0; + } + } else { + c = ch; + } + + chars++; + if (c == '\n') { + last_was_whitespace = 1; + lines++; + words++; + } else if (c == ' ') { + if (last_was_whitespace) continue; + last_was_whitespace = 1; + words++; + } else { + last_was_whitespace = 0; + } + } + + if (!last_was_whitespace && chars > 0) words++; + + if (!show_words && !show_chars && !show_bytes && !show_lines) { + fprintf(stdout, "%d %d %d %s\n", lines, words, chars, argv[i]); + } else { + if (show_lines) fprintf(stdout, "%d ", lines); + if (show_words) fprintf(stdout, "%d ", words); + if (show_bytes|show_chars) fprintf(stdout, "%d ", chars); + fprintf(stdout, "%s\n", argv[i]); + } + + total_lines += lines; + total_words += words; + total_chars += chars; + + if (f != stdin) fclose(f); + if (just_stdin) return 0; + } + + if (optind + 1 < argc) { + if (!show_words && !show_chars && !show_bytes && !show_lines) { + fprintf(stdout, "%d %d %d %s\n", total_lines, total_words, total_chars, "total"); + } else { + if (show_lines) fprintf(stdout, "%d ", total_lines); + if (show_words) fprintf(stdout, "%d ", total_words); + if (show_bytes|show_chars) fprintf(stdout, "%d ", total_chars); + fprintf(stdout, "%s\n", "total"); + } + } + + return retval; +} + diff --git a/userspace/core/which.c b/apps/which.c similarity index 70% rename from userspace/core/which.c rename to apps/which.c index c6f24ba7..06028005 100644 --- a/userspace/core/which.c +++ b/apps/which.c @@ -1,17 +1,20 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2014 K. Lange * - * which + * which - Figure out which binary will be used * - * Searches through PATH to find an executable. + * Searches through $PATH to find a matching binary, just like + * how execp* family does it. (Except does our execp actually + * bother checking permissions? Look into this...) */ #include #include #include #include -#define DEFAULT_PATH ".:/bin:/usr/bin" +#define DEFAULT_PATH "/bin:/usr/bin" int main(int argc, char * argv[]) { @@ -35,9 +38,7 @@ int main(int argc, char * argv[]) { } char * xpath = strdup(path); - int found = 0; - char * p, * tokens[10], * last; - int i = 0; + char * p, * last; for ((p = strtok_r(xpath, ":", &last)); p; p = strtok_r(NULL, ":", &last)) { int r; struct stat stat_buf; diff --git a/userspace/core/whoami.c b/apps/whoami.c similarity index 92% rename from userspace/core/whoami.c rename to apps/whoami.c index 5381ed52..e8ddf36d 100644 --- a/userspace/core/whoami.c +++ b/apps/whoami.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2014 K. Lange * * Who Am I? * diff --git a/userspace/core/yes.c b/apps/yes.c similarity index 74% rename from userspace/core/yes.c rename to apps/yes.c index ad28c467..f9af926a 100644 --- a/userspace/core/yes.c +++ b/apps/yes.c @@ -1,10 +1,9 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ /* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013 K Lange * - * yes + * yes - Continually print stuff * * Continually prints its first argument, followed by a newline. */ diff --git a/apps/yutani-clipboard.c b/apps/yutani-clipboard.c new file mode 100644 index 00000000..deafad85 --- /dev/null +++ b/apps/yutani-clipboard.c @@ -0,0 +1,111 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * yutani-clipboard - Manipulate the Yutani clipboard + * + * Gets and sets clipboard values. + */ +#include +#include +#include + +#include + +void show_usage(int argc, char * argv[]) { + printf( + "yutani-clipboard - set and obtain clipboard contents\n" + "\n" + "usage: %s -g\n" + " %s -s TEXT...\n" + " %s -f FILE\n" + "\n" + " -s \033[3mset the clipboard text to argument\033[0m\n" + " -f \033[3mset the clibboard text to file\033[0m\n" + " -g \033[3mprint clipboard contents to stdout\033[0m\n" + " -n \033[3mensure a linefeed is printed\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0], argv[0], argv[0]); +} + +yutani_t * yctx; +int force_linefeed = 0; + +int set_clipboard_from_file(char * file) { + FILE * f; + + f = fopen(file, "r"); + if (!f) return 1; + + fseek(f, 0, SEEK_END); + size_t size = ftell(f); + fseek(f, 0, SEEK_SET); + + char * tmp = malloc(size); + fread(tmp, 1, size, f); + + yutani_set_clipboard(yctx, tmp); + + free(tmp); + + return 0; +} + +void get_clipboard(void) { + yutani_special_request(yctx, NULL, YUTANI_SPECIAL_REQUEST_CLIPBOARD); + yutani_msg_t * clipboard = yutani_wait_for(yctx, YUTANI_MSG_CLIPBOARD); + struct yutani_msg_clipboard * cb = (void *)clipboard->data; + + if (*cb->content == '\002') { + int size = atoi(&cb->content[2]); + FILE * clipboard = yutani_open_clipboard(yctx); + char * selection_text = malloc(size + 1); + fread(selection_text, 1, size, clipboard); + selection_text[size] = '\0'; + fclose(clipboard); + fwrite(selection_text, 1, size, stdout); + if (force_linefeed && size && selection_text[size-1] != '\n') { + printf("\n"); + } + } else { + char * selection_text = malloc(cb->size+1); + memcpy(selection_text, cb->content, cb->size); + selection_text[cb->size] = '\0'; + fwrite(selection_text, 1, cb->size, stdout); + if (force_linefeed && cb->size && selection_text[cb->size-1] != '\n') { + printf("\n"); + } + } + +} + +int main(int argc, char * argv[]) { + yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } + int opt; + while ((opt = getopt(argc, argv, "?s:f:gn")) != -1) { + switch (opt) { + case 's': + yutani_set_clipboard(yctx, optarg); + return 0; + case 'f': + return set_clipboard_from_file(optarg); + case 'n': + force_linefeed = 1; + break; + case 'g': + get_clipboard(); + return 0; + case '?': + show_usage(argc,argv); + return 1; + } + } + + show_usage(argc, argv); + return 1; +} diff --git a/apps/yutani-query.c b/apps/yutani-query.c new file mode 100644 index 00000000..079dece2 --- /dev/null +++ b/apps/yutani-query.c @@ -0,0 +1,59 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015-2018 K. Lange + * + * yutani-query - Query display server information + * + * At the moment, this only supports querying the display + * resolution. An older version of this application had + * support for getting the default font names, but the + * font server is no longer part of the compositor, so + * that functionality doesn't make sense here. + */ +#include +#include + +#include + +yutani_t * yctx; + +void show_usage(int argc, char * argv[]) { + printf( + "yutani-query - show misc. information about the display system\n" + "\n" + "usage: %s [-r?]\n" + "\n" + " -r \033[3mprint display resoluton\033[0m\n" + " -e \033[3mask compositor to reload extensions\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); +} + +int show_resolution(void) { + printf("%dx%d\n", (int)yctx->display_width, (int)yctx->display_height); + return 0; +} + +int main(int argc, char * argv[]) { + yctx = yutani_init(); + if (!yctx) { + printf("(not connected)\n"); + return 1; + } + int opt; + while ((opt = getopt(argc, argv, "?re")) != -1) { + switch (opt) { + case 'r': + return show_resolution(); + case 'e': + yutani_special_request(yctx, NULL, YUTANI_SPECIAL_REQUEST_RELOAD); + return 0; + case '?': + show_usage(argc,argv); + return 0; + } + } + + return 0; +} diff --git a/userspace/gui/basic/yutani-test.c b/apps/yutani-test.c similarity index 89% rename from userspace/gui/basic/yutani-test.c rename to apps/yutani-test.c index d3c3dbd3..130dcfda 100644 --- a/userspace/gui/basic/yutani-test.c +++ b/apps/yutani-test.c @@ -1,8 +1,9 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Kevin Lange + * Copyright (C) 2015-2018 K. Lange * - * Yutani Test Tool + * yutani-test - Yutani Test Tool * * Kinda like xev: Pops up a window and displays events in a * human-readable format. @@ -10,12 +11,10 @@ */ #include #include -#include #include -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/pthread.h" +#include +#include static int left, top, width, height; @@ -144,10 +143,10 @@ int main (int argc, char ** argv) { "\told = %d, %d\n" "\tbuttons = %s\n" "\tcommand = %d\n", - me->wid, + (int)me->wid, mouse_command(me->command), - me->new_x, me->new_y, - me->old_x, me->old_y, + (int)me->new_x, (int)me->new_y, + (int)me->old_x, (int)me->old_y, mouse_buttons(me->buttons), me->command); } @@ -161,7 +160,7 @@ int main (int argc, char ** argv) { case YUTANI_MSG_WINDOW_MOVE: { struct yutani_msg_window_move * wm = (void*)m->data; - fprintf(stderr, "Window Moved (wid=%d) %d, %d\n", wm->wid, wm->x, wm->y); + fprintf(stderr, "Window Moved (wid=%d) %d, %d\n", (int)wm->wid, (int)wm->x, (int)wm->y); } break; case YUTANI_MSG_RESIZE_OFFER: @@ -169,11 +168,12 @@ int main (int argc, char ** argv) { struct yutani_msg_window_resize * wr = (void*)m->data; fprintf(stderr, "Resize Offer (wid=%d) %d x %d\n" "\tbufid = %d\n", - wr->wid, - wr->width, wr->height, - wr->bufid); + (int)wr->wid, + (int)wr->width, (int)wr->height, + (int)wr->bufid); } break; + case YUTANI_MSG_WINDOW_CLOSE: case YUTANI_MSG_SESSION_END: should_exit = 1; break; diff --git a/base/etc/default.desktop b/base/etc/default.desktop new file mode 100644 index 00000000..fcff755e --- /dev/null +++ b/base/etc/default.desktop @@ -0,0 +1 @@ +utilities-terminal,terminal,Terminal diff --git a/base/etc/demo.conf b/base/etc/demo.conf new file mode 100644 index 00000000..5b1e9d8a --- /dev/null +++ b/base/etc/demo.conf @@ -0,0 +1,7 @@ +; this is a comment +test=hello + +[sec] +tion=test + +; this is also a comment diff --git a/base/etc/hostname b/base/etc/hostname new file mode 100644 index 00000000..f1060b43 --- /dev/null +++ b/base/etc/hostname @@ -0,0 +1 @@ +livecd diff --git a/base/etc/master.passwd b/base/etc/master.passwd new file mode 100644 index 00000000..f064c87e --- /dev/null +++ b/base/etc/master.passwd @@ -0,0 +1,2 @@ +root:toor:0:0:Administrator:/home/root:/bin/sh:fancy +local:local:1000:1000:Local User:/home/local:/bin/sh:fancy diff --git a/base/etc/menu.desktop b/base/etc/menu.desktop new file mode 100644 index 00000000..0746830e --- /dev/null +++ b/base/etc/menu.desktop @@ -0,0 +1,5 @@ +utilities-terminal,terminal,Terminal +drawlines,drawlines,Draw Lines +julia,julia,Julia Fractals +plasma,plasma,Plasma +star,about,About ToaruOS diff --git a/hdd/etc/motd b/base/etc/motd similarity index 73% rename from hdd/etc/motd rename to base/etc/motd index 3d2ae1be..2ca34e1c 100644 --- a/hdd/etc/motd +++ b/base/etc/motd @@ -4,5 +4,5 @@ ToaruOS is free software, released under the terms of the NCSA / University of Illinois License. -http://github.com/klange/toaruos +https://toaruos.org https://gitlab.com/toaruos diff --git a/base/etc/passwd b/base/etc/passwd new file mode 100644 index 00000000..3c66eb70 --- /dev/null +++ b/base/etc/passwd @@ -0,0 +1,2 @@ +root:x:0:0:Administrator:/home/root:/bin/sh:fancy +local:x:1000:1000:Local User:/home/local:/bin/sh:fancy diff --git a/base/etc/sdf.conf b/base/etc/sdf.conf new file mode 100644 index 00000000..a6081c61 --- /dev/null +++ b/base/etc/sdf.conf @@ -0,0 +1,191 @@ +! b 20 +" b 35 +# b 40 +$ b 35 +% b 35 +& b 35 +' b 35 +( b 22 +) b 22 +* b 35 ++ b 35 +, b 35 +- b 30 +. b 18 +/ b 24 +0 b 32 +1 b 32 +2 b 32 +3 b 32 +4 b 32 +5 b 32 +6 b 32 +7 b 32 +8 b 32 +9 b 32 +: b 22 +; b 22 +< b 35 += b 35 +> b 35 +? b 35 +@ b 50 +A b 35 +B b 35 +C b 34 +D b 36 +E b 34 +F b 34 +G b 35 +H b 35 +I b 22 +J b 24 +K b 35 +L b 32 +M b 45 +N b 36 +O b 38 +P b 35 +Q b 38 +R b 36 +S b 35 +T b 35 +U b 35 +V b 37 +W b 50 +X b 35 +Y b 32 +Z b 35 +[ b 35 +\ b 35 +] b 35 +^ b 35 +_ b 35 +` b 35 +a b 32 +b b 32 +c b 29 +d b 32 +e b 32 +f b 25 +g b 32 +h b 32 +i b 16 +j b 16 +k b 30 +l b 16 +m b 47 +n b 33 +o b 32 +p b 32 +q b 32 +r b 25 +s b 31 +t b 26 +u b 32 +v b 32 +w b 42 +x b 32 +y b 32 +z b 32 +{ b 32 +| b 32 +} b 32 +~ b 32 + b 20 +! t 16 +" t 28 +# t 32 +$ t 28 +% t 28 +& t 28 +' t 17 +( t 17 +) t 17 +* t 28 ++ t 28 +, t 28 +- t 24 +. t 14 +/ t 19 +0 t 25 +1 t 25 +2 t 25 +3 t 25 +4 t 25 +5 t 25 +6 t 25 +7 t 25 +8 t 25 +9 t 25 +: t 17 +; t 17 +< t 28 += t 28 +> t 28 +? t 28 +@ t 40 +A t 29 +B t 28 +C t 27 +D t 30 +E t 27 +F t 27 +G t 28 +H t 28 +I t 15 +J t 15 +K t 28 +L t 25 +M t 36 +N t 28 +O t 30 +P t 28 +Q t 30 +R t 28 +S t 28 +T t 28 +U t 28 +V t 29 +W t 40 +X t 28 +Y t 25 +Z t 28 +[ t 28 +\ t 28 +] t 28 +^ t 28 +_ t 28 +` t 28 +a t 25 +b t 25 +c t 23 +d t 25 +e t 25 +f t 20 +g t 25 +h t 25 +i t 12 +j t 12 +k t 24 +l t 12 +m t 38 +n t 26 +o t 25 +p t 25 +q t 25 +r t 20 +s t 24 +t t 20 +u t 25 +v t 25 +w t 33 +x t 25 +y t 25 +z t 25 +{ t 25 +| t 25 +} t 25 +~ t 25 + t 15 + diff --git a/base/etc/startup.d/00_migrate.sh b/base/etc/startup.d/00_migrate.sh new file mode 100755 index 00000000..6481a2fb --- /dev/null +++ b/base/etc/startup.d/00_migrate.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +if kcmdline -q migrate then /bin/migrate diff --git a/base/etc/startup.d/01_hostname.sh b/base/etc/startup.d/01_hostname.sh new file mode 100755 index 00000000..b521bca6 --- /dev/null +++ b/base/etc/startup.d/01_hostname.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +export-cmd HOSTNAME cat /etc/hostname + +if empty? "$HOSTNAME" then exec hostname "localhost" else exec hostname "$HOSTNAME" diff --git a/base/etc/startup.d/01_mountcd.sh b/base/etc/startup.d/01_mountcd.sh new file mode 100755 index 00000000..003a6d26 --- /dev/null +++ b/base/etc/startup.d/01_mountcd.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +if stat -Lq /dev/cdrom0 then mount iso /dev/cdrom0 /cdrom diff --git a/base/etc/startup.d/90_qemu_hack.sh b/base/etc/startup.d/90_qemu_hack.sh new file mode 100755 index 00000000..a8c6ebfe --- /dev/null +++ b/base/etc/startup.d/90_qemu_hack.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +if qemu-fwcfg -q opt/org.toaruos.displayharness then /bin/qemu-display-hack diff --git a/base/etc/startup.d/91_font_server.sh b/base/etc/startup.d/91_font_server.sh new file mode 100755 index 00000000..8f9d5077 --- /dev/null +++ b/base/etc/startup.d/91_font_server.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +# Only start if we're likely to be running a GUI +export-cmd START kcmdline -g start +if equals? "$START" "--vga" then exit +if equals? "$START" "--headless" then exit + +if stat -Lq /usr/share/fonts/DejaVuSansMono.ttf then font-server diff --git a/base/etc/startup.d/98_qemu_login.sh b/base/etc/startup.d/98_qemu_login.sh new file mode 100755 index 00000000..c2067d78 --- /dev/null +++ b/base/etc/startup.d/98_qemu_login.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +if not qemu-fwcfg -q opt/org.toaruos.forceuser then exit 0 + +export-cmd QEMU_USER qemu-fwcfg opt/org.toaruos.forceuser +/bin/getty -a "$QEMU_USER" +reboot + diff --git a/base/etc/startup.d/99_runstart.sh b/base/etc/startup.d/99_runstart.sh new file mode 100755 index 00000000..4642ca06 --- /dev/null +++ b/base/etc/startup.d/99_runstart.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +export-cmd START kcmdline -g start + +if equals? "$START" "--vga" then exec /bin/terminal-vga -l +if equals? "$START" "--headless" then exec /bin/getty +if empty? "$START" then exec /bin/compositor else exec /bin/compositor $START + diff --git a/hdd/etc/weather.json b/base/etc/weather.json similarity index 100% rename from hdd/etc/weather.json rename to base/etc/weather.json diff --git a/base/home/local/.bimrc b/base/home/local/.bimrc new file mode 100644 index 00000000..d76f8277 --- /dev/null +++ b/base/home/local/.bimrc @@ -0,0 +1,4 @@ +# Nice 256-color default +theme=sunsmoke +# Enable experimental history support +history diff --git a/base/home/local/.eshrc b/base/home/local/.eshrc new file mode 100644 index 00000000..ace0f29c --- /dev/null +++ b/base/home/local/.eshrc @@ -0,0 +1,10 @@ +export PS1_TITLE="\[\e]1;\u@\h:\w\\007\e]2;\u@\h:\w\\007\]" +export PS1_RIGHT="\[\\e[1m\e[38;5;59m\][\[\e[38;5;173m\]\d \[\e[38;5;167m\]\t\[\e[38;5;59m\]] " +export PS1_LEFT="${PS1_TITLE}\[\e[1m\e[38;5;221m\]\u\[\e[38;5;59m\]@\[\e[38;5;81m\]\h \[\e[38;5;167m\]\r\[\e[0m\]\w\U\\\$\[\e[0m\] " +export RLINE_THEME="sunsmoke" +# Old prompt +export PS1="\e]1;\u@\h:\w\\007\e]2;\u@\\h:\w\007\\e[1m\e[s\e[400C\e[16D\e[1m\e[38;5;59m[\e[38;5;173m\d \e[38;5;167m\t\e[38;5;59m]\e[u\e[38;5;221m\u\e[38;5;59m@\e[38;5;81m\h \e[38;5;167m\r\e[0m\w\U\\\$\e[0m " + +export-cmd START kcmdline -g start +if equals? "$START" "--vga" then export RLINE_THEME="default" else export RLINE_THEME="sunsmoke" +unset START diff --git a/base/home/local/.yutanirc b/base/home/local/.yutanirc new file mode 100755 index 00000000..d2849c47 --- /dev/null +++ b/base/home/local/.yutanirc @@ -0,0 +1,5 @@ +#!/bin/sh + +if stat -Lq /usr/share/fonts/DejaVuSansMono.ttf then export FREETYPE_PROPERTIES="truetype:interpreter-version=35" +background --really & +exec panel --really diff --git a/base/home/local/README b/base/home/local/README new file mode 100644 index 00000000..aeb8078d --- /dev/null +++ b/base/home/local/README @@ -0,0 +1,18 @@ +Welcome to ToaruOS! + +ToaruOS provides a familiar Unix-like environment, but please be aware that +the shell is incomplete and does not implement all Unix shell features. For +help with the shell's syntax and built-in functions, run `help`. For a list +of available commands, hit Tab twice. Tab completion is available for both +commands and file names. + +To edit files, try using `bim` - a vi-like editor with syntax highlighting, +line and character selection, history stack, and tabs. + +ToaruOS's compositing window server includes many common keybindings: +- Hold Alt to drag windows. +- Super (Win) combined with the arrow keys will "grid" windows to the sides + or top and bottom of the screen. Combine with Ctrl and Shift for quarter- + sized gridding. +- Alt-F10 maximized and unmaximizes windows. +- Alt-F4 closes windows. diff --git a/base/home/root/hello b/base/home/root/hello new file mode 100644 index 00000000..f12f4c1e --- /dev/null +++ b/base/home/root/hello @@ -0,0 +1 @@ +Hello, root. diff --git a/hdd/bin/.dummy b/base/usr/bin/.dummy similarity index 100% rename from hdd/bin/.dummy rename to base/usr/bin/.dummy diff --git a/base/usr/include/_xlog.h b/base/usr/include/_xlog.h new file mode 100644 index 00000000..826547b9 --- /dev/null +++ b/base/usr/include/_xlog.h @@ -0,0 +1,15 @@ +#include +#include + +#include + +#define _XLOG(_msg) do { \ + char * msg[] = { \ + __FILE__, \ + (char*)__LINE__, \ + (char*)2, \ + _msg, \ + }; \ + syscall_system_function(12, msg); \ +} while (0); + diff --git a/base/usr/include/alloca.h b/base/usr/include/alloca.h new file mode 100644 index 00000000..a4e1fc38 --- /dev/null +++ b/base/usr/include/alloca.h @@ -0,0 +1,8 @@ +#pragma once + +#ifdef __GNUC__ +#define alloca(size) __builtin_alloca(size) +#else +#error alloca requested but this isn't gcc +#endif + diff --git a/base/usr/include/assert.h b/base/usr/include/assert.h new file mode 100644 index 00000000..6f12cbd2 --- /dev/null +++ b/base/usr/include/assert.h @@ -0,0 +1,5 @@ +#ifndef NDEBUG +#define assert(statement) ((statement) ? (void)0 : __assert_func(__FILE__, __LINE__, __FUNCTION__, #statement)) +#else +#define assert(statement) ((void)0) +#endif diff --git a/toolchain/patches/newlib/toaru/bits/dirent.h b/base/usr/include/bits/dirent.h similarity index 91% rename from toolchain/patches/newlib/toaru/bits/dirent.h rename to base/usr/include/bits/dirent.h index 43b051c9..e148fea0 100644 --- a/toolchain/patches/newlib/toaru/bits/dirent.h +++ b/base/usr/include/bits/dirent.h @@ -1,4 +1,4 @@ -#ifndef DIRENT_H +#pragma once #include @@ -16,4 +16,3 @@ DIR * opendir (const char * dirname); int closedir (DIR * dir); struct dirent * readdir (DIR * dirp); -#endif diff --git a/base/usr/include/ctype.h b/base/usr/include/ctype.h new file mode 100644 index 00000000..78a0bc04 --- /dev/null +++ b/base/usr/include/ctype.h @@ -0,0 +1,19 @@ +#pragma once + +extern int isalnum(int c); +extern int isalpha(int c); +extern int isdigit(int c); +extern int islower(int c); +extern int isprint(int c); +extern int isgraph(int c); +extern int iscntrl(int c); +extern int isgraph(int c); +extern int ispunct(int c); +extern int isspace(int c); +extern int isupper(int c); +extern int isxdigit(int c); + +extern int isascii(int c); + +extern int tolower(int c); +extern int toupper(int c); diff --git a/toolchain/patches/newlib/toaru/sys/dirent.h b/base/usr/include/dirent.h similarity index 64% rename from toolchain/patches/newlib/toaru/sys/dirent.h rename to base/usr/include/dirent.h index 1d985c9b..9a68b451 100644 --- a/toolchain/patches/newlib/toaru/sys/dirent.h +++ b/base/usr/include/dirent.h @@ -1 +1,3 @@ +#pragma once + #include diff --git a/base/usr/include/dlfcn.h b/base/usr/include/dlfcn.h new file mode 100644 index 00000000..20924d39 --- /dev/null +++ b/base/usr/include/dlfcn.h @@ -0,0 +1,15 @@ +#pragma once + +/* Currently unused... */ +#define RTLD_LAZY (1 << 0) +#define RTLD_NOW (1 << 1) +#define RTLD_GLOBAL (1 << 2) + +#define RTLD_DEFAULT ((void*)0) + +/* Provided by ld.so, but also defined by libc.so for linking */ +extern void * dlopen(const char *, int); +extern int dlclose(void *); +extern void * dlsym(void *, const char *); +extern char * dlerror(void); + diff --git a/toolchain/patches/newlib/toaru/sys/errno_defs.h b/base/usr/include/errno.h similarity index 98% rename from toolchain/patches/newlib/toaru/sys/errno_defs.h rename to base/usr/include/errno.h index 44ff32b7..8d63d9d4 100644 --- a/toolchain/patches/newlib/toaru/sys/errno_defs.h +++ b/base/usr/include/errno.h @@ -129,3 +129,7 @@ #define ESTRPIPE 143 /* Streams pipe error */ #define EWOULDBLOCK EAGAIN /* Operation would block */ +#ifndef _KERNEL_ +extern int errno; +#define __sets_errno(...) int ret = __VA_ARGS__; if (ret < 0) { errno = -ret; ret = -1; } return ret +#endif diff --git a/base/usr/include/fcntl.h b/base/usr/include/fcntl.h new file mode 100644 index 00000000..94293be0 --- /dev/null +++ b/base/usr/include/fcntl.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_APPEND 0x0008 +#define O_CREAT 0x0200 +#define O_TRUNC 0x0400 +#define O_EXCL 0x0800 +#define O_NOFOLLOW 0x1000 +#define O_PATH 0x2000 +#define O_NONBLOCK 0x4000 + +#define F_OK 1 +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 + +#define F_GETFD 1 +#define F_SETFD 2 + +#define F_GETFL 3 +#define F_SETFL 4 + +/* Advisory locks are not currently supported; + * these definitions are stubs. */ +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +#define FD_CLOEXEC (1 << 0) + +extern int open (const char *, int, ...); +extern int chmod(const char *path, mode_t mode); +extern int fcntl(int fd, int cmd, ...); diff --git a/base/usr/include/getopt.h b/base/usr/include/getopt.h new file mode 100644 index 00000000..1b52053e --- /dev/null +++ b/base/usr/include/getopt.h @@ -0,0 +1,17 @@ +#pragma once + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +extern char * optarg; +extern int optind, opterr, optopt; + +extern int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex); + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 /* Unsupported */ diff --git a/base/usr/include/inttypes.h b/base/usr/include/inttypes.h new file mode 100644 index 00000000..c087963c --- /dev/null +++ b/base/usr/include/inttypes.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +#define PRIi8 "i" +#define PRIi16 "i" +#define PRIi32 "i" diff --git a/kernel/include/args.h b/base/usr/include/kernel/args.h similarity index 100% rename from kernel/include/args.h rename to base/usr/include/kernel/args.h diff --git a/kernel/include/ata.h b/base/usr/include/kernel/ata.h similarity index 100% rename from kernel/include/ata.h rename to base/usr/include/kernel/ata.h diff --git a/kernel/include/bitset.h b/base/usr/include/kernel/bitset.h similarity index 93% rename from kernel/include/bitset.h rename to base/usr/include/kernel/bitset.h index 3e4934d0..ccd3efb7 100644 --- a/kernel/include/bitset.h +++ b/base/usr/include/kernel/bitset.h @@ -2,7 +2,7 @@ */ #pragma once -#include +#include typedef struct { unsigned char *data; diff --git a/kernel/include/boot.h b/base/usr/include/kernel/boot.h similarity index 86% rename from kernel/include/boot.h rename to base/usr/include/kernel/boot.h index 1a01c826..34683981 100644 --- a/kernel/include/boot.h +++ b/base/usr/include/kernel/boot.h @@ -8,7 +8,7 @@ * information from that bootloader. * */ -#include +#include /* * Multiboot @@ -16,5 +16,5 @@ * Also supported natively by QEMU and a few * other emulators. */ -#include +#include diff --git a/kernel/include/elf.h b/base/usr/include/kernel/elf.h similarity index 99% rename from kernel/include/elf.h rename to base/usr/include/kernel/elf.h index 628e63d7..75204398 100644 --- a/kernel/include/elf.h +++ b/base/usr/include/kernel/elf.h @@ -11,7 +11,7 @@ * require different header files for definitions */ #ifdef _KERNEL_ -# include +# include #else # include #endif diff --git a/kernel/include/ext2.h b/base/usr/include/kernel/ext2.h similarity index 98% rename from kernel/include/ext2.h rename to base/usr/include/kernel/ext2.h index 5e8cbcb7..965af6cc 100644 --- a/kernel/include/ext2.h +++ b/base/usr/include/kernel/ext2.h @@ -3,10 +3,10 @@ #pragma once #ifdef _KERNEL_ -# include +# include #else # ifdef BOOTLOADER -# include +# include # else # include # endif diff --git a/kernel/include/fs.h b/base/usr/include/kernel/fs.h similarity index 94% rename from kernel/include/fs.h rename to base/usr/include/kernel/fs.h index d207f0d4..c8039540 100644 --- a/kernel/include/fs.h +++ b/base/usr/include/kernel/fs.h @@ -43,13 +43,13 @@ typedef void (*open_type_t) (struct fs_node *, unsigned int flags); typedef void (*close_type_t) (struct fs_node *); typedef struct dirent *(*readdir_type_t) (struct fs_node *, uint32_t); typedef struct fs_node *(*finddir_type_t) (struct fs_node *, char *name); -typedef void (*create_type_t) (struct fs_node *, char *name, uint16_t permission); -typedef void (*unlink_type_t) (struct fs_node *, char *name); -typedef void (*mkdir_type_t) (struct fs_node *, char *name, uint16_t permission); +typedef int (*create_type_t) (struct fs_node *, char *name, uint16_t permission); +typedef int (*unlink_type_t) (struct fs_node *, char *name); +typedef int (*mkdir_type_t) (struct fs_node *, char *name, uint16_t permission); typedef int (*ioctl_type_t) (struct fs_node *, int request, void * argp); typedef int (*get_size_type_t) (struct fs_node *); typedef int (*chmod_type_t) (struct fs_node *, int mode); -typedef void (*symlink_type_t) (struct fs_node *, char * name, char * value); +typedef int (*symlink_type_t) (struct fs_node *, char * name, char * value); typedef int (*readlink_type_t) (struct fs_node *, char * buf, size_t size); typedef int (*selectcheck_type_t) (struct fs_node *); typedef int (*selectwait_type_t) (struct fs_node *, void * process); diff --git a/kernel/include/ipv4.h b/base/usr/include/kernel/ipv4.h similarity index 99% rename from kernel/include/ipv4.h rename to base/usr/include/kernel/ipv4.h index 61de0c37..078f0b5b 100644 --- a/kernel/include/ipv4.h +++ b/base/usr/include/kernel/ipv4.h @@ -1,6 +1,6 @@ #pragma once -#include +#include struct ethernet_packet { uint8_t destination[6]; diff --git a/kernel/include/libc.h b/base/usr/include/kernel/libc.h similarity index 100% rename from kernel/include/libc.h rename to base/usr/include/kernel/libc.h diff --git a/kernel/include/logging.h b/base/usr/include/kernel/logging.h similarity index 100% rename from kernel/include/logging.h rename to base/usr/include/kernel/logging.h diff --git a/kernel/include/mem.h b/base/usr/include/kernel/mem.h similarity index 92% rename from kernel/include/mem.h rename to base/usr/include/kernel/mem.h index cb7c9894..5e5ca4a9 100644 --- a/kernel/include/mem.h +++ b/base/usr/include/kernel/mem.h @@ -3,7 +3,7 @@ #pragma once -#include +#include extern uintptr_t heap_end; diff --git a/kernel/include/mod/net.h b/base/usr/include/kernel/mod/net.h similarity index 100% rename from kernel/include/mod/net.h rename to base/usr/include/kernel/mod/net.h diff --git a/base/usr/include/kernel/mod/procfs.h b/base/usr/include/kernel/mod/procfs.h new file mode 100644 index 00000000..cab331b4 --- /dev/null +++ b/base/usr/include/kernel/mod/procfs.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct procfs_entry { + int id; + char * name; + read_type_t func; +}; + +extern int procfs_install(struct procfs_entry * entry); diff --git a/kernel/include/mod/rtl.h b/base/usr/include/kernel/mod/rtl.h similarity index 100% rename from kernel/include/mod/rtl.h rename to base/usr/include/kernel/mod/rtl.h diff --git a/kernel/include/mod/shell.h b/base/usr/include/kernel/mod/shell.h similarity index 97% rename from kernel/include/mod/shell.h rename to base/usr/include/kernel/mod/shell.h index a83c795b..48ca5ed7 100644 --- a/kernel/include/mod/shell.h +++ b/base/usr/include/kernel/mod/shell.h @@ -1,7 +1,7 @@ #ifndef KERNEL_MOD_SHELL_H #define KERNEL_MOD_SHELL_H -#include +#include /* * We're going to have a list of shell commands. diff --git a/kernel/include/mod/snd.h b/base/usr/include/kernel/mod/snd.h similarity index 94% rename from kernel/include/mod/snd.h rename to base/usr/include/kernel/mod/snd.h index 11c86647..115314a5 100644 --- a/kernel/include/mod/snd.h +++ b/base/usr/include/kernel/mod/snd.h @@ -4,9 +4,9 @@ /* The format isn't really used for anything right now */ #define SND_FORMAT_L16SLE 0 /* Linear 16-bit signed little endian */ -#include -#include -#include +#include +#include +#include #define SND_KNOB_VENDOR 1024 diff --git a/userspace/lib/sound.h b/base/usr/include/kernel/mod/sound.h similarity index 100% rename from userspace/lib/sound.h rename to base/usr/include/kernel/mod/sound.h diff --git a/kernel/include/mod/tmpfs.h b/base/usr/include/kernel/mod/tmpfs.h similarity index 96% rename from kernel/include/mod/tmpfs.h rename to base/usr/include/kernel/mod/tmpfs.h index ddd9aa74..ea606d66 100644 --- a/kernel/include/mod/tmpfs.h +++ b/base/usr/include/kernel/mod/tmpfs.h @@ -1,6 +1,6 @@ #ifndef _TMPFS_H__ #define _TMPFS_H__ -#include +#include fs_node_t * tmpfs_create(char * name); diff --git a/kernel/include/module.h b/base/usr/include/kernel/module.h similarity index 94% rename from kernel/include/module.h rename to base/usr/include/kernel/module.h index 4468bc8d..4b02f864 100644 --- a/kernel/include/module.h +++ b/base/usr/include/kernel/module.h @@ -1,7 +1,8 @@ #pragma once -#include -#include +#include + +#include typedef struct { char * name; diff --git a/kernel/include/mouse.h b/base/usr/include/kernel/mouse.h similarity index 100% rename from kernel/include/mouse.h rename to base/usr/include/kernel/mouse.h diff --git a/kernel/include/multiboot.h b/base/usr/include/kernel/multiboot.h similarity index 98% rename from kernel/include/multiboot.h rename to base/usr/include/kernel/multiboot.h index 62648574..a9ee78ca 100644 --- a/kernel/include/multiboot.h +++ b/base/usr/include/kernel/multiboot.h @@ -2,7 +2,7 @@ */ #pragma once -#include +#include #define MULTIBOOT_MAGIC 0x1BADB002 #define MULTIBOOT_EAX_MAGIC 0x2BADB002 diff --git a/kernel/include/pci.h b/base/usr/include/kernel/pci.h similarity index 97% rename from kernel/include/pci.h rename to base/usr/include/kernel/pci.h index 613e884b..d3b1109b 100644 --- a/kernel/include/pci.h +++ b/base/usr/include/kernel/pci.h @@ -66,4 +66,5 @@ void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, void * e void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void * extra); void pci_scan_bus(pci_func_t f, int type, int bus, void * extra); void pci_scan(pci_func_t f, int type, void * extra); - +void pci_remap(void); +int pci_get_interrupt(uint32_t device); diff --git a/kernel/include/pipe.h b/base/usr/include/kernel/pipe.h similarity index 94% rename from kernel/include/pipe.h rename to base/usr/include/kernel/pipe.h index e2de45f7..1b7a1f87 100644 --- a/kernel/include/pipe.h +++ b/base/usr/include/kernel/pipe.h @@ -5,7 +5,7 @@ #pragma once -#include +#include typedef struct _pipe_device { uint8_t * buffer; diff --git a/kernel/include/printf.h b/base/usr/include/kernel/printf.h similarity index 81% rename from kernel/include/printf.h rename to base/usr/include/kernel/printf.h index 37ff085e..9182c4de 100644 --- a/kernel/include/printf.h +++ b/base/usr/include/kernel/printf.h @@ -1,6 +1,8 @@ #pragma once -#include +#include + +#include extern size_t vasprintf(char * buf, const char *fmt, va_list args); extern int sprintf(char *buf, const char *fmt, ...); diff --git a/kernel/include/process.h b/base/usr/include/kernel/process.h similarity index 97% rename from kernel/include/process.h rename to base/usr/include/kernel/process.h index 322f88fc..5da4f4bc 100644 --- a/kernel/include/process.h +++ b/base/usr/include/kernel/process.h @@ -3,16 +3,16 @@ #pragma once -//#include -#include -#include -#include +#include +#include + +#include #define KERNEL_STACK_SIZE 0x8000 typedef signed int pid_t; typedef unsigned int user_t; -typedef unsigned char status_t; +typedef unsigned int status_t; #define USER_ROOT_UID (user_t)0 diff --git a/kernel/include/ringbuffer.h b/base/usr/include/kernel/ringbuffer.h similarity index 93% rename from kernel/include/ringbuffer.h rename to base/usr/include/kernel/ringbuffer.h index 80bcae68..a062a7c0 100644 --- a/kernel/include/ringbuffer.h +++ b/base/usr/include/kernel/ringbuffer.h @@ -22,5 +22,6 @@ size_t ring_buffer_write(ring_buffer_t * ring_buffer, size_t size, uint8_t * buf ring_buffer_t * ring_buffer_create(size_t size); void ring_buffer_destroy(ring_buffer_t * ring_buffer); void ring_buffer_interrupt(ring_buffer_t * ring_buffer); +void ring_buffer_alert_waiters(ring_buffer_t * ring_buffer); void ring_buffer_select_wait(ring_buffer_t * ring_buffer, void * process); diff --git a/kernel/include/shm.h b/base/usr/include/kernel/shm.h similarity index 92% rename from kernel/include/shm.h rename to base/usr/include/kernel/shm.h index 46a36f7f..7c8f32f5 100644 --- a/kernel/include/shm.h +++ b/base/usr/include/kernel/shm.h @@ -2,8 +2,8 @@ */ #pragma once -#include -#include +#include +#include #define SHM_PATH_SEPARATOR "." diff --git a/kernel/include/signal.h b/base/usr/include/kernel/signal.h similarity index 70% rename from kernel/include/signal.h rename to base/usr/include/kernel/signal.h index fdd43cce..126100d3 100644 --- a/kernel/include/signal.h +++ b/base/usr/include/kernel/signal.h @@ -3,9 +3,9 @@ #pragma once -#include +#include void return_from_signal_handler(void); void fix_signal_stacks(void); -#include +#include diff --git a/kernel/include/system.h b/base/usr/include/kernel/system.h similarity index 94% rename from kernel/include/system.h rename to base/usr/include/kernel/system.h index 08ab5941..7ac35659 100644 --- a/kernel/include/system.h +++ b/base/usr/include/kernel/system.h @@ -2,13 +2,15 @@ */ #pragma once -#include -#include #include -#include -#include -#include -#include + +#include +#include +#include +#include +#include + +#include #define ASSUME(cond) __extension__ ({ if (!(cond)) { __builtin_unreachable(); } }) @@ -108,7 +110,7 @@ extern void isrs_uninstall_handler(size_t isrs); /* Interrupt Handlers */ extern void irq_install(void); -extern void irq_install_handler(size_t irq, irq_handler_chain_t); +extern void irq_install_handler(size_t irq, irq_handler_chain_t, char * desc); extern void irq_uninstall_handler(size_t irq); extern int irq_is_handler_free(size_t irq); extern void irq_gates(void); @@ -203,7 +205,7 @@ extern void fpu_install(void); /* ELF */ extern int exec( char *, int, char **, char **); -extern int system( char *, int, char **); +extern int system( char *, int, char **, char **); /* Sytem Calls */ extern void syscalls_install(void); @@ -221,7 +223,7 @@ typedef struct { extern void handle_signal(process_t *, signal_t *); -extern int send_signal(pid_t process, uint32_t signal); +extern int send_signal(pid_t process, uint32_t signal, int force); #define USER_STACK_BOTTOM 0xAFF00000 #define USER_STACK_TOP 0xB0000000 @@ -230,5 +232,5 @@ extern int send_signal(pid_t process, uint32_t signal); extern void validate(void * ptr); extern int validate_safe(void * ptr); -#include +#include diff --git a/kernel/include/task.h b/base/usr/include/kernel/task.h similarity index 80% rename from kernel/include/task.h rename to base/usr/include/kernel/task.h index 1498a329..a5639ae9 100644 --- a/kernel/include/task.h +++ b/base/usr/include/kernel/task.h @@ -1,6 +1,6 @@ #pragma once -#include +#include typedef struct page { unsigned int present:1; @@ -8,7 +8,11 @@ typedef struct page { unsigned int user:1; unsigned int writethrough:1; unsigned int cachedisable:1; - unsigned int unused:7; + unsigned int accessed:1; + unsigned int dirty:1; + unsigned int pat:1; + unsigned int global:1; + unsigned int unused:3; unsigned int frame:20; } __attribute__((packed)) page_t; diff --git a/kernel/include/tokenize.h b/base/usr/include/kernel/tokenize.h similarity index 100% rename from kernel/include/tokenize.h rename to base/usr/include/kernel/tokenize.h diff --git a/kernel/include/tss.h b/base/usr/include/kernel/tss.h similarity index 100% rename from kernel/include/tss.h rename to base/usr/include/kernel/tss.h diff --git a/kernel/include/types.h b/base/usr/include/kernel/types.h similarity index 100% rename from kernel/include/types.h rename to base/usr/include/kernel/types.h diff --git a/kernel/include/ubsan.h b/base/usr/include/kernel/ubsan.h similarity index 97% rename from kernel/include/ubsan.h rename to base/usr/include/kernel/ubsan.h index 86d0014e..c8be5939 100644 --- a/kernel/include/ubsan.h +++ b/base/usr/include/kernel/ubsan.h @@ -1,6 +1,6 @@ #pragma once -#include +#include struct TypeDescriptor { uint16_t type_kind; diff --git a/kernel/include/version.h b/base/usr/include/kernel/version.h similarity index 100% rename from kernel/include/version.h rename to base/usr/include/kernel/version.h diff --git a/kernel/include/video.h b/base/usr/include/kernel/video.h similarity index 88% rename from kernel/include/video.h rename to base/usr/include/kernel/video.h index b70f994a..bc4231f2 100644 --- a/kernel/include/video.h +++ b/base/usr/include/kernel/video.h @@ -7,6 +7,7 @@ #define IO_VID_SIGNAL 0x5005 #define IO_VID_SET 0x5006 #define IO_VID_STRIDE 0x5007 +#define IO_VID_DRIVER 0x6008 struct vid_size { uint32_t width; @@ -19,5 +20,6 @@ extern uint16_t lfb_resolution_x; extern uint16_t lfb_resolution_y; extern uint16_t lfb_resolution_b; extern uint8_t * lfb_vid_memory; +extern const char * lfb_driver_name; #endif diff --git a/base/usr/include/locale.h b/base/usr/include/locale.h new file mode 100644 index 00000000..805aab91 --- /dev/null +++ b/base/usr/include/locale.h @@ -0,0 +1,33 @@ +#pragma once + +#define LC_ALL 0 +#define LC_COLLATE 1 +#define LC_CTYPE 2 +#define LC_MONETARY 3 +#define LC_NUMERIC 4 +#define LC_TIME 5 +#define LC_MESSAGES 6 + +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; +}; + +extern struct lconv * localeconv(void); +extern char * setlocale(int category, const char *locale); diff --git a/base/usr/include/math.h b/base/usr/include/math.h new file mode 100644 index 00000000..782715df --- /dev/null +++ b/base/usr/include/math.h @@ -0,0 +1,34 @@ +#define M_PI 3.1415926 + +extern double floor(double x); +extern int abs(int j); +extern double pow(double x, double y); +extern double exp(double x); +extern double fmod(double x, double y); +extern double sqrt(double x); +extern double fabs(double x); +extern double sin(double x); +extern double cos(double x); + +double frexp(double x, int *exp); + +#define HUGE_VAL (__builtin_huge_val()) + +/* Unimplemented, but stubbed */ +extern double acos(double x); +extern double asin(double x); +extern double atan2(double y, double x); +extern double ceil(double x); +extern double cosh(double x); +extern double ldexp(double a, int exp); +extern double log(double x); +extern double log10(double x); +extern double log2(double x); +extern double sinh(double x); +extern double tan(double x); +extern double tanh(double x); +extern double atan(double x); + +extern double modf(double x, double *iptr); + +extern double hypot(double x, double y); diff --git a/base/usr/include/poll.h b/base/usr/include/poll.h new file mode 100644 index 00000000..c8107396 --- /dev/null +++ b/base/usr/include/poll.h @@ -0,0 +1,19 @@ +#pragma once + +#define POLLIN 0x0001 +#define POLLOUT 0x0002 +#define POLLRDHUP 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 +#define POLLPRI 0x0040 + +typedef unsigned int nfds_t; + +struct pollfd { + int fd; + short events; + short revents; +}; + +extern int poll(struct pollfd * fds, nfds_t nfds, int timeout); diff --git a/base/usr/include/pthread.h b/base/usr/include/pthread.h new file mode 100644 index 00000000..e75b602a --- /dev/null +++ b/base/usr/include/pthread.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +typedef struct { + uint32_t id; + char * stack; + void * ret_val; +} pthread_t; +typedef unsigned int pthread_attr_t; + +extern int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg); +extern void pthread_exit(void * value); +extern int pthread_kill(pthread_t thread, int sig); + +extern int clone(uintptr_t,uintptr_t,void*); +extern int gettid(); + diff --git a/base/usr/include/pty.h b/base/usr/include/pty.h new file mode 100644 index 00000000..c3cbb9f9 --- /dev/null +++ b/base/usr/include/pty.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern int openpty(int * amaster, int * aslave, char * name, const struct termios *termp, const struct winsize * winp); diff --git a/toolchain/patches/newlib/include/pwd.h b/base/usr/include/pwd.h similarity index 56% rename from toolchain/patches/newlib/include/pwd.h rename to base/usr/include/pwd.h index f636ace1..7f534ec5 100644 --- a/toolchain/patches/newlib/include/pwd.h +++ b/base/usr/include/pwd.h @@ -1,19 +1,5 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - * - * getpwent, setpwent, endpwent, fgetpwent - * getpwuid, getpwnam - * - * These functions manage entries in the password files. - */ +#pragma once -#ifndef _PWD_H_ -#ifdef __cplusplus -extern "C" { -#endif - -#include #include struct passwd { @@ -34,8 +20,3 @@ void setpwent(void); void endpwent(void); struct passwd * getpwnam(const char * name); struct passwd * getpwuid(uid_t uid); - -#ifdef __cplusplus -} -#endif -#endif /* _PWD_H_ */ diff --git a/base/usr/include/sched.h b/base/usr/include/sched.h new file mode 100644 index 00000000..53cb4ac9 --- /dev/null +++ b/base/usr/include/sched.h @@ -0,0 +1,3 @@ +#pragma once + +extern int sched_yield(void); diff --git a/base/usr/include/setjmp.h b/base/usr/include/setjmp.h new file mode 100644 index 00000000..3ad2ff22 --- /dev/null +++ b/base/usr/include/setjmp.h @@ -0,0 +1,9 @@ +#pragma once + +/* i386 */ +#define _JBLEN 9 + +typedef int jmp_buf[_JBLEN]; + +extern void longjmp(jmp_buf j, int r); +extern int setjmp(jmp_buf j); diff --git a/base/usr/include/signal.h b/base/usr/include/signal.h new file mode 100644 index 00000000..1bf0677c --- /dev/null +++ b/base/usr/include/signal.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +typedef _sig_func_ptr sighandler_t; + +#define SIG_DFL ((_sig_func_ptr)0)/* Default action */ +#define SIG_IGN ((_sig_func_ptr)1)/* Ignore action */ +#define SIG_ERR ((_sig_func_ptr)-1)/* Error return */ + +typedef int sig_atomic_t; + +extern sighandler_t signal(int signum, sighandler_t handler); +extern int raise(int sig); diff --git a/base/usr/include/stdint.h b/base/usr/include/stdint.h new file mode 100644 index 00000000..94759e96 --- /dev/null +++ b/base/usr/include/stdint.h @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2004, 2005 by + * Ralf Corsepius, Ulm/Germany. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software + * is freely granted, provided that this notice is preserved. + */ + +#ifndef _STDINT_H +#define _STDINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && \ + ( (__GNUC__ >= 4) || \ + ( (__GNUC__ >= 3) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ > 2) ) ) +/* gcc > 3.2 implicitly defines the values we are interested */ +#define __STDINT_EXP(x) __##x##__ +#else +#define __STDINT_EXP(x) x +#include +#endif + +/* Check if "long long" is 64bit wide */ +/* Modern GCCs provide __LONG_LONG_MAX__, SUSv3 wants LLONG_MAX */ +#if ( defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff) ) \ + || ( defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff) ) +#define __have_longlong64 1 +#endif + +/* Check if "long" is 64bit or 32bit wide */ +#if __STDINT_EXP(LONG_MAX) > 0x7fffffff +#define __have_long64 1 +#elif __STDINT_EXP(LONG_MAX) == 0x7fffffff && !defined(__SPU__) +#define __have_long32 1 +#endif + +#if __STDINT_EXP(SCHAR_MAX) == 0x7f +typedef signed char int8_t ; +typedef unsigned char uint8_t ; +#define __int8_t_defined 1 +#endif + +#if __int8_t_defined +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +#define __int_least8_t_defined 1 +#endif + +#if __STDINT_EXP(SHRT_MAX) == 0x7fff +typedef signed short int16_t; +typedef unsigned short uint16_t; +#define __int16_t_defined 1 +#elif __STDINT_EXP(INT_MAX) == 0x7fff +typedef signed int int16_t; +typedef unsigned int uint16_t; +#define __int16_t_defined 1 +#elif __STDINT_EXP(SCHAR_MAX) == 0x7fff +typedef signed char int16_t; +typedef unsigned char uint16_t; +#define __int16_t_defined 1 +#endif + +#if __int16_t_defined +typedef int16_t int_least16_t; +typedef uint16_t uint_least16_t; +#define __int_least16_t_defined 1 + +#if !__int_least8_t_defined +typedef int16_t int_least8_t; +typedef uint16_t uint_least8_t; +#define __int_least8_t_defined 1 +#endif +#endif + +#if __have_long32 +typedef signed long int32_t; +typedef unsigned long uint32_t; +#define __int32_t_defined 1 +#elif __STDINT_EXP(INT_MAX) == 0x7fffffffL +typedef signed int int32_t; +typedef unsigned int uint32_t; +#define __int32_t_defined 1 +#elif __STDINT_EXP(SHRT_MAX) == 0x7fffffffL +typedef signed short int32_t; +typedef unsigned short uint32_t; +#define __int32_t_defined 1 +#elif __STDINT_EXP(SCHAR_MAX) == 0x7fffffffL +typedef signed char int32_t; +typedef unsigned char uint32_t; +#define __int32_t_defined 1 +#endif + +#if __int32_t_defined +typedef int32_t int_least32_t; +typedef uint32_t uint_least32_t; +#define __int_least32_t_defined 1 + +#if !__int_least8_t_defined +typedef int32_t int_least8_t; +typedef uint32_t uint_least8_t; +#define __int_least8_t_defined 1 +#endif + +#if !__int_least16_t_defined +typedef int32_t int_least16_t; +typedef uint32_t uint_least16_t; +#define __int_least16_t_defined 1 +#endif +#endif + +#if __have_long64 +typedef signed long int64_t; +typedef unsigned long uint64_t; +#define __int64_t_defined 1 +#elif __have_longlong64 +typedef signed long long int64_t; +typedef unsigned long long uint64_t; +#define __int64_t_defined 1 +#elif __STDINT_EXP(INT_MAX) > 0x7fffffff +typedef signed int int64_t; +typedef unsigned int uint64_t; +#define __int64_t_defined 1 +#endif + +#if __int64_t_defined +typedef int64_t int_least64_t; +typedef uint64_t uint_least64_t; +#define __int_least64_t_defined 1 + +#if !__int_least8_t_defined +typedef int64_t int_least8_t; +typedef uint64_t uint_least8_t; +#define __int_least8_t_defined 1 +#endif + +#if !__int_least16_t_defined +typedef int64_t int_least16_t; +typedef uint64_t uint_least16_t; +#define __int_least16_t_defined 1 +#endif + +#if !__int_least32_t_defined +typedef int64_t int_least32_t; +typedef uint64_t uint_least32_t; +#define __int_least32_t_defined 1 +#endif +#endif + +/* + * Fastest minimum-width integer types + * + * Assume int to be the fastest type for all types with a width + * less than __INT_MAX__ rsp. INT_MAX + */ +#if __STDINT_EXP(INT_MAX) >= 0x7f + typedef signed int int_fast8_t; + typedef unsigned int uint_fast8_t; +#define __int_fast8_t_defined 1 +#endif + +#if __STDINT_EXP(INT_MAX) >= 0x7fff + typedef signed int int_fast16_t; + typedef unsigned int uint_fast16_t; +#define __int_fast16_t_defined 1 +#endif + +#if __STDINT_EXP(INT_MAX) >= 0x7fffffff + typedef signed int int_fast32_t; + typedef unsigned int uint_fast32_t; +#define __int_fast32_t_defined 1 +#endif + +#if __STDINT_EXP(INT_MAX) > 0x7fffffff + typedef signed int int_fast64_t; + typedef unsigned int uint_fast64_t; +#define __int_fast64_t_defined 1 +#endif + +/* + * Fall back to [u]int_least_t for [u]int_fast_t types + * not having been defined, yet. + * Leave undefined, if [u]int_least_t should not be available. + */ +#if !__int_fast8_t_defined +#if __int_least8_t_defined + typedef int_least8_t int_fast8_t; + typedef uint_least8_t uint_fast8_t; +#define __int_fast8_t_defined 1 +#endif +#endif + +#if !__int_fast16_t_defined +#if __int_least16_t_defined + typedef int_least16_t int_fast16_t; + typedef uint_least16_t uint_fast16_t; +#define __int_fast16_t_defined 1 +#endif +#endif + +#if !__int_fast32_t_defined +#if __int_least32_t_defined + typedef int_least32_t int_fast32_t; + typedef uint_least32_t uint_fast32_t; +#define __int_fast32_t_defined 1 +#endif +#endif + +#if !__int_fast64_t_defined +#if __int_least64_t_defined + typedef int_least64_t int_fast64_t; + typedef uint_least64_t uint_fast64_t; +#define __int_fast64_t_defined 1 +#endif +#endif + +/* Greatest-width integer types */ +/* Modern GCCs provide __INTMAX_TYPE__ */ +#if defined(__INTMAX_TYPE__) + typedef __INTMAX_TYPE__ intmax_t; +#elif __have_longlong64 + typedef signed long long intmax_t; +#else + typedef signed long intmax_t; +#endif + +/* Modern GCCs provide __UINTMAX_TYPE__ */ +#if defined(__UINTMAX_TYPE__) + typedef __UINTMAX_TYPE__ uintmax_t; +#elif __have_longlong64 + typedef unsigned long long uintmax_t; +#else + typedef unsigned long uintmax_t; +#endif + +/* + * GCC doesn't provide an appropriate macro for [u]intptr_t + * For now, use __PTRDIFF_TYPE__ + */ +#if defined(__PTRDIFF_TYPE__) +typedef signed __PTRDIFF_TYPE__ intptr_t; +typedef unsigned __PTRDIFF_TYPE__ uintptr_t; +#define INTPTR_MAX PTRDIFF_MAX +#define INTPTR_MIN PTRDIFF_MIN +#ifdef __UINTPTR_MAX__ +#define UINTPTR_MAX __UINTPTR_MAX__ +#else +#define UINTPTR_MAX (2UL * PTRDIFF_MAX + 1) +#endif +#else +/* + * Fallback to hardcoded values, + * should be valid on cpu's with 32bit int/32bit void* + */ +typedef signed long intptr_t; +typedef unsigned long uintptr_t; +#define INTPTR_MAX __STDINT_EXP(LONG_MAX) +#define INTPTR_MIN (-__STDINT_EXP(LONG_MAX) - 1) +#define UINTPTR_MAX (__STDINT_EXP(LONG_MAX) * 2UL + 1) +#endif + +/* Limits of Specified-Width Integer Types */ + +#if __int8_t_defined +#define INT8_MIN -128 +#define INT8_MAX 127 +#define UINT8_MAX 255 +#endif + +#if __int_least8_t_defined +#define INT_LEAST8_MIN -128 +#define INT_LEAST8_MAX 127 +#define UINT_LEAST8_MAX 255 +#else +#error required type int_least8_t missing +#endif + +#if __int16_t_defined +#define INT16_MIN -32768 +#define INT16_MAX 32767 +#define UINT16_MAX 65535 +#endif + +#if __int_least16_t_defined +#define INT_LEAST16_MIN -32768 +#define INT_LEAST16_MAX 32767 +#define UINT_LEAST16_MAX 65535 +#else +#error required type int_least16_t missing +#endif + +#if __int32_t_defined +#if __have_long32 +#define INT32_MIN (-2147483647L-1) +#define INT32_MAX 2147483647L +#define UINT32_MAX 4294967295UL +#else +#define INT32_MIN (-2147483647-1) +#define INT32_MAX 2147483647 +#define UINT32_MAX 4294967295U +#endif +#endif + +#if __int_least32_t_defined +#if __have_long32 +#define INT_LEAST32_MIN (-2147483647L-1) +#define INT_LEAST32_MAX 2147483647L +#define UINT_LEAST32_MAX 4294967295UL +#else +#define INT_LEAST32_MIN (-2147483647-1) +#define INT_LEAST32_MAX 2147483647 +#define UINT_LEAST32_MAX 4294967295U +#endif +#else +#error required type int_least32_t missing +#endif + +#if __int64_t_defined +#if __have_long64 +#define INT64_MIN (-9223372036854775807L-1L) +#define INT64_MAX 9223372036854775807L +#define UINT64_MAX 18446744073709551615U +#elif __have_longlong64 +#define INT64_MIN (-9223372036854775807LL-1LL) +#define INT64_MAX 9223372036854775807LL +#define UINT64_MAX 18446744073709551615ULL +#endif +#endif + +#if __int_least64_t_defined +#if __have_long64 +#define INT_LEAST64_MIN (-9223372036854775807L-1L) +#define INT_LEAST64_MAX 9223372036854775807L +#define UINT_LEAST64_MAX 18446744073709551615U +#elif __have_longlong64 +#define INT_LEAST64_MIN (-9223372036854775807LL-1LL) +#define INT_LEAST64_MAX 9223372036854775807LL +#define UINT_LEAST64_MAX 18446744073709551615ULL +#endif +#endif + +#if __int_fast8_t_defined +#if __STDINT_EXP(INT_MAX) >= 0x7f +#define INT_FAST8_MIN (-__STDINT_EXP(INT_MAX)-1) +#define INT_FAST8_MAX __STDINT_EXP(INT_MAX) +#define UINT_FAST8_MAX (__STDINT_EXP(INT_MAX)*2U+1U) +#else +#define INT_FAST8_MIN INT_LEAST8_MIN +#define INT_FAST8_MAX INT_LEAST8_MAX +#define UINT_FAST8_MAX UINT_LEAST8_MAX +#endif +#endif + +#if __int_fast16_t_defined +#if __STDINT_EXP(INT_MAX) >= 0x7fff +#define INT_FAST16_MIN (-__STDINT_EXP(INT_MAX)-1) +#define INT_FAST16_MAX __STDINT_EXP(INT_MAX) +#define UINT_FAST16_MAX (__STDINT_EXP(INT_MAX)*2U+1U) +#else +#define INT_FAST16_MIN INT_LEAST16_MIN +#define INT_FAST16_MAX INT_LEAST16_MAX +#define UINT_FAST16_MAX UINT_LEAST16_MAX +#endif +#endif + +#if __int_fast32_t_defined +#if __STDINT_EXP(INT_MAX) >= 0x7fffffff +#define INT_FAST32_MIN (-__STDINT_EXP(INT_MAX)-1) +#define INT_FAST32_MAX __STDINT_EXP(INT_MAX) +#define UINT_FAST32_MAX (__STDINT_EXP(INT_MAX)*2U+1U) +#else +#define INT_FAST32_MIN INT_LEAST32_MIN +#define INT_FAST32_MAX INT_LEAST32_MAX +#define UINT_FAST32_MAX UINT_LEAST32_MAX +#endif +#endif + +#if __int_fast64_t_defined +#if __STDINT_EXP(INT_MAX) > 0x7fffffff +#define INT_FAST64_MIN (-__STDINT_EXP(INT_MAX)-1) +#define INT_FAST64_MAX __STDINT_EXP(INT_MAX) +#define UINT_FAST64_MAX (__STDINT_EXP(INT_MAX)*2U+1U) +#else +#define INT_FAST64_MIN INT_LEAST64_MIN +#define INT_FAST64_MAX INT_LEAST64_MAX +#define UINT_FAST64_MAX UINT_LEAST64_MAX +#endif +#endif + +#ifdef __INTMAX_MAX__ +#define INTMAX_MAX __INTMAX_MAX__ +#define INTMAX_MIN (-INTMAX_MAX - 1) +#elif defined(__INTMAX_TYPE__) +/* All relevant GCC versions prefer long to long long for intmax_t. */ +#define INTMAX_MAX INT64_MAX +#define INTMAX_MIN INT64_MIN +#endif + +#ifdef __UINTMAX_MAX__ +#define UINTMAX_MAX __UINTMAX_MAX__ +#elif defined(__UINTMAX_TYPE__) +/* All relevant GCC versions prefer long to long long for intmax_t. */ +#define UINTMAX_MAX UINT64_MAX +#endif + +/* This must match size_t in stddef.h, currently long unsigned int */ +#ifdef __SIZE_MAX__ +#define SIZE_MAX __SIZE_MAX__ +#else +#define SIZE_MAX (__STDINT_EXP(LONG_MAX) * 2UL + 1) +#endif + +/* This must match sig_atomic_t in (currently int) */ +#define SIG_ATOMIC_MIN (-__STDINT_EXP(INT_MAX) - 1) +#define SIG_ATOMIC_MAX __STDINT_EXP(INT_MAX) + +/* This must match ptrdiff_t in (currently long int) */ +#ifdef __PTRDIFF_MAX__ +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#else +#define PTRDIFF_MAX __STDINT_EXP(LONG_MAX) +#endif +#define PTRDIFF_MIN (-PTRDIFF_MAX - 1) + +#ifdef __WCHAR_MAX__ +#define WCHAR_MAX __WCHAR_MAX__ +#endif +#ifdef __WCHAR_MIN__ +#define WCHAR_MIN __WCHAR_MIN__ +#endif + +/* wint_t is unsigned int on almost all GCC targets. */ +#ifdef __WINT_MAX__ +#define WINT_MAX __WINT_MAX__ +#else +#define WINT_MAX (__STDINT_EXP(INT_MAX) * 2U + 1U) +#endif +#ifdef __WINT_MIN__ +#define WINT_MIN __WINT_MIN__ +#else +#define WINT_MIN 0U +#endif + +/** Macros for minimum-width integer constant expressions */ +#define INT8_C(x) x +#if __STDINT_EXP(INT_MAX) > 0x7f +#define UINT8_C(x) x +#else +#define UINT8_C(x) x##U +#endif + +#define INT16_C(x) x +#if __STDINT_EXP(INT_MAX) > 0x7fff +#define UINT16_C(x) x +#else +#define UINT16_C(x) x##U +#endif + +#if __have_long32 +#define INT32_C(x) x##L +#define UINT32_C(x) x##UL +#else +#define INT32_C(x) x +#define UINT32_C(x) x##U +#endif + +#if __int64_t_defined +#if __have_long64 +#define INT64_C(x) x##L +#define UINT64_C(x) x##UL +#else +#define INT64_C(x) x##LL +#define UINT64_C(x) x##ULL +#endif +#endif + +/** Macros for greatest-width integer constant expression */ +#if __have_long64 +#define INTMAX_C(x) x##L +#define UINTMAX_C(x) x##UL +#else +#define INTMAX_C(x) x##LL +#define UINTMAX_C(x) x##ULL +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* _STDINT_H */ diff --git a/base/usr/include/stdio.h b/base/usr/include/stdio.h new file mode 100644 index 00000000..4da27a87 --- /dev/null +++ b/base/usr/include/stdio.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include + +typedef struct _FILE FILE; + +#define BUFSIZ 8192 + +extern FILE * stdin; +extern FILE * stdout; +extern FILE * stderr; + +#define EOF (-1) + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +extern FILE * fopen(const char *path, const char *mode); +extern int fclose(FILE * stream); +extern int fseek(FILE * stream, long offset, int whence); +extern long ftell(FILE * stream); +extern FILE * fdopen(int fd, const char *mode); +extern FILE * freopen(const char *path, const char *mode, FILE * stream); + +extern size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream); +extern size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE * stream); + +extern int fileno(FILE * stream); +extern int fflush(FILE * stream); + +extern int vasprintf(char ** buf, const char *fmt, va_list args); +extern int sprintf(char *buf, const char *fmt, ...); +extern int fprintf(FILE *stream, const char *fmt, ...); +extern int printf(const char *fmt, ...); +extern int snprintf(char * buf, size_t size, const char * fmt, ...); +extern int vsprintf(char * buf, const char *fmt, va_list args); +extern int vsnprintf(char * buf, size_t size, const char *fmt, va_list args); +extern int vfprintf(FILE * device, const char *format, va_list ap); +extern int vprintf(const char *format, va_list ap); + +extern int puts(const char *s); +extern int fputs(const char *s, FILE *stream); +extern int fputc(int c, FILE *stream); +extern int putc(int c, FILE *stream); +extern int putchar(int c); +extern int fgetc(FILE *stream); +extern int getc(FILE *stream); +extern char *fgets(char *s, int size, FILE *stream); +extern int getchar(void); + +extern void rewind(FILE *stream); +extern void setbuf(FILE * stream, char * buf); + +extern void perror(const char *s); + +extern int ungetc(int c, FILE * stream); + +extern int feof(FILE * stream); +extern void clearerr(FILE * stream); +extern int ferror(FILE * stream); + +extern char * strerror(int errnum); + +extern int _fwouldblock(FILE * stream); + +extern FILE * tmpfile(void); + +extern int setvbuf(FILE * stream, char * buf, int mode, size_t size); + +extern int remove(const char * pathname); +extern int rename(const char * oldpath, const char * newpath); + +#define _IONBF 0 +#define _IOLBF 1 +#define _IOFBF 2 + +extern char * tmpnam(char * s); +#define L_tmpnam 256 diff --git a/base/usr/include/stdlib.h b/base/usr/include/stdlib.h new file mode 100644 index 00000000..448e3ede --- /dev/null +++ b/base/usr/include/stdlib.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +extern void exit(int status); +extern char * getenv(const char *name); + +extern void *malloc(size_t size); +extern void free(void *ptr); +extern void *calloc(size_t nmemb, size_t size); +extern void *realloc(void *ptr, size_t size); + +extern void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void*,const void*)); + +extern int system(const char * command); + +extern int abs(int j); + +extern int putenv(char * name); +extern int setenv(const char *name, const char *value, int overwrite); +extern int unsetenv(const char * str); + +extern double strtod(const char *nptr, char **endptr); +extern double atof(const char * nptr); +extern int atoi(const char * nptr); +extern long atol(const char * nptr); +extern long int labs(long int j); +extern long int strtol(const char * s, char **endptr, int base); + +extern void srand(unsigned int); +extern int rand(void); + +#define ATEXIT_MAX 32 +extern int atexit(void (*h)(void)); +extern void _handle_atexit(void); + +#define RAND_MAX 0x7FFFFFFF + +extern void abort(void); + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define NULL 0 diff --git a/base/usr/include/string.h b/base/usr/include/string.h new file mode 100644 index 00000000..52b01631 --- /dev/null +++ b/base/usr/include/string.h @@ -0,0 +1,46 @@ +#include +#include + +extern void * memset(void * dest, int c, size_t n); +extern void * memcpy(void * dest, const void * src, size_t n); +extern void * memmove(void * dest, const void * src, size_t n); + +extern void * memchr(const void * src, int c, size_t n); +extern void * memrchr(const void * m, int c, size_t n); +extern int memcmp(const void *vl, const void *vr, size_t n); + +extern void * __attribute__ ((malloc)) malloc(uintptr_t size); +extern void * __attribute__ ((malloc)) realloc(void * ptr, uintptr_t size); +extern void * __attribute__ ((malloc)) calloc(uintptr_t nmemb, uintptr_t size); +extern void * __attribute__ ((malloc)) valloc(uintptr_t size); +extern void free(void * ptr); + +extern char * strdup(const char * s); +extern char * stpcpy(char * d, const char * s); +extern char * strcpy(char * dest, const char * src); +extern char * strchrnul(const char * s, int c); +extern char * strchr(const char * s, int c); +extern char * strrchr(const char * s, int c); +extern char * strpbrk(const char * s, const char * b); +extern char * strstr(const char * h, const char * n); + +extern char * strncpy(char * dest, const char * src, size_t n); + +extern int strcmp(const char * l, const char * r); +extern int strncmp(const char *s1, const char *s2, size_t n); +extern int strcoll(const char * s1, const char * s2); + +extern size_t strcspn(const char * s, const char * c); +extern size_t strspn(const char * s, const char * c); +extern size_t strlen(const char * s); + +extern int atoi(const char * s); + +extern char * strcat(char *dest, const char *src); + +extern char * strtok(char * str, const char * delim); +extern char * strtok_r(char * str, const char * delim, char ** saveptr); + +extern char * strncpy(char *dest, const char *src, size_t n); + +extern char * strerror(int errnum); diff --git a/base/usr/include/sys/fswait.h b/base/usr/include/sys/fswait.h new file mode 100644 index 00000000..349ab889 --- /dev/null +++ b/base/usr/include/sys/fswait.h @@ -0,0 +1,4 @@ +#pragma once + +extern int fswait(int count, int * fds); +extern int fswait2(int count, int * fds, int timeout); diff --git a/toolchain/patches/newlib/toaru/sys/ioctl.h b/base/usr/include/sys/ioctl.h similarity index 100% rename from toolchain/patches/newlib/toaru/sys/ioctl.h rename to base/usr/include/sys/ioctl.h diff --git a/base/usr/include/sys/mman.h b/base/usr/include/sys/mman.h new file mode 100644 index 00000000..2ba5a128 --- /dev/null +++ b/base/usr/include/sys/mman.h @@ -0,0 +1,3 @@ +#pragma once + +/* Nothing here, we don't have an mmap implementation yet? */ diff --git a/base/usr/include/sys/mount.h b/base/usr/include/sys/mount.h new file mode 100644 index 00000000..954efeb9 --- /dev/null +++ b/base/usr/include/sys/mount.h @@ -0,0 +1,3 @@ +#pragma once + +extern int mount(char * source, char * target, char * type, unsigned long flags, void * data); diff --git a/toolchain/patches/newlib/toaru/sys/signal.h b/base/usr/include/sys/signal.h similarity index 53% rename from toolchain/patches/newlib/toaru/sys/signal.h rename to base/usr/include/sys/signal.h index e1232d34..83cdad68 100644 --- a/toolchain/patches/newlib/toaru/sys/signal.h +++ b/base/usr/include/sys/signal.h @@ -1,17 +1,7 @@ -/* sys/signal.h */ +#pragma once -#ifndef _SYS_SIGNAL_H -#define _SYS_SIGNAL_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "_ansi.h" -#include #include -typedef unsigned long sigset_t; - #define SIGEV_NONE 1 #define SIGEV_SIGNAL 2 #define SIGEV_THREAD 3 @@ -25,9 +15,11 @@ typedef unsigned long sigset_t; #define SA_NOCLDSTOP 1 #define SA_SIGINFO 2 +#if 0 #define SIG_SETMASK 0 #define SIG_BLOCK 1 #define SIG_UNBLOCK 2 +#endif #define sa_handler _signal_handlers._handler #define sa_sigaction _signal_handlers._sigaction @@ -49,6 +41,7 @@ typedef struct { union sigval si_value; } siginfo_t; +typedef unsigned long sigset_t; typedef void (*_sig_func_ptr)(); struct sigaction { @@ -60,27 +53,5 @@ struct sigaction { } _signal_handlers; }; -#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0) -#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0) -#define sigemptyset(what) (*(what) = 0, 0) -#define sigfillset(what) (*(what) = ~(0), 0) -#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0) -int _EXFUN(kill, (pid_t, int)); -int _EXFUN(killpg, (pid_t, int)); -int _EXFUN(sigaction, (int, const struct sigaction *, struct sigaction *)); -int _EXFUN(sigpending, (sigset_t *)); -int _EXFUN(sigsuspend, (const sigset_t *)); -int _EXFUN(sigpause, (int)); - - -#include - -#ifdef __cplusplus -} -#endif - -#ifndef _SIGNAL_H_ -#include -#endif -#endif /* _SYS_SIGNAL_H */ +extern int kill(pid_t, int); diff --git a/toolchain/patches/newlib/toaru/sys/signal_defs.h b/base/usr/include/sys/signal_defs.h similarity index 100% rename from toolchain/patches/newlib/toaru/sys/signal_defs.h rename to base/usr/include/sys/signal_defs.h diff --git a/userspace/lib/network.h b/base/usr/include/sys/socket.h similarity index 99% rename from userspace/lib/network.h rename to base/usr/include/sys/socket.h index 07e230e9..c3bcb22d 100644 --- a/userspace/lib/network.h +++ b/base/usr/include/sys/socket.h @@ -1,6 +1,7 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -104,3 +105,4 @@ int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t } #endif + diff --git a/base/usr/include/sys/stat.h b/base/usr/include/sys/stat.h new file mode 100644 index 00000000..c41846db --- /dev/null +++ b/base/usr/include/sys/stat.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include + +typedef int mode_t; + +struct stat { + uint16_t st_dev; + uint16_t st_ino; + uint32_t st_mode; + uint16_t st_nlink; + uint16_t st_uid; + uint16_t st_gid; + uint16_t st_rdev; + uint32_t st_size; + uint32_t st_atime; + uint32_t __unused1; + uint32_t st_mtime; + uint32_t __unused2; + uint32_t st_ctime; + uint32_t __unused3; + uint32_t st_blksize; + uint32_t st_blocks; +}; + +#define _IFMT 0170000 /* type of file */ +#define _IFDIR 0040000 /* directory */ +#define _IFCHR 0020000 /* character special */ +#define _IFBLK 0060000 /* block special */ +#define _IFREG 0100000 /* regular */ +#define _IFLNK 0120000 /* symbolic link */ +#define _IFSOCK 0140000 /* socket */ +#define _IFIFO 0010000 /* fifo */ + +#define S_BLKSIZE 1024 /* size of a block */ + +#define S_ISUID 0004000 /* set user id on execution */ +#define S_ISGID 0002000 /* set group id on execution */ +#define S_ISVTX 0001000 /* save swapped text even after use */ +#define S_IREAD 0000400 /* read permission, owner */ +#define S_IWRITE 0000200 /* write permission, owner */ +#define S_IEXEC 0000100 /* execute/search permission, owner */ +#define S_ENFMT 0002000 /* enforcement-mode locking */ + +#define S_IFMT _IFMT +#define S_IFDIR _IFDIR +#define S_IFCHR _IFCHR +#define S_IFBLK _IFBLK +#define S_IFREG _IFREG +#define S_IFLNK _IFLNK +#define S_IFSOCK _IFSOCK +#define S_IFIFO _IFIFO + +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#define S_IRUSR 0000400 /* read permission, owner */ +#define S_IWUSR 0000200 /* write permission, owner */ +#define S_IXUSR 0000100/* execute/search permission, owner */ +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#define S_IRGRP 0000040 /* read permission, group */ +#define S_IWGRP 0000020 /* write permission, grougroup */ +#define S_IXGRP 0000010/* execute/search permission, group */ +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_IROTH 0000004 /* read permission, other */ +#define S_IWOTH 0000002 /* write permission, other */ +#define S_IXOTH 0000001/* execute/search permission, other */ + +#define S_ISBLK(m) (((m)&_IFMT) == _IFBLK) +#define S_ISCHR(m) (((m)&_IFMT) == _IFCHR) +#define S_ISDIR(m) (((m)&_IFMT) == _IFDIR) +#define S_ISFIFO(m) (((m)&_IFMT) == _IFIFO) +#define S_ISREG(m) (((m)&_IFMT) == _IFREG) +#define S_ISLNK(m) (((m)&_IFMT) == _IFLNK) +#define S_ISSOCK(m) (((m)&_IFMT) == _IFSOCK) + +extern int stat(const char *file, struct stat *st); +extern int lstat(const char *path, struct stat *st); +extern int fstat(int fd, struct stat *st); +extern int mkdir(const char *pathname, mode_t mode); + diff --git a/toolchain/patches/newlib/toaru/sys/termios.h b/base/usr/include/sys/termios.h similarity index 98% rename from toolchain/patches/newlib/toaru/sys/termios.h rename to base/usr/include/sys/termios.h index 128ac309..75ffba5d 100644 --- a/toolchain/patches/newlib/toaru/sys/termios.h +++ b/base/usr/include/sys/termios.h @@ -1,5 +1,11 @@ #pragma once +#ifndef _KERNEL_ +#include +#else +#include +#endif + /* Technically part of ioctl */ struct winsize { unsigned short ws_row; diff --git a/base/usr/include/sys/time.h b/base/usr/include/sys/time.h new file mode 100644 index 00000000..584609d1 --- /dev/null +++ b/base/usr/include/sys/time.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +struct timeval { + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* microseconds */ +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of DST correction */ +}; + +extern int gettimeofday(struct timeval *p, void *z); diff --git a/base/usr/include/sys/types.h b/base/usr/include/sys/types.h new file mode 100644 index 00000000..a6e82990 --- /dev/null +++ b/base/usr/include/sys/types.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +typedef int gid_t; +typedef int uid_t; +typedef int dev_t; +typedef int ino_t; +typedef int mode_t; +typedef int caddr_t; + +typedef unsigned short nlink_t; + +typedef long off_t; +typedef long time_t; + +#if defined(__INT_MAX__) && __INT_MAX__ == 2147483647 +typedef int ssize_t; +#else +typedef long ssize_t; +#endif + +typedef unsigned long useconds_t; +typedef long suseconds_t; +typedef int pid_t; + +#define FD_SETSIZE 64 /* compatibility with newlib */ +typedef long fd_mask; +typedef struct _fd_set { + fd_mask fds_bits[2]; /* should be 64 bits */ +} fd_set; diff --git a/toolchain/patches/newlib/toaru/sys/utsname.h b/base/usr/include/sys/utsname.h similarity index 87% rename from toolchain/patches/newlib/toaru/sys/utsname.h rename to base/usr/include/sys/utsname.h index 5bd49c4f..93fdbc11 100644 --- a/toolchain/patches/newlib/toaru/sys/utsname.h +++ b/base/usr/include/sys/utsname.h @@ -11,7 +11,7 @@ struct utsname { char domainname[_UTSNAME_LENGTH]; }; -#ifndef _KERNEL_ -int uname(struct utsname *); -#endif +#ifndef _KERNEL_ +extern int uname(struct utsname *__name); +#endif diff --git a/base/usr/include/sys/wait.h b/base/usr/include/sys/wait.h new file mode 100644 index 00000000..1d3ebd3a --- /dev/null +++ b/base/usr/include/sys/wait.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#define WNOHANG 0x0001 +#define WUNTRACED 0x0002 +#define WNOKERN 0x0010 + +/* This were taken from newlib, but they remain true */ +#define WIFEXITED(w) (((w) & 0xff) == 0) +#define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f)) +#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f) +#define WEXITSTATUS(w) (((w) >> 8) & 0xff) +#define WTERMSIG(w) ((w) & 0x7f) +#define WSTOPSIG WEXITSTATUS + + +#ifndef _KERNEL_ +extern pid_t wait(int*); +extern pid_t waitpid(pid_t, int *, int); +#endif diff --git a/toolchain/patches/newlib/include/syscall.h b/base/usr/include/syscall.h similarity index 94% rename from toolchain/patches/newlib/include/syscall.h rename to base/usr/include/syscall.h index b5a448c4..7fdbb0f3 100644 --- a/toolchain/patches/newlib/include/syscall.h +++ b/base/usr/include/syscall.h @@ -1,8 +1,7 @@ -#ifndef _SYSCALL_H -#define _SYSCALL_H +#pragma once #include -#include +#include #define DECL_SYSCALL0(fn) int syscall_##fn() #define DECL_SYSCALL1(fn,p1) int syscall_##fn(p1) @@ -111,8 +110,10 @@ DECL_SYSCALL2(stat, char *, void *); DECL_SYSCALL2(fswait,int,int*); DECL_SYSCALL3(fswait2,int,int*,int); DECL_SYSCALL3(chown,char*,int,int); - -#endif +DECL_SYSCALL3(waitpid, int, int *, int); +DECL_SYSCALL5(mount, char *, char *, char *, unsigned long, void *); +DECL_SYSCALL1(pipe, int *); +DECL_SYSCALL3(readlink, char *, char *, int); /* * vim:tabstop=4 * vim:noexpandtab diff --git a/toolchain/patches/newlib/include/syscall_nums.h b/base/usr/include/syscall_nums.h similarity index 100% rename from toolchain/patches/newlib/include/syscall_nums.h rename to base/usr/include/syscall_nums.h diff --git a/base/usr/include/termios.h b/base/usr/include/termios.h new file mode 100644 index 00000000..ee1820ce --- /dev/null +++ b/base/usr/include/termios.h @@ -0,0 +1,7 @@ +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif diff --git a/base/usr/include/time.h b/base/usr/include/time.h new file mode 100644 index 00000000..aed7c557 --- /dev/null +++ b/base/usr/include/time.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +struct tm { + int tm_sec; /* Seconds (0-60) */ + int tm_min; /* Minutes (0-59) */ + int tm_hour; /* Hours (0-23) */ + int tm_mday; /* Day of the month (1-31) */ + int tm_mon; /* Month (0-11) */ + int tm_year; /* Year - 1900 */ + int tm_wday; /* Day of the week (0-6, Sunday = 0) */ + int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */ + int tm_isdst; /* Daylight saving time */ +}; + +extern struct tm *localtime(const time_t *timep); +extern struct tm *gmtime(const time_t *timep); + +extern struct tm *localtime_r(const time_t *timep, struct tm * buf); +extern struct tm *gmtime_r(const time_t *timep, struct tm * buf); + +extern size_t strftime(char *s, size_t max, const char *format, const struct tm *tm); +extern time_t time(time_t * out); +extern double difftime(time_t a, time_t b); +extern time_t mktime(struct tm *tm); + +extern char * asctime(const struct tm *tm); +extern char * ctime(const time_t * timep); + +typedef int clock_t; + +extern clock_t clock(void); +#define CLOCKS_PER_SEC 1 diff --git a/userspace/lib/toaru_auth.h b/base/usr/include/toaru/auth.h similarity index 58% rename from userspace/lib/toaru_auth.h rename to base/usr/include/toaru/auth.h index a1b3e2ac..d1e5348c 100644 --- a/userspace/lib/toaru_auth.h +++ b/base/usr/include/toaru/auth.h @@ -1,11 +1,11 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2018 K. Lange */ #pragma once -int toaru_auth_check_pass(char * user, char * pass); -void toaru_auth_set_vars(void); +extern int toaru_auth_check_pass(char * user, char * pass); +extern void toaru_auth_set_vars(void); diff --git a/userspace/lib/confreader.h b/base/usr/include/toaru/confreader.h similarity index 95% rename from userspace/lib/confreader.h rename to base/usr/include/toaru/confreader.h index b50cb33a..f1fcb934 100644 --- a/userspace/lib/confreader.h +++ b/base/usr/include/toaru/confreader.h @@ -3,7 +3,7 @@ #pragma once -#include "hashmap.h" +#include typedef struct { hashmap_t * sections; diff --git a/base/usr/include/toaru/decodeutf8.h b/base/usr/include/toaru/decodeutf8.h new file mode 100644 index 00000000..aec6b74e --- /dev/null +++ b/base/usr/include/toaru/decodeutf8.h @@ -0,0 +1,47 @@ +/* + * Stateful UTF-8 decoder + */ + +#include + +#define UTF8_ACCEPT 0 +#define UTF8_REJECT 1 + + +static inline uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t byte) { + static int state_table[32] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xxxxxxx */ + 1,1,1,1,1,1,1,1, /* 10xxxxxx */ + 2,2,2,2, /* 110xxxxx */ + 3,3, /* 1110xxxx */ + 4, /* 11110xxx */ + 1 /* 11111xxx */ + }; + + static int mask_bytes[32] = { + 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, + 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x1F,0x1F,0x1F,0x1F, + 0x0F,0x0F, + 0x07, + 0x00 + }; + + static int next[5] = { + 0, + 1, + 0, + 2, + 3 + }; + + if (*state == UTF8_ACCEPT) { + *codep = byte & mask_bytes[byte >> 3]; + *state = state_table[byte >> 3]; + } else if (*state > 0) { + *codep = (byte & 0x3F) | (*codep << 6); + *state = next[*state]; + } + return *state; +} diff --git a/userspace/lib/decorations.h b/base/usr/include/toaru/decorations.h similarity index 58% rename from userspace/lib/decorations.h rename to base/usr/include/toaru/decorations.h index 0772cd66..284c85fc 100644 --- a/userspace/lib/decorations.h +++ b/base/usr/include/toaru/decorations.h @@ -6,13 +6,8 @@ #pragma once -#include "graphics.h" -#include "yutani.h" - -extern uint32_t decor_top_height; -extern uint32_t decor_bottom_height; -extern uint32_t decor_left_width; -extern uint32_t decor_right_width; +#include +#include /* * Render decorations to a window. A buffer pointer is @@ -24,31 +19,50 @@ extern uint32_t decor_right_width; extern void render_decorations(yutani_window_t * window, gfx_context_t * ctx, char * title); extern void render_decorations_inactive(yutani_window_t * window, gfx_context_t * ctx, char * title); +/** + * Decoration boundaries + */ +struct decor_bounds { + int top_height; + int bottom_height; + int left_width; + int right_width; + + /* Convenience */ + int width; + int height; +}; + /* * Used by decoration libraries to set callbacks */ extern void (*decor_render_decorations)(yutani_window_t *, gfx_context_t *, char *, int); extern int (*decor_check_button_press)(yutani_window_t *, int x, int y); +extern int (*decor_get_bounds)(yutani_window_t *, struct decor_bounds *); /* * Run me once to set things up */ extern void init_decorations(); -extern uint32_t decor_width(); -extern uint32_t decor_height(); - extern int decor_handle_event(yutani_t * yctx, yutani_msg_t * m); /* Callbacks for handle_event */ extern void decor_set_close_callback(void (*callback)(yutani_window_t *)); extern void decor_set_resize_callback(void (*callback)(yutani_window_t *)); +extern void decor_set_maximize_callback(void (*callback)(yutani_window_t *)); +extern yutani_window_t * decor_show_default_menu(yutani_window_t * window, int y, int x); /* Responses from handle_event */ -#define DECOR_OTHER 1 -#define DECOR_CLOSE 2 -#define DECOR_RESIZE 3 +#define DECOR_OTHER 1 /* Clicked on title bar but otherwise unimportant */ +#define DECOR_CLOSE 2 /* Clicked on close button */ +#define DECOR_RESIZE 3 /* Resize button */ +#define DECOR_MAXIMIZE 4 +#define DECOR_RIGHT 5 #define DECOR_ACTIVE 0 #define DECOR_INACTIVE 1 +#define DECOR_FLAG_DECORATED (1 << 0) +#define DECOR_FLAG_NO_MAXIMIZE (1 << 1) +#define DECOR_FLAG_TILED (1 << 2) diff --git a/base/usr/include/toaru/drawstring.h b/base/usr/include/toaru/drawstring.h new file mode 100644 index 00000000..f55129d3 --- /dev/null +++ b/base/usr/include/toaru/drawstring.h @@ -0,0 +1,5 @@ +#pragma once +#include + +void draw_string(gfx_context_t * ctx, int x, int y, uint32_t _fg, char * str); +int draw_string_width(char * str); diff --git a/base/usr/include/toaru/graphics.h b/base/usr/include/toaru/graphics.h new file mode 100644 index 00000000..25f99aa7 --- /dev/null +++ b/base/usr/include/toaru/graphics.h @@ -0,0 +1,113 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +#include +#include + +#define GFX_W(ctx) ((ctx)->width) /* Display width */ +#define GFX_H(ctx) ((ctx)->height) /* Display height */ +#define GFX_B(ctx) ((ctx)->depth / 8) /* Display byte depth */ +#define GFX_S(ctx) ((ctx)->stride) /* Stride */ + +#define _RED(color) ((color & 0x00FF0000) / 0x10000) +#define _GRE(color) ((color & 0x0000FF00) / 0x100) +#define _BLU(color) ((color & 0x000000FF) / 0x1) +#define _ALP(color) ((color & 0xFF000000) / 0x1000000) + +/* + * Macros make verything easier. + */ +#define GFX(ctx,x,y) *((uint32_t *)&((ctx)->backbuffer)[(GFX_S(ctx) * (y) + (x) * GFX_B(ctx))]) +#define GFXR(ctx,x,y) *((uint32_t *)&((ctx)->buffer)[(GFX_S(ctx) * (y) + (x) * GFX_B(ctx))]) +#define SPRITE(sprite,x,y) sprite->bitmap[sprite->width * (y) + (x)] +#define SMASKS(sprite,x,y) sprite->masks[sprite->width * (y) + (x)] + +typedef struct sprite { + uint16_t width; + uint16_t height; + uint32_t * bitmap; + uint32_t * masks; + uint32_t blank; + uint8_t alpha; +} sprite_t; + +typedef struct context { + uint16_t width; + uint16_t height; + uint16_t depth; + uint32_t size; + char * buffer; + char * backbuffer; + char * clips; + int32_t clips_size; + uint32_t stride; +} gfx_context_t; + +extern gfx_context_t * init_graphics_fullscreen(); +extern gfx_context_t * init_graphics_fullscreen_double_buffer(); +extern void reinit_graphics_fullscreen(gfx_context_t * ctx); + +#define ALPHA_OPAQUE 0 +#define ALPHA_MASK 1 +#define ALPHA_EMBEDDED 2 +#define ALPHA_INDEXED 3 +#define ALPHA_FORCE_SLOW_EMBEDDED 4 + +extern uint32_t rgb(uint8_t r, uint8_t g, uint8_t b); +extern uint32_t rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); +extern uint32_t alpha_blend(uint32_t bottom, uint32_t top, uint32_t mask); +extern uint32_t alpha_blend_rgba(uint32_t bottom, uint32_t top); +extern uint32_t framebuffer_stride(void); + +extern void flip(gfx_context_t * ctx); +void clear_buffer(gfx_context_t * ctx); + +extern gfx_context_t * init_graphics_sprite(sprite_t * sprite); +extern sprite_t * create_sprite(size_t width, size_t height, int alpha); + +extern void blur_context(gfx_context_t * _dst, gfx_context_t * _src, double amount); +extern void blur_context_no_vignette(gfx_context_t * _dst, gfx_context_t * _src, double amount); +extern void blur_context_box(gfx_context_t * _src, int radius); +extern void sprite_free(sprite_t * sprite); + +extern void load_sprite(sprite_t * sprite, char * filename); +//extern int load_sprite_png(sprite_t * sprite, char * file); +extern void draw_sprite(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y); +extern void draw_line(gfx_context_t * ctx, int32_t x0, int32_t x1, int32_t y0, int32_t y1, uint32_t color); +extern void draw_line_thick(gfx_context_t * ctx, int32_t x0, int32_t x1, int32_t y0, int32_t y1, uint32_t color, char thickness); +extern void draw_fill(gfx_context_t * ctx, uint32_t color); + +extern void draw_sprite_scaled(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, uint16_t width, uint16_t height); +extern void draw_sprite_scaled_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, uint16_t width, uint16_t height, float alpha); +extern void draw_sprite_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, float alpha); +extern void draw_sprite_alpha_paint(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, float alpha, uint32_t c); + +//extern void context_to_png(FILE * file, gfx_context_t * ctx); + +extern uint32_t premultiply(uint32_t color); + +extern void gfx_add_clip(gfx_context_t * ctx, int32_t x, int32_t y, int32_t w, int32_t h); +extern void gfx_clear_clip(gfx_context_t * ctx); +extern void gfx_no_clip(gfx_context_t * ctx); + +extern uint32_t getBilinearFilteredPixelColor(sprite_t * tex, double u, double v); + +extern uint32_t interp_colors(uint32_t bottom, uint32_t top, uint8_t interp); +extern void draw_rounded_rectangle(gfx_context_t * ctx, int32_t x, int32_t y, uint16_t width, uint16_t height, int radius, uint32_t color); +extern void draw_rectangle(gfx_context_t * ctx, int32_t x, int32_t y, uint16_t width, uint16_t height, uint32_t color); + +struct gfx_point { + float x; + float y; +}; + +extern float gfx_point_distance(struct gfx_point * a, struct gfx_point * b); +extern float gfx_point_distance_squared(struct gfx_point * a, struct gfx_point * b); +extern float gfx_point_dot(struct gfx_point * a, struct gfx_point * b); +extern struct gfx_point gfx_point_sub(struct gfx_point * a, struct gfx_point * b); +extern struct gfx_point gfx_point_add(struct gfx_point * a, struct gfx_point * b); +extern float gfx_line_distance(struct gfx_point * p, struct gfx_point * v, struct gfx_point * w); +extern void draw_line_aa(gfx_context_t * ctx, int x_1, int x_2, int y_1, int y_2, uint32_t color, float thickness); + +extern void draw_sprite_rotate(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, float rotation, float alpha); diff --git a/base/usr/include/toaru/hashmap.h b/base/usr/include/toaru/hashmap.h new file mode 100644 index 00000000..f896877e --- /dev/null +++ b/base/usr/include/toaru/hashmap.h @@ -0,0 +1,49 @@ +#pragma once + + +#ifdef _KERNEL_ +# include +#else +# include +# include +# include +#endif + +#include + +typedef unsigned int (*hashmap_hash_t) (void * key); +typedef int (*hashmap_comp_t) (void * a, void * b); +typedef void (*hashmap_free_t) (void *); +typedef void * (*hashmap_dupe_t) (void *); + +typedef struct hashmap_entry { + char * key; + void * value; + struct hashmap_entry * next; +} hashmap_entry_t; + +typedef struct hashmap { + hashmap_hash_t hash_func; + hashmap_comp_t hash_comp; + hashmap_dupe_t hash_key_dup; + hashmap_free_t hash_key_free; + hashmap_free_t hash_val_free; + size_t size; + hashmap_entry_t ** entries; +} hashmap_t; + +extern hashmap_t * hashmap_create(int size); +extern hashmap_t * hashmap_create_int(int size); +extern void * hashmap_set(hashmap_t * map, void * key, void * value); +extern void * hashmap_get(hashmap_t * map, void * key); +extern void * hashmap_remove(hashmap_t * map, void * key); +extern int hashmap_has(hashmap_t * map, void * key); +extern list_t * hashmap_keys(hashmap_t * map); +extern list_t * hashmap_values(hashmap_t * map); +extern void hashmap_free(hashmap_t * map); + +extern unsigned int hashmap_string_hash(void * key); +extern int hashmap_string_comp(void * a, void * b); +extern void * hashmap_string_dupe(void * key); +extern int hashmap_is_empty(hashmap_t * map); + diff --git a/base/usr/include/toaru/icon_cache.h b/base/usr/include/toaru/icon_cache.h new file mode 100644 index 00000000..f43afa2a --- /dev/null +++ b/base/usr/include/toaru/icon_cache.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +extern sprite_t * icon_get_16(const char * name); +extern sprite_t * icon_get_48(const char * name); + diff --git a/userspace/lib/kbd.h b/base/usr/include/toaru/kbd.h similarity index 74% rename from userspace/lib/kbd.h rename to base/usr/include/toaru/kbd.h index a818f6d3..7dcab513 100644 --- a/userspace/lib/kbd.h +++ b/base/usr/include/toaru/kbd.h @@ -83,6 +83,25 @@ #define KEY_END 2016 #define KEY_DEL 2017 #define KEY_INSERT 2018 +#define KEY_PAUSE 2019 +#define KEY_SCROLL_LOCK 2020 + +#define KEY_NUM_0 2500 +#define KEY_NUM_1 2501 +#define KEY_NUM_2 2502 +#define KEY_NUM_3 2503 +#define KEY_NUM_4 2504 +#define KEY_NUM_5 2505 +#define KEY_NUM_6 2506 +#define KEY_NUM_7 2507 +#define KEY_NUM_8 2508 +#define KEY_NUM_9 2509 +#define KEY_NUM_DOT 2510 +#define KEY_NUM_DIV 2511 +#define KEY_NUM_STAR 2512 +#define KEY_NUM_MINUS 2513 +#define KEY_NUM_PLUS 2514 +#define KEY_NUM_ENTER 2515 #define KEY_SCANCODE_F1 0x3b #define KEY_SCANCODE_F2 0x3c @@ -97,6 +116,23 @@ #define KEY_SCANCODE_F11 0x57 #define KEY_SCANCODE_F12 0x58 +#define KEY_SCANCODE_NUM_1 0x4f +#define KEY_SCANCODE_NUM_2 0x50 +#define KEY_SCANCODE_NUM_3 0x51 +#define KEY_SCANCODE_NUM_4 0x4B +#define KEY_SCANCODE_NUM_5 0x4C +#define KEY_SCANCODE_NUM_6 0x4D +#define KEY_SCANCODE_NUM_7 0x47 +#define KEY_SCANCODE_NUM_8 0x48 +#define KEY_SCANCODE_NUM_9 0x49 +#define KEY_SCANCODE_NUM_0 0x52 +#define KEY_SCANCODE_NUM_DOT 0x53 +#define KEY_SCANCODE_NUM_MIN 0x4a +#define KEY_SCANCODE_NUM_ADD 0x4e + +#define KEY_SCANCODE_NUM_LK 0x45 +#define KEY_SCANCODE_SCROLL 0x46 + #define KEY_MOD_LEFT_CTRL 0x01 #define KEY_MOD_LEFT_SHIFT 0x02 #define KEY_MOD_LEFT_ALT 0x04 @@ -144,6 +180,6 @@ typedef struct { int kbd_esc_buf; } key_event_state_t; -kbd_key_t kbd_key(key_event_state_t * state, unsigned char c); -int kbd_scancode(key_event_state_t * state, unsigned char c, key_event_t * event); +extern kbd_key_t kbd_key(key_event_state_t * state, unsigned char c); +extern int kbd_scancode(key_event_state_t * state, unsigned char c, key_event_t * event); diff --git a/base/usr/include/toaru/list.h b/base/usr/include/toaru/list.h new file mode 100644 index 00000000..f0b8b380 --- /dev/null +++ b/base/usr/include/toaru/list.h @@ -0,0 +1,50 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * General-purpose list implementations. + */ +#pragma once + +#ifdef _KERNEL_ +# include +#else +# include +# include +# include +#endif + +typedef struct node { + struct node * next; + struct node * prev; + void * value; + void * owner; +} __attribute__((packed)) node_t; + +typedef struct { + node_t * head; + node_t * tail; + size_t length; +} __attribute__((packed)) list_t; + +extern void list_destroy(list_t * list); +extern void list_free(list_t * list); +extern void list_append(list_t * list, node_t * item); +extern node_t * list_insert(list_t * list, void * item); +extern list_t * list_create(void); +extern node_t * list_find(list_t * list, void * value); +extern int list_index_of(list_t * list, void * value); +extern void list_remove(list_t * list, size_t index); +extern void list_delete(list_t * list, node_t * node); +extern node_t * list_pop(list_t * list); +extern node_t * list_dequeue(list_t * list); +extern list_t * list_copy(list_t * original); +extern void list_merge(list_t * target, list_t * source); + +extern void list_append_after(list_t * list, node_t * before, node_t * node); +extern node_t * list_insert_after(list_t * list, node_t * before, void * item); + +extern void list_append_before(list_t * list, node_t * after, node_t * node); +extern node_t * list_insert_before(list_t * list, node_t * after, void * item); + +#define foreach(i, list) for (node_t * i = (list)->head; i != NULL; i = i->next) +#define foreachr(i, list) for (node_t * i = (list)->tail; i != NULL; i = i->prev) + diff --git a/base/usr/include/toaru/menu.h b/base/usr/include/toaru/menu.h new file mode 100644 index 00000000..2810b9a3 --- /dev/null +++ b/base/usr/include/toaru/menu.h @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include + +enum MenuEntry_Type { + MenuEntry_Unknown, + MenuEntry_Normal, + MenuEntry_Submenu, + MenuEntry_Separator, +}; + +struct MenuList; + +struct MenuEntry { + enum MenuEntry_Type _type; + struct MenuList * _owner; + + int height; /* All must have a height, so put it here. */ + int width; /* Actual width */ + int rwidth; /* Requested width */ + int hilight; /* Is currently hilighted */ + int offset; /* Our offset when we were rendered */ + + void (*renderer)(gfx_context_t *, struct MenuEntry *, int); + void (*focus_change)(struct MenuEntry *, int); + void (*activate)(struct MenuEntry *, int); + + void (*callback)(struct MenuEntry *); +}; + +struct MenuEntry_Normal { + struct MenuEntry; /* dependent on plan9 extensions */ + const char * icon; + const char * title; + const char * action; +}; + +struct MenuEntry_Submenu { + struct MenuEntry; + const char * icon; + const char * title; + const char * action; + struct MenuList * _my_child; +}; + +struct MenuEntry_Separator { + struct MenuEntry; +}; + +struct MenuList { + list_t * entries; + gfx_context_t * ctx; + yutani_window_t * window; + struct MenuSet * set; + struct MenuList * child; + struct MenuList * parent; + struct menu_bar * _bar; + int closed; +}; + +struct MenuSet { + hashmap_t * _menus; +}; + +extern struct MenuEntry * menu_create_normal(const char * icon, const char * action, const char * title, void (*callback)(struct MenuEntry *)); +extern struct MenuEntry * menu_create_submenu(const char * icon, const char * action, const char * title); +extern struct MenuEntry * menu_create_separator(void); +extern struct MenuList * menu_create(void); +extern struct MenuSet * menu_set_from_description(const char * path, void (*callback)(struct MenuEntry *)); + +extern void menu_insert(struct MenuList * menu, struct MenuEntry * entry); +extern void menu_show(struct MenuList * menu, yutani_t * yctx); +extern int menu_process_event(yutani_t * yctx, yutani_msg_t * m); +extern struct MenuList * menu_set_get_root(struct MenuSet * menu); +extern struct MenuList * menu_set_get_menu(struct MenuSet * menu, char * submenu); + +extern void menu_free_entry(struct MenuEntry * ptr); +extern void menu_free_menu(struct MenuList * ptr); +extern void menu_free_set(struct MenuSet * ptr); + +extern hashmap_t * menu_get_windows_hash(void); +extern int menu_definitely_close(struct MenuList * menu); +extern struct MenuSet * menu_set_create(void); +extern void menu_set_insert(struct MenuSet * set, char * action, struct MenuList * menu); +extern void menu_update_title(struct MenuEntry * self, char * new_title); + +#define MENU_BAR_HEIGHT 24 + +struct menu_bar_entries { + char * title; + char * action; +}; + +struct menu_bar { + int x; + int y; + int width; + + struct menu_bar_entries * entries; + + struct MenuSet * set; + + struct menu_bar_entries * active_entry; + struct MenuList * active_menu; + int active_menu_wid; + int active_entry_idx; + yutani_window_t * window; + + int num_entries; + + void (*redraw_callback)(void); +}; + +extern void menu_bar_render(struct menu_bar * self, gfx_context_t * ctx); +extern int menu_bar_mouse_event(yutani_t * yctx, yutani_window_t * window, struct menu_bar * self, struct yutani_msg_window_mouse_event * me, int x, int y); +extern void menu_bar_show_menu(yutani_t * yctx, yutani_window_t * window, struct menu_bar * self, int offset, struct menu_bar_entries * _entries); diff --git a/base/usr/include/toaru/mouse.h b/base/usr/include/toaru/mouse.h new file mode 100644 index 00000000..45138390 --- /dev/null +++ b/base/usr/include/toaru/mouse.h @@ -0,0 +1,20 @@ +#pragma once + +typedef enum { + LEFT_CLICK = 0x01, + RIGHT_CLICK = 0x02, + MIDDLE_CLICK = 0x04, + + MOUSE_SCROLL_UP = 0x10, + MOUSE_SCROLL_DOWN = 0x20, +} mouse_click_t; + +typedef struct { + uint32_t magic; + int32_t x_difference; + int32_t y_difference; + mouse_click_t buttons; +} mouse_device_packet_t; + +#define MOUSE_MAGIC 0xFEED1234 + diff --git a/base/usr/include/toaru/pex.h b/base/usr/include/toaru/pex.h new file mode 100644 index 00000000..6c0faee7 --- /dev/null +++ b/base/usr/include/toaru/pex.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +typedef struct pex_packet { + uintptr_t source; + size_t size; + uint8_t data[]; +} pex_packet_t; +#define MAX_PACKET_SIZE 1024 +#define PACKET_SIZE (sizeof(pex_packet_t) + MAX_PACKET_SIZE) + +typedef struct pex_header { + uintptr_t target; + uint8_t data[]; +} pex_header_t; + +extern size_t pex_send(FILE * sock, unsigned int rcpt, size_t size, char * blob); +extern size_t pex_broadcast(FILE * sock, size_t size, char * blob); +extern size_t pex_listen(FILE * sock, pex_packet_t * packet); + +extern size_t pex_reply(FILE * sock, size_t size, char * blob); +extern size_t pex_recv(FILE * sock, char * blob); +extern size_t pex_query(FILE * sock); + +extern FILE * pex_bind(char * target); +extern FILE * pex_connect(char * target); + diff --git a/userspace/lib/rline.h b/base/usr/include/toaru/rline.h similarity index 60% rename from userspace/lib/rline.h rename to base/usr/include/toaru/rline.h index 77209076..7812cda6 100644 --- a/userspace/lib/rline.h +++ b/base/usr/include/toaru/rline.h @@ -11,6 +11,7 @@ typedef struct { int cancel; int offset; int tabbed; + int quiet; } rline_context_t; typedef void (*rline_callback_t)(rline_context_t * context); @@ -26,15 +27,16 @@ typedef struct rline_callback { rline_callback_t rev_search; } rline_callbacks_t; -void rline_redraw(rline_context_t * context); -void rline_redraw_clean(rline_context_t * context); -void rline_insert(rline_context_t * context, const char * what); -int rline(char * buffer, int buf_size, rline_callbacks_t * callbacks); +extern void rline_redraw(rline_context_t * context); +extern void rline_redraw_clean(rline_context_t * context); +extern void rline_insert(rline_context_t * context, const char * what); +extern int rline(char * buffer, int buf_size, rline_callbacks_t * callbacks); +extern void rline_reverse_search(rline_context_t * context); -void rline_history_insert(char * str); -void rline_history_append_line(char * str); -char * rline_history_get(int item); -char * rline_history_prev(int item); +extern void rline_history_insert(char * str); +extern void rline_history_append_line(char * str); +extern char * rline_history_get(int item); +extern char * rline_history_prev(int item); #define RLINE_HISTORY_ENTRIES 128 extern char * rline_history[RLINE_HISTORY_ENTRIES]; diff --git a/base/usr/include/toaru/rline_exp.h b/base/usr/include/toaru/rline_exp.h new file mode 100644 index 00000000..488c09f8 --- /dev/null +++ b/base/usr/include/toaru/rline_exp.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +extern int rline_experimental(char * buffer, int buf_size); +extern int rline_exp_set_prompts(char * left, char * right, int left_width, int right_width); +extern int rline_exp_set_shell_commands(char ** cmds, int len); +extern int rline_exp_set_tab_complete_func(rline_callback_t func); +extern int rline_exp_set_syntax(char * name); diff --git a/base/usr/include/toaru/sdf.h b/base/usr/include/toaru/sdf.h new file mode 100644 index 00000000..dd56a742 --- /dev/null +++ b/base/usr/include/toaru/sdf.h @@ -0,0 +1,14 @@ +#pragma once + +enum sdf_font { + SDF_FONT_THIN, + SDF_FONT_BOLD, + SDF_FONT_MONO, + SDF_FONT_MONO_BOLD, + SDF_FONT_MONO_OBLIQUE, + SDF_FONT_MONO_BOLD_OBLIQUE, +}; + +extern int draw_sdf_string(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font); +extern int draw_sdf_string_width(const char * str, int size, int font); +extern int draw_sdf_string_gamma(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font, double _gamma); diff --git a/userspace/lib/spinlock.h b/base/usr/include/toaru/spinlock.h similarity index 100% rename from userspace/lib/spinlock.h rename to base/usr/include/toaru/spinlock.h diff --git a/userspace/gui/terminal/lib/termemu.h b/base/usr/include/toaru/termemu.h similarity index 94% rename from userspace/gui/terminal/lib/termemu.h rename to base/usr/include/toaru/termemu.h index baf7430c..ad7c06e4 100644 --- a/userspace/gui/terminal/lib/termemu.h +++ b/base/usr/include/toaru/termemu.h @@ -1,9 +1,9 @@ #pragma once #ifdef _KERNEL_ -# include +# include #else -#include +# include #endif #define TERM_BUF_LEN 128 @@ -27,12 +27,12 @@ typedef struct { void (*scroll)(int); void (*redraw_cursor)(void); void (*input_buffer_stuff)(char *); - void (*set_font_size)(float); void (*set_title)(char *); void (*set_cell_contents)(int,int,char *); int (*get_cell_width)(void); int (*get_cell_height)(void); void (*set_csr_on)(int); + void (*switch_buffer)(int); } term_callbacks_t; typedef struct { @@ -105,6 +105,6 @@ typedef struct { #define TERM_DEFAULT_FLAGS 0x00 /* Default flags for a cell */ #define TERM_DEFAULT_OPAC 0xF2 /* For background, default transparency */ -term_state_t * ansi_init(term_state_t * s, int w, int y, term_callbacks_t * callbacks_in); -void ansi_put(term_state_t * s, char c); +extern term_state_t * ansi_init(term_state_t * s, int w, int y, term_callbacks_t * callbacks_in); +extern void ansi_put(term_state_t * s, char c); diff --git a/base/usr/include/toaru/textregion.h b/base/usr/include/toaru/textregion.h new file mode 100644 index 00000000..fcf07034 --- /dev/null +++ b/base/usr/include/toaru/textregion.h @@ -0,0 +1,88 @@ +#pragma once + +#include +#include + +#include +#include + +struct TR_Font { + int typeface; /* Should probably be more flexible than int, but tough luck for now. */ + int size; + uint32_t color; + /* TODO shadow - we had built-in support for this in the old setup, not sure I want to do it here */ +}; + +/* TODO This should probably all use wchar_t, but the font library needs to support that as well. */ + +extern int tr_font_get_width(struct TR_Font * font, char * string); +extern int tr_font_write(struct TR_Font * font, gfx_context_t * ctx, int x, int y, char * string); + +struct TR_TextUnit { + char * string; + int unit_type; + int width; /* calculated on creation */ + + struct TR_Font * font; /* not a pointer */ + hashmap_t * extra; /* extra properties in hashmap if present */ + list_t * tag_group; /* tag group membership if present */ +}; + +extern void tr_textunit_set_tag_group(struct TR_TextUnit * self, list_t * tag_group); +extern void tr_textunit_set_font(struct TR_TextUnit * self, struct TR_Font * font); +extern void tr_textunit_set_extra(struct TR_TextUnit * self, char * key, void * data); + +struct TR_TextRegion { + int x; + int y; + + int width; + int height; + + struct TR_Font * font; + + char * text; + list_t * lines; + int align; + int valign; + int line_height; /* TODO should be property of lines */ + + struct TR_TextUnit * text_units; /* array */ + int scroll; + char * ellipsis; /* blank by default */ + bool one_line; /* False by default */ + + char * base_dir; /* Used for links and images */ + bool break_all; /* False by default */ + char * title; /* blank by default */ + int max_lines; /* 0 is None */ +}; + +struct TR_Offset { + struct TR_TextUnit * unit; + int line; + int left; + int right; + int index; +}; + +extern void tr_textregion_set_alignment(struct TR_TextRegion * self, int align); +extern void tr_textregion_set_valignment(struct TR_TextRegion * self, int align); +extern void tr_textregion_set_max_lines(struct TR_TextRegion * self, int max_lines); +extern int tr_textregion_get_visible_lines(struct TR_TextRegion * self); /* height / line_height */ +extern void tr_textregion_reflow(struct TR_TextRegion * self); +extern list_t * tr_textregion_units_from_text(struct TR_TextRegion * self, char * text, struct TR_Font * font, bool whitespace); + +extern void tr_textregion_set_one_line(struct TR_TextRegion * self, bool one_line); +extern void tr_textregion_set_ellipsis(struct TR_TextRegion * self, char * ellipsis); +extern void tr_textregion_set_text(struct TR_TextRegion* self, char * text); +extern void tr_textregion_set_font(struct TR_TextRegion* self, struct TR_Font * font); +extern void tr_textregion_set_line_height(struct TR_TextRegion * self, int line_height); +extern void tr_textregion_resize(struct TR_TextRegion * self, int width, int height); +extern void tr_textregion_move(struct TR_TextRegion * self, int x, int y); + +extern void tr_textregion_get_offset_at_index(struct TR_TextRegion* self, int index, struct TR_Offset * out); +extern void tr_textregion_pick(struct TR_TextRegion * self, int x, int y, struct TR_Offset * out); +extern struct TR_TextUnit * tr_textregion_click(struct TR_TextRegion * self, int x, int y); +extern void tr_textregion_draw(struct TR_TextRegion * self, gfx_context_t * ctx); + diff --git a/userspace/lib/trace.h b/base/usr/include/toaru/trace.h similarity index 100% rename from userspace/lib/trace.h rename to base/usr/include/toaru/trace.h diff --git a/base/usr/include/toaru/tree.h b/base/usr/include/toaru/tree.h new file mode 100644 index 00000000..06b60abf --- /dev/null +++ b/base/usr/include/toaru/tree.h @@ -0,0 +1,37 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * General-purpose tree implementation + */ +#pragma once + +#include + +typedef struct tree_node { + void * value; + list_t * children; + struct tree_node * parent; +} tree_node_t; + +typedef struct { + size_t nodes; + tree_node_t * root; +} tree_t; + +typedef uint8_t (*tree_comparator_t) (void *, void *); + +extern tree_t * tree_create(void); +extern void tree_set_root(tree_t * tree, void * value); +extern void tree_node_destroy(tree_node_t * node); +extern void tree_destroy(tree_t * tree); +extern void tree_free(tree_t * tree); +extern tree_node_t * tree_node_create(void * value); +extern void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node); +extern tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value); +extern tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle); +extern void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node); +extern void tree_node_remove(tree_t * tree, tree_node_t * node); +extern void tree_remove(tree_t * tree, tree_node_t * node); +extern tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator); +extern void tree_break_off(tree_t * tree, tree_node_t * node); + + diff --git a/base/usr/include/toaru/yutani-internal.h b/base/usr/include/toaru/yutani-internal.h new file mode 100644 index 00000000..80526301 --- /dev/null +++ b/base/usr/include/toaru/yutani-internal.h @@ -0,0 +1,68 @@ +#include + +#define YUTANI_SHMKEY(server_ident,buf,sz,win) sprintf(buf, "sys.%s.%d", server_ident, win->bufid); +#define YUTANI_SHMKEY_EXP(server_ident,buf,sz,bufid) sprintf(buf, "sys.%s.%d", server_ident, bufid); + +#define yutani_msg_buildx_hello_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_flip_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_flip)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_welcome_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_welcome)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_new_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_new)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_new_flags_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_new_flags)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_init_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_init)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_close_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_close)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_key_event_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_key_event)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_mouse_event_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_mouse_event)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_move_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_move)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_stack_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_stack)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_focus_change_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_focus_change)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_mouse_event_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_mouse_event)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_flip_region_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_flip_region)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_resize_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_resize)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_advertise_alloc(out, length) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_advertise) + length]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_subscribe_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_unsubscribe_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_query_windows_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_notify_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_session_end_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_focus_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_focus)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_key_bind_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_key_bind)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_drag_start_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_drag_start)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_update_shape_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_update_shape)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_warp_mouse_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_warp_mouse)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_show_mouse_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_show_mouse)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_window_resize_start_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_resize_start)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_special_request_alloc(out) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_special_request)]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; +#define yutani_msg_buildx_clipboard_alloc(out, length) char _yutani_tmp_ ## LINE [sizeof(struct yutani_message) + sizeof(struct yutani_msg_clipboard)+length]; yutani_msg_t * out = (void *)&_yutani_tmp_ ## LINE; + +extern void yutani_msg_buildx_hello(yutani_msg_t * msg); +extern void yutani_msg_buildx_flip(yutani_msg_t * msg, yutani_wid_t wid); +extern void yutani_msg_buildx_welcome(yutani_msg_t * msg, uint32_t width, uint32_t height); +extern void yutani_msg_buildx_window_new(yutani_msg_t * msg, uint32_t width, uint32_t height); +extern void yutani_msg_buildx_window_new_flags(yutani_msg_t * msg, uint32_t width, uint32_t height, uint32_t flags); +extern void yutani_msg_buildx_window_init(yutani_msg_t * msg, yutani_wid_t wid, uint32_t width, uint32_t height, uint32_t bufid); +extern void yutani_msg_buildx_window_close(yutani_msg_t * msg, yutani_wid_t wid); +extern void yutani_msg_buildx_key_event(yutani_msg_t * msg, yutani_wid_t wid, key_event_t * event, key_event_state_t * state); +extern void yutani_msg_buildx_mouse_event(yutani_msg_t * msg, yutani_wid_t wid, mouse_device_packet_t * event, int32_t type); +extern void yutani_msg_buildx_window_move(yutani_msg_t * msg, yutani_wid_t wid, int32_t x, int32_t y); +extern void yutani_msg_buildx_window_stack(yutani_msg_t * msg, yutani_wid_t wid, int z); +extern void yutani_msg_buildx_window_focus_change(yutani_msg_t * msg, yutani_wid_t wid, int focused); +extern void yutani_msg_buildx_window_mouse_event(yutani_msg_t * msg, yutani_wid_t wid, int32_t new_x, int32_t new_y, int32_t old_x, int32_t old_y, uint8_t buttons, uint8_t command); +extern void yutani_msg_buildx_flip_region(yutani_msg_t * msg, yutani_wid_t wid, int32_t x, int32_t y, int32_t width, int32_t height); +extern void yutani_msg_buildx_window_resize(yutani_msg_t * msg, uint32_t type, yutani_wid_t wid, uint32_t width, uint32_t height, uint32_t bufid, uint32_t flags); +extern void yutani_msg_buildx_window_advertise(yutani_msg_t * msg, yutani_wid_t wid, uint32_t flags, uint16_t * offsets, size_t length, char * data); +extern void yutani_msg_buildx_subscribe(yutani_msg_t * msg); +extern void yutani_msg_buildx_unsubscribe(yutani_msg_t * msg); +extern void yutani_msg_buildx_query_windows(yutani_msg_t * msg); +extern void yutani_msg_buildx_notify(yutani_msg_t * msg); +extern void yutani_msg_buildx_session_end(yutani_msg_t * msg); +extern void yutani_msg_buildx_window_focus(yutani_msg_t * msg, yutani_wid_t wid); +extern void yutani_msg_buildx_key_bind(yutani_msg_t * msg, kbd_key_t key, kbd_mod_t mod, int response); +extern void yutani_msg_buildx_window_drag_start(yutani_msg_t * msg, yutani_wid_t wid); +extern void yutani_msg_buildx_window_update_shape(yutani_msg_t * msg, yutani_wid_t wid, int set_shape); +extern void yutani_msg_buildx_window_warp_mouse(yutani_msg_t * msg, yutani_wid_t wid, int32_t x, int32_t y); +extern void yutani_msg_buildx_window_show_mouse(yutani_msg_t * msg, yutani_wid_t wid, int32_t show_mouse); +extern void yutani_msg_buildx_window_resize_start(yutani_msg_t * msg, yutani_wid_t wid, yutani_scale_direction_t direction); +extern void yutani_msg_buildx_special_request(yutani_msg_t * msg, yutani_wid_t wid, uint32_t request); +extern void yutani_msg_buildx_clipboard(yutani_msg_t * msg, char * content); + + diff --git a/base/usr/include/toaru/yutani-server.h b/base/usr/include/toaru/yutani-server.h new file mode 100644 index 00000000..d0884d85 --- /dev/null +++ b/base/usr/include/toaru/yutani-server.h @@ -0,0 +1,300 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + * + * Internal definitions used by the Yutani compositor + * and extension plugins. + */ +#pragma once + +#include +#include +#include + +/* Mouse resolution scaling */ +#define MOUSE_SCALE 3 +#define YUTANI_INCOMING_MOUSE_SCALE * 3 + +/* Mouse cursor hotspot */ +#define MOUSE_OFFSET_X 26 +#define MOUSE_OFFSET_Y 26 + +/* Mouse cursor size */ +#define MOUSE_WIDTH 64 +#define MOUSE_HEIGHT 64 + +/* How much the mouse needs to move to break off a tiled window */ +#define UNTILE_SENSITIVITY (MOUSE_SCALE * 5) + +/* Screenshot modes */ +#define YUTANI_SCREENSHOT_FULL 1 +#define YUTANI_SCREENSHOT_WINDOW 2 + +/* + * Animation effect types. + * XXX: Should this be in the client library? + */ +typedef enum { + YUTANI_EFFECT_NONE, + + /* Basic animations */ + YUTANI_EFFECT_FADE_IN, + YUTANI_EFFECT_FADE_OUT, + + /* XXX: Are these used? */ + YUTANI_EFFECT_MINIMIZE, + YUTANI_EFFECT_UNMINIMIZE, +} yutani_effect; + +/* Animation lengths */ +static int yutani_animation_lengths[] = { + 0, /* None */ + 200, /* Fade In */ + 200, /* Fade Out */ + 0, /* Minimize */ + 0, /* Unminimized */ +}; + +/* Debug Options */ +#define YUTANI_DEBUG_WINDOW_BOUNDS 1 +#define YUTANI_DEBUG_WINDOW_SHAPES 1 + +/* Command line flag values */ +struct { + int nested; + int nest_width; + int nest_height; +} yutani_options = { + .nested = 0, + .nest_width = 640, + .nest_height = 480, +}; + +/* + * Server window definitions + */ +typedef struct YutaniServerWindow { + /* Window identifier number */ + yutani_wid_t wid; + + /* Window location */ + signed long x; + signed long y; + + /* Stack order */ + unsigned short z; + + /* Window size */ + int32_t width; + int32_t height; + + /* Canvas buffer */ + uint8_t * buffer; + uint32_t bufid; + uint32_t newbufid; + uint8_t * newbuffer; + + /* Connection that owns this window */ + uint32_t owner; + + /* Rotation of windows XXX */ + int16_t rotation; + + /* Client advertisements */ + uint32_t client_flags; + uint16_t client_offsets[5]; + uint32_t client_length; + char * client_strings; + + /* Window animations */ + int anim_mode; + uint32_t anim_start; + + /* Alpha shaping threshold */ + int alpha_threshold; + + /* + * Mouse cursor selection + * Originally, this specified whether the mouse was + * hidden, but it plays double duty since client + * control over mouse cursors was added. + */ + int show_mouse; + int default_mouse; + + /* Tiling / untiling information */ + int tiled; + int32_t untiled_width; + int32_t untiled_height; + int32_t untiled_left; + int32_t untiled_top; + + /* Client-configurable server behavior flags */ + uint32_t server_flags; + + /* Window opacity */ + int opacity; +} yutani_server_window_t; + +typedef struct YutaniGlobals { + /* Display resolution */ + unsigned int width; + unsigned int height; + uint32_t stride; + + /* TODO: What about multiple screens? + * + * Obviously this is the whole canvas size, + * but we need to be able to track different + * monitors if/when we ever get support for that. + */ + + /* Core graphics context */ + void * backend_framebuffer; + gfx_context_t * backend_ctx; + + /* Mouse location */ + signed int mouse_x; + signed int mouse_y; + + /* + * Previous mouse location, so that events can have + * both the new and old mouse location together + */ + signed int last_mouse_x; + signed int last_mouse_y; + + /* List of all windows */ + list_t * windows; + + /* Hash of window IDs to their objects */ + hashmap_t * wids_to_windows; + + /* + * Window stacking information + * TODO: Support multiple top and bottom windows. + */ + yutani_server_window_t * bottom_z; + list_t * mid_zs; + yutani_server_window_t * top_z; + + /* Damage region list */ + list_t * update_list; + volatile int update_list_lock; + + /* Mouse cursors */ + sprite_t mouse_sprite; + sprite_t mouse_sprite_drag; + sprite_t mouse_sprite_resize_v; + sprite_t mouse_sprite_resize_h; + sprite_t mouse_sprite_resize_da; + sprite_t mouse_sprite_resize_db; + int current_cursor; + + /* Server backend communication identifier */ + char * server_ident; + FILE * server; + + /* Pointer to focused window */ + yutani_server_window_t * focused_window; + + /* Mouse movement state */ + int mouse_state; + + /* Pointer to window being manipulated by mouse actions */ + yutani_server_window_t * mouse_window; + + /* Buffered information on mouse-moved window */ + int mouse_win_x; + int mouse_win_y; + int mouse_init_x; + int mouse_init_y; + int mouse_init_r; + + int32_t mouse_click_x_orig; + int32_t mouse_click_y_orig; + + int mouse_drag_button; + int mouse_moved; + + int32_t mouse_click_x; + int32_t mouse_click_y; + + /* Keyboard library state machine state */ + key_event_state_t kbd_state; + + /* Pointer to window being resized */ + yutani_server_window_t * resizing_window; + int32_t resizing_w; + int32_t resizing_h; + yutani_scale_direction_t resizing_direction; + int32_t resizing_offset_x; + int32_t resizing_offset_y; + int resizing_button; + + /* List of clients subscribing to window information events */ + list_t * window_subscribers; + + /* When the server started, used for timing functions */ + time_t start_time; + suseconds_t start_subtime; + + /* Basic lock to prevent redraw thread and communication thread interference */ + volatile int redraw_lock; + + /* Pointer to last hovered window to allow exit events */ + yutani_server_window_t * old_hover_window; + + /* Key bindigns */ + hashmap_t * key_binds; + + /* Windows to remove after the end of the rendering pass */ + list_t * windows_to_remove; + + /* For nested mode, the host Yutani context and window */ + yutani_t * host_context; + yutani_window_t * host_window; + + /* Map of clients to their windows */ + hashmap_t * clients_to_windows; + + /* Toggles for debugging window locations */ + int debug_bounds; + int debug_shapes; + + /* If the next rendered frame should be saved as a screenshot */ + int screenshot_frame; + + /* Next frame should resize host context */ + int resize_on_next; + + /* Last mouse buttons - used for some specialized mouse drivers */ + uint32_t last_mouse_buttons; + + /* Clipboard buffer */ + char clipboard[512]; + int clipboard_size; + + /* VirtualBox Seamless mode support information */ + int vbox_rects; + int vbox_pointer; + + /* Renderer plugin context */ + void * renderer_ctx; + + int reload_renderer; +} yutani_globals_t; + +struct key_bind { + unsigned int owner; + int response; +}; + +/* Exported functions for plugins */ +extern int yutani_window_is_top(yutani_globals_t * yg, yutani_server_window_t * window); +extern int yutani_window_is_bottom(yutani_globals_t * yg, yutani_server_window_t * window); +extern uint32_t yutani_time_since(yutani_globals_t * yg, uint32_t start_time); +extern void yutani_window_to_device(yutani_server_window_t * window, int32_t x, int32_t y, int32_t * out_x, int32_t * out_y); +extern void yutani_device_to_window(yutani_server_window_t * window, int32_t x, int32_t y, int32_t * out_x, int32_t * out_y); +extern uint32_t yutani_color_for_wid(yutani_wid_t wid); diff --git a/userspace/lib/yutani.h b/base/usr/include/toaru/yutani.h similarity index 78% rename from userspace/lib/yutani.h rename to base/usr/include/toaru/yutani.h index 750490d1..bcbc723a 100644 --- a/userspace/lib/yutani.h +++ b/base/usr/include/toaru/yutani.h @@ -1,49 +1,83 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014-2018 K. Lange + * + * Yutani Client Library + * + * Client library for the compositing window system. + */ #pragma once #include #include +#include -#include "hashmap.h" -#include "graphics.h" -#include "kbd.h" -#include "mouse.h" -#include "list.h" - -#define YUTANI_SHMKEY(server_ident,buf,sz,win) snprintf(buf, sz, "sys.%s.%d", server_ident, win->bufid); -#define YUTANI_SHMKEY_EXP(server_ident,buf,sz,bufid) snprintf(buf, sz, "sys.%s.%d", server_ident, bufid); +#include +#include +#include +#include +#include typedef unsigned int yutani_wid_t; -typedef enum { - SCALE_AUTO, - - SCALE_UP, - SCALE_DOWN, - SCALE_LEFT, - SCALE_RIGHT, - - SCALE_UP_LEFT, - SCALE_UP_RIGHT, - SCALE_DOWN_LEFT, - SCALE_DOWN_RIGHT, - - SCALE_NONE, -} yutani_scale_direction_t; - +/* + * Server connection context. + */ typedef struct yutani_context { FILE * sock; - /* XXX list of displays? */ - /* XXX display struct with more information? */ + /* server display size */ size_t display_width; size_t display_height; + /* Hash of window IDs to window objects */ hashmap_t * windows; + + /* queued events */ list_t * queued; + /* server identifier string */ char * server_ident; } yutani_t; +typedef struct yutani_window { + /* Server window identifier, unique to each window */ + yutani_wid_t wid; + + /* Window size */ + uint32_t width; + uint32_t height; + + /* Window backing buffer */ + char * buffer; + /* + * Because the buffer can change during resizing, + * buffers are indexed to ensure we are using + * the one the server expects. + */ + uint32_t bufid; + + /* Window focused flag */ + uint8_t focused; + + /* Old buffer ID */ + uint32_t oldbufid; + + /* Generic pointer for client use */ + void * user_data; + + /* Window position in the server; automatically updated */ + int32_t x; + int32_t y; + + /* Flags for the decorator library to use */ + uint32_t decorator_flags; + + /* Server context that owns this window */ + yutani_t * ctx; +} yutani_window_t; + typedef struct yutani_message { uint32_t magic; uint32_t type; @@ -133,6 +167,7 @@ struct yutani_msg_window_resize { uint32_t width; uint32_t height; uint32_t bufid; + uint32_t flags; }; struct yutani_msg_window_advertise { @@ -173,29 +208,36 @@ struct yutani_msg_window_show_mouse { int32_t show_mouse; }; +typedef enum { + SCALE_AUTO, + + SCALE_UP, + SCALE_DOWN, + SCALE_LEFT, + SCALE_RIGHT, + + SCALE_UP_LEFT, + SCALE_UP_RIGHT, + SCALE_DOWN_LEFT, + SCALE_DOWN_RIGHT, + + SCALE_NONE, +} yutani_scale_direction_t; + struct yutani_msg_window_resize_start { yutani_wid_t wid; yutani_scale_direction_t direction; }; -struct yutani_msg_timer_request { - uint32_t precision; - uint32_t flags; +struct yutani_msg_special_request { + yutani_wid_t wid; + uint32_t request; }; -typedef struct yutani_window { - yutani_wid_t wid; - - uint32_t width; - uint32_t height; - - uint8_t * buffer; - uint32_t bufid;/* We occasionally replace the buffer; each is uniquely-indexed */ - - uint8_t focused; - - uint32_t oldbufid; -} yutani_window_t; +struct yutani_msg_clipboard { + uint32_t size; + char content[]; +}; /* Magic value */ #define YUTANI_MSG__MAGIC 0xABAD1DEA @@ -240,11 +282,12 @@ typedef struct yutani_window { #define YUTANI_MSG_WINDOW_UPDATE_SHAPE 0x00000050 +#define YUTANI_MSG_CLIPBOARD 0x00000060 + #define YUTANI_MSG_GOODBYE 0x000000F0 -/* Timing Event Requests */ -#define YUTANI_MSG_TIMER_REQUEST 0x00000100 -#define YUTANI_MSG_TIMER_TICK 0x00000101 +/* Special request (eg. one-off single-shot requests like "please maximize me" */ +#define YUTANI_MSG_SPECIAL_REQUEST 0x00000100 /* Server responses */ #define YUTANI_MSG_WELCOME 0x00010001 @@ -391,6 +434,25 @@ typedef struct yutani_window { #define YUTANI_WINDOW_FLAG_DISALLOW_RESIZE (1 << 2) #define YUTANI_WINDOW_FLAG_ALT_ANIMATION (1 << 3) +/* YUTANI_SPECIAL_REQUEST + * + * Special one-off single-shot request messages. + */ +#define YUTANI_SPECIAL_REQUEST_MAXIMIZE 1 +#define YUTANI_SPECIAL_REQUEST_PLEASE_CLOSE 2 + +#define YUTANI_SPECIAL_REQUEST_CLIPBOARD 10 + +#define YUTANI_SPECIAL_REQUEST_RELOAD 20 + +/* + * YUTANI_RESIZE + * + * Flags provided in resize offers describing the window state. + */ +#define YUTANI_RESIZE_NORMAL 0 +#define YUTANI_RESIZE_TILED 1 + typedef struct { int x; int y; @@ -403,37 +465,6 @@ extern yutani_msg_t * yutani_poll(yutani_t * y); extern yutani_msg_t * yutani_poll_async(yutani_t * y); extern size_t yutani_query(yutani_t * y); -extern yutani_msg_t * yutani_msg_build_hello(void); -extern yutani_msg_t * yutani_msg_build_welcome(uint32_t width, uint32_t height); -extern yutani_msg_t * yutani_msg_build_window_new(uint32_t width, uint32_t height); -extern yutani_msg_t * yutani_msg_build_window_new_flags(uint32_t width, uint32_t height, uint32_t flags); -extern yutani_msg_t * yutani_msg_build_window_init(yutani_wid_t wid, uint32_t width, uint32_t height, uint32_t bufid); -extern yutani_msg_t * yutani_msg_build_flip(yutani_wid_t); -extern yutani_msg_t * yutani_msg_build_key_event(yutani_wid_t wid, key_event_t * event, key_event_state_t * state); -extern yutani_msg_t * yutani_msg_build_mouse_event(yutani_wid_t wid, mouse_device_packet_t * event, int32_t type); -extern yutani_msg_t * yutani_msg_build_window_move(yutani_wid_t wid, int32_t x, int32_t y); -extern yutani_msg_t * yutani_msg_build_window_close(yutani_wid_t wid); -extern yutani_msg_t * yutani_msg_build_window_stack(yutani_wid_t wid, int z); -extern yutani_msg_t * yutani_msg_build_window_focus_change(yutani_wid_t wid, int focused); -extern yutani_msg_t * yutani_msg_build_window_mouse_event(yutani_wid_t wid, int32_t new_x, int32_t new_y, int32_t old_x, int32_t old_y, uint8_t buttons, uint8_t command); -extern yutani_msg_t * yutani_msg_build_window_resize(uint32_t type, yutani_wid_t wid, uint32_t width, uint32_t height, uint32_t bufid); -extern yutani_msg_t * yutani_msg_build_window_advertise(yutani_wid_t wid, uint32_t flags, uint16_t * offsets, size_t length, char * data); -extern yutani_msg_t * yutani_msg_build_subscribe(void); -extern yutani_msg_t * yutani_msg_build_unsubscribe(void); -extern yutani_msg_t * yutani_msg_build_query(void); -extern yutani_msg_t * yutani_msg_build_notify(void); -extern yutani_msg_t * yutani_msg_build_session_end(void); -extern yutani_msg_t * yutani_msg_build_window_focus(yutani_wid_t wid); -extern yutani_msg_t * yutani_msg_build_key_bind(kbd_key_t key, kbd_mod_t mod, int response); -extern yutani_msg_t * yutani_msg_build_window_drag_start(yutani_wid_t wid); -extern yutani_msg_t * yutani_msg_build_window_update_shape(yutani_wid_t wid, int set_shape); -extern yutani_msg_t * yutani_msg_build_window_warp_mouse(yutani_wid_t wid, int32_t x, int32_t y); -extern yutani_msg_t * yutani_msg_build_window_show_mouse(yutani_wid_t wid, int32_t show_mouse); -extern yutani_msg_t * yutani_msg_build_window_resize_start(yutani_wid_t wid, yutani_scale_direction_t direction); -extern yutani_msg_t * yutani_msg_build_timer_request(uint32_t precision, uint32_t flags); -extern yutani_msg_t * yutani_msg_build_timer_tick(void); - - extern int yutani_msg_send(yutani_t * y, yutani_msg_t * msg); extern yutani_t * yutani_context_create(FILE * socket); extern yutani_t * yutani_init(void); @@ -457,12 +488,15 @@ extern void yutani_session_end(yutani_t * y); extern void yutani_focus_window(yutani_t * y, yutani_wid_t wid); extern void yutani_key_bind(yutani_t * yctx, kbd_key_t key, kbd_mod_t mod, int response); extern void yutani_window_drag_start(yutani_t * yctx, yutani_window_t * window); +extern void yutani_window_drag_start_wid(yutani_t * yctx, yutani_wid_t wid); extern void yutani_window_update_shape(yutani_t * yctx, yutani_window_t * window, int set_shape); extern void yutani_window_warp_mouse(yutani_t * yctx, yutani_window_t * window, int32_t x, int32_t y); extern void yutani_window_show_mouse(yutani_t * yctx, yutani_window_t * window, int32_t show_mouse); extern void yutani_window_resize_start(yutani_t * yctx, yutani_window_t * window, yutani_scale_direction_t direction); -extern void yutani_timer_request(yutani_t * yctx, uint32_t precision, uint32_t flags); - +extern void yutani_special_request(yutani_t * yctx, yutani_window_t * window, uint32_t request); +extern void yutani_special_request_wid(yutani_t * yctx, yutani_wid_t wid, uint32_t request); +extern void yutani_set_clipboard(yutani_t * yctx, char * content); +extern FILE * yutani_open_clipboard(yutani_t * yctx); extern gfx_context_t * init_graphics_yutani(yutani_window_t * window); extern gfx_context_t * init_graphics_yutani_double_buffer(yutani_window_t * window); diff --git a/base/usr/include/unistd.h b/base/usr/include/unistd.h new file mode 100644 index 00000000..c842a5f7 --- /dev/null +++ b/base/usr/include/unistd.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include + +extern char **environ; + +extern pid_t getpid(void); +extern pid_t getppid(void); + +extern int close(int fd); + +extern pid_t fork(void); + +extern int execl(const char *path, const char *arg, ...); +extern int execlp(const char *file, const char *arg, ...); +extern int execle(const char *path, const char *arg, ...); +extern int execv(const char *path, char *const argv[]); +extern int execvp(const char *file, char *const argv[]); +extern int execvpe(const char *file, char *const argv[], char *const envp[]); +extern int execve(const char *name, char * const argv[], char * const envp[]); +extern void _exit(int status); + +extern int setuid(uid_t uid); + +extern uid_t getuid(void); +extern uid_t geteuid(void); +extern gid_t getgid(void); +extern gid_t getegid(void); +extern char * getcwd(char *buf, size_t size); +extern int pipe(int pipefd[2]); +extern int dup(int oldfd); +extern int dup2(int oldfd, int newfd); + +extern pid_t tcgetpgrp(int fd); +extern int tcsetpgrp(int fd, pid_t pgrp); + +extern ssize_t write(int fd, const void * buf, size_t count); +extern ssize_t read(int fd, void * buf, size_t count); + +extern int symlink(const char *target, const char *linkpath); +extern ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); + +extern int chdir(const char *path); +//extern int fchdir(int fd); +extern int isatty(int fd); + +extern unsigned int sleep(unsigned int seconds); +extern int usleep(useconds_t usec); +extern off_t lseek(int fd, off_t offset, int whence); + +extern int access(const char * pathname, int mode); + +extern int getopt(int argc, char * const argv[], const char * optstring); + +extern char * optarg; +extern int optind, opterr, optopt; + +extern int unlink(const char * pathname); + +/* Unimplemented stubs */ +struct utimbuf { + time_t actime; + time_t modtime; +}; +extern char * ttyname(int fd); +extern int utime(const char *filename, const struct utimbuf *times); +extern int rmdir(const char *pathname); /* TODO rm probably just works */ +extern int chown(const char * pathname, uid_t owner, gid_t group); + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +extern int gethostname(char * name, size_t len); +extern int sethostname(const char * name, size_t len); diff --git a/kernel/include/va_list.h b/base/usr/include/va_list.h similarity index 100% rename from kernel/include/va_list.h rename to base/usr/include/va_list.h diff --git a/base/usr/include/wait.h b/base/usr/include/wait.h new file mode 100644 index 00000000..2ff92505 --- /dev/null +++ b/base/usr/include/wait.h @@ -0,0 +1,4 @@ +#pragma once + +int waitpid(int pid, int *status, int options); +int wait(int *status); diff --git a/base/usr/include/wchar.h b/base/usr/include/wchar.h new file mode 100644 index 00000000..0261201c --- /dev/null +++ b/base/usr/include/wchar.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +extern int wcwidth(wchar_t c); +extern wchar_t * wcsncpy(wchar_t * dest, const wchar_t * src, size_t n); +extern size_t wcslen(const wchar_t * s); +extern int wcscmp(const wchar_t *s1, const wchar_t *s2); +extern wchar_t * wcscat(wchar_t *dest, const wchar_t *src); +extern wchar_t * wcstok(wchar_t * str, const wchar_t * delim, wchar_t ** saveptr); +extern size_t wcsspn(const wchar_t * wcs, const wchar_t * accept); +extern wchar_t *wcspbrk(const wchar_t *wcs, const wchar_t *accept); +extern wchar_t * wcschr(const wchar_t *wcs, wchar_t wc); +extern wchar_t * wcsrchr(const wchar_t *wcs, wchar_t wc); +extern wchar_t * wcsncat(wchar_t *dest, const wchar_t * src, size_t n); + +/* TODO */ +extern size_t wcstombs(char * dest, const wchar_t *src, size_t n); + +typedef unsigned int wint_t; diff --git a/hdd/dev/.dummy b/base/usr/lib/.dummy similarity index 100% rename from hdd/dev/.dummy rename to base/usr/lib/.dummy diff --git a/base/usr/share/cursor/drag.bmp b/base/usr/share/cursor/drag.bmp new file mode 100644 index 00000000..93e97b35 Binary files /dev/null and b/base/usr/share/cursor/drag.bmp differ diff --git a/base/usr/share/cursor/mouse.bmp b/base/usr/share/cursor/mouse.bmp new file mode 100644 index 00000000..c38156af Binary files /dev/null and b/base/usr/share/cursor/mouse.bmp differ diff --git a/base/usr/share/cursor/resize-dlur.bmp b/base/usr/share/cursor/resize-dlur.bmp new file mode 100644 index 00000000..be2b49ee Binary files /dev/null and b/base/usr/share/cursor/resize-dlur.bmp differ diff --git a/base/usr/share/cursor/resize-horizontal.bmp b/base/usr/share/cursor/resize-horizontal.bmp new file mode 100644 index 00000000..0ad21df4 Binary files /dev/null and b/base/usr/share/cursor/resize-horizontal.bmp differ diff --git a/base/usr/share/cursor/resize-uldr.bmp b/base/usr/share/cursor/resize-uldr.bmp new file mode 100644 index 00000000..a97f35ea Binary files /dev/null and b/base/usr/share/cursor/resize-uldr.bmp differ diff --git a/base/usr/share/cursor/resize-vertical.bmp b/base/usr/share/cursor/resize-vertical.bmp new file mode 100644 index 00000000..0f233e1e Binary files /dev/null and b/base/usr/share/cursor/resize-vertical.bmp differ diff --git a/base/usr/share/demo.menu b/base/usr/share/demo.menu new file mode 100644 index 00000000..e881acf2 --- /dev/null +++ b/base/usr/share/demo.menu @@ -0,0 +1,18 @@ +:_ +&accessories,folder,Accessories +&demos,folder,Demos +- +exec help-browser,help,Help Browser +exec about,star,About ToaruOS +log-out,exit,Log Out +:accessories +exec file-browser,folder,File Browser +exec terminal,utilities-terminal,Terminal +:demos +&decorated,folder,Decorated +&undecorated,folder,Undecorated +:undecorated +exec drawlines,drawlines,Draw Lines +:decorated +exec julia,julia,Julia Fractals +exec plasma,plasma,Plasma diff --git a/base/usr/share/icons/16/applications-generic.bmp b/base/usr/share/icons/16/applications-generic.bmp new file mode 100644 index 00000000..a2c249df Binary files /dev/null and b/base/usr/share/icons/16/applications-generic.bmp differ diff --git a/base/usr/share/icons/16/back.bmp b/base/usr/share/icons/16/back.bmp new file mode 100644 index 00000000..c38ee4c5 Binary files /dev/null and b/base/usr/share/icons/16/back.bmp differ diff --git a/base/usr/share/icons/16/bookmark.bmp b/base/usr/share/icons/16/bookmark.bmp new file mode 100644 index 00000000..acae97e1 Binary files /dev/null and b/base/usr/share/icons/16/bookmark.bmp differ diff --git a/base/usr/share/icons/16/calculator.bmp b/base/usr/share/icons/16/calculator.bmp new file mode 100644 index 00000000..b7b7ec65 Binary files /dev/null and b/base/usr/share/icons/16/calculator.bmp differ diff --git a/base/usr/share/icons/16/clock.bmp b/base/usr/share/icons/16/clock.bmp new file mode 100644 index 00000000..a320c9dd Binary files /dev/null and b/base/usr/share/icons/16/clock.bmp differ diff --git a/base/usr/share/icons/16/config.bmp b/base/usr/share/icons/16/config.bmp new file mode 100644 index 00000000..c9292484 Binary files /dev/null and b/base/usr/share/icons/16/config.bmp differ diff --git a/base/usr/share/icons/16/exit.bmp b/base/usr/share/icons/16/exit.bmp new file mode 100644 index 00000000..66204512 Binary files /dev/null and b/base/usr/share/icons/16/exit.bmp differ diff --git a/base/usr/share/icons/16/file.bmp b/base/usr/share/icons/16/file.bmp new file mode 100644 index 00000000..8ce4635b Binary files /dev/null and b/base/usr/share/icons/16/file.bmp differ diff --git a/base/usr/share/icons/16/folder.bmp b/base/usr/share/icons/16/folder.bmp new file mode 100644 index 00000000..b6885837 Binary files /dev/null and b/base/usr/share/icons/16/folder.bmp differ diff --git a/base/usr/share/icons/16/forward.bmp b/base/usr/share/icons/16/forward.bmp new file mode 100644 index 00000000..fb4cbeb8 Binary files /dev/null and b/base/usr/share/icons/16/forward.bmp differ diff --git a/base/usr/share/icons/16/help.bmp b/base/usr/share/icons/16/help.bmp new file mode 100644 index 00000000..405311fa Binary files /dev/null and b/base/usr/share/icons/16/help.bmp differ diff --git a/base/usr/share/icons/16/home.bmp b/base/usr/share/icons/16/home.bmp new file mode 100644 index 00000000..34fc5d3f Binary files /dev/null and b/base/usr/share/icons/16/home.bmp differ diff --git a/base/usr/share/icons/16/menu-tick.bmp b/base/usr/share/icons/16/menu-tick.bmp new file mode 100644 index 00000000..51767cdf Binary files /dev/null and b/base/usr/share/icons/16/menu-tick.bmp differ diff --git a/base/usr/share/icons/16/mines.bmp b/base/usr/share/icons/16/mines.bmp new file mode 100644 index 00000000..a4bd03fd Binary files /dev/null and b/base/usr/share/icons/16/mines.bmp differ diff --git a/base/usr/share/icons/16/missing.bmp b/base/usr/share/icons/16/missing.bmp new file mode 100644 index 00000000..a8cde2ba Binary files /dev/null and b/base/usr/share/icons/16/missing.bmp differ diff --git a/base/usr/share/icons/16/new.bmp b/base/usr/share/icons/16/new.bmp new file mode 100644 index 00000000..ce4d11f9 Binary files /dev/null and b/base/usr/share/icons/16/new.bmp differ diff --git a/base/usr/share/icons/16/open.bmp b/base/usr/share/icons/16/open.bmp new file mode 100644 index 00000000..a0c6de5c Binary files /dev/null and b/base/usr/share/icons/16/open.bmp differ diff --git a/base/usr/share/icons/16/package.bmp b/base/usr/share/icons/16/package.bmp new file mode 100644 index 00000000..0f2fb4a0 Binary files /dev/null and b/base/usr/share/icons/16/package.bmp differ diff --git a/base/usr/share/icons/16/refresh.bmp b/base/usr/share/icons/16/refresh.bmp new file mode 100644 index 00000000..29bd92e3 Binary files /dev/null and b/base/usr/share/icons/16/refresh.bmp differ diff --git a/base/usr/share/icons/16/save.bmp b/base/usr/share/icons/16/save.bmp new file mode 100644 index 00000000..f195e036 Binary files /dev/null and b/base/usr/share/icons/16/save.bmp differ diff --git a/base/usr/share/icons/16/star.bmp b/base/usr/share/icons/16/star.bmp new file mode 100644 index 00000000..7c0a0980 Binary files /dev/null and b/base/usr/share/icons/16/star.bmp differ diff --git a/base/usr/share/icons/16/up.bmp b/base/usr/share/icons/16/up.bmp new file mode 100644 index 00000000..2d7794fe Binary files /dev/null and b/base/usr/share/icons/16/up.bmp differ diff --git a/base/usr/share/icons/16/utilities-terminal.bmp b/base/usr/share/icons/16/utilities-terminal.bmp new file mode 100644 index 00000000..e7048689 Binary files /dev/null and b/base/usr/share/icons/16/utilities-terminal.bmp differ diff --git a/base/usr/share/icons/24/applications-generic.bmp b/base/usr/share/icons/24/applications-generic.bmp new file mode 100644 index 00000000..550015b7 Binary files /dev/null and b/base/usr/share/icons/24/applications-generic.bmp differ diff --git a/base/usr/share/icons/24/mouse-relative.bmp b/base/usr/share/icons/24/mouse-relative.bmp new file mode 100644 index 00000000..f21979a4 Binary files /dev/null and b/base/usr/share/icons/24/mouse-relative.bmp differ diff --git a/base/usr/share/icons/24/mouse-status.bmp b/base/usr/share/icons/24/mouse-status.bmp new file mode 100644 index 00000000..ae78dc55 Binary files /dev/null and b/base/usr/share/icons/24/mouse-status.bmp differ diff --git a/base/usr/share/icons/24/net-active.bmp b/base/usr/share/icons/24/net-active.bmp new file mode 100644 index 00000000..03b70a48 Binary files /dev/null and b/base/usr/share/icons/24/net-active.bmp differ diff --git a/base/usr/share/icons/24/net-disconnected.bmp b/base/usr/share/icons/24/net-disconnected.bmp new file mode 100644 index 00000000..cfa5b149 Binary files /dev/null and b/base/usr/share/icons/24/net-disconnected.bmp differ diff --git a/base/usr/share/icons/24/utilities-terminal.bmp b/base/usr/share/icons/24/utilities-terminal.bmp new file mode 100644 index 00000000..70dd5e49 Binary files /dev/null and b/base/usr/share/icons/24/utilities-terminal.bmp differ diff --git a/base/usr/share/icons/24/volume-full.bmp b/base/usr/share/icons/24/volume-full.bmp new file mode 100644 index 00000000..b5c5d51c Binary files /dev/null and b/base/usr/share/icons/24/volume-full.bmp differ diff --git a/base/usr/share/icons/24/volume-low.bmp b/base/usr/share/icons/24/volume-low.bmp new file mode 100644 index 00000000..a788d5a5 Binary files /dev/null and b/base/usr/share/icons/24/volume-low.bmp differ diff --git a/base/usr/share/icons/24/volume-medium.bmp b/base/usr/share/icons/24/volume-medium.bmp new file mode 100644 index 00000000..a4a1dd79 Binary files /dev/null and b/base/usr/share/icons/24/volume-medium.bmp differ diff --git a/base/usr/share/icons/24/volume-mute.bmp b/base/usr/share/icons/24/volume-mute.bmp new file mode 100644 index 00000000..486e5bdf Binary files /dev/null and b/base/usr/share/icons/24/volume-mute.bmp differ diff --git a/base/usr/share/icons/48/applications-generic.bmp b/base/usr/share/icons/48/applications-generic.bmp new file mode 100644 index 00000000..26c69498 Binary files /dev/null and b/base/usr/share/icons/48/applications-generic.bmp differ diff --git a/base/usr/share/icons/48/applications-painting.bmp b/base/usr/share/icons/48/applications-painting.bmp new file mode 100644 index 00000000..61d630c5 Binary files /dev/null and b/base/usr/share/icons/48/applications-painting.bmp differ diff --git a/base/usr/share/icons/48/calculator.bmp b/base/usr/share/icons/48/calculator.bmp new file mode 100644 index 00000000..f173e801 Binary files /dev/null and b/base/usr/share/icons/48/calculator.bmp differ diff --git a/base/usr/share/icons/48/clock.bmp b/base/usr/share/icons/48/clock.bmp new file mode 100644 index 00000000..b2a66bc7 Binary files /dev/null and b/base/usr/share/icons/48/clock.bmp differ diff --git a/base/usr/share/icons/48/drawlines.bmp b/base/usr/share/icons/48/drawlines.bmp new file mode 100644 index 00000000..99d40509 Binary files /dev/null and b/base/usr/share/icons/48/drawlines.bmp differ diff --git a/base/usr/share/icons/48/exit.bmp b/base/usr/share/icons/48/exit.bmp new file mode 100644 index 00000000..36c65bc2 Binary files /dev/null and b/base/usr/share/icons/48/exit.bmp differ diff --git a/base/usr/share/icons/48/file.bmp b/base/usr/share/icons/48/file.bmp new file mode 100644 index 00000000..f18d6333 Binary files /dev/null and b/base/usr/share/icons/48/file.bmp differ diff --git a/base/usr/share/icons/48/folder.bmp b/base/usr/share/icons/48/folder.bmp new file mode 100644 index 00000000..bcb0ae03 Binary files /dev/null and b/base/usr/share/icons/48/folder.bmp differ diff --git a/base/usr/share/icons/48/gears.bmp b/base/usr/share/icons/48/gears.bmp new file mode 100644 index 00000000..5775e3db Binary files /dev/null and b/base/usr/share/icons/48/gears.bmp differ diff --git a/base/usr/share/icons/48/help.bmp b/base/usr/share/icons/48/help.bmp new file mode 100644 index 00000000..ed5e9c66 Binary files /dev/null and b/base/usr/share/icons/48/help.bmp differ diff --git a/base/usr/share/icons/48/julia.bmp b/base/usr/share/icons/48/julia.bmp new file mode 100644 index 00000000..be4d0231 Binary files /dev/null and b/base/usr/share/icons/48/julia.bmp differ diff --git a/base/usr/share/icons/48/mines.bmp b/base/usr/share/icons/48/mines.bmp new file mode 100644 index 00000000..f8aac1da Binary files /dev/null and b/base/usr/share/icons/48/mines.bmp differ diff --git a/base/usr/share/icons/48/package-uninstalled.bmp b/base/usr/share/icons/48/package-uninstalled.bmp new file mode 100644 index 00000000..91b3a2b6 Binary files /dev/null and b/base/usr/share/icons/48/package-uninstalled.bmp differ diff --git a/base/usr/share/icons/48/package.bmp b/base/usr/share/icons/48/package.bmp new file mode 100644 index 00000000..0d76c7fe Binary files /dev/null and b/base/usr/share/icons/48/package.bmp differ diff --git a/base/usr/share/icons/48/plasma.bmp b/base/usr/share/icons/48/plasma.bmp new file mode 100644 index 00000000..bfcea84b Binary files /dev/null and b/base/usr/share/icons/48/plasma.bmp differ diff --git a/base/usr/share/icons/48/star.bmp b/base/usr/share/icons/48/star.bmp new file mode 100644 index 00000000..53cc6838 Binary files /dev/null and b/base/usr/share/icons/48/star.bmp differ diff --git a/base/usr/share/icons/48/utilities-terminal.bmp b/base/usr/share/icons/48/utilities-terminal.bmp new file mode 100644 index 00000000..83cb6e77 Binary files /dev/null and b/base/usr/share/icons/48/utilities-terminal.bmp differ diff --git a/base/usr/share/icons/panel-shutdown.bmp b/base/usr/share/icons/panel-shutdown.bmp new file mode 100644 index 00000000..3e983e40 Binary files /dev/null and b/base/usr/share/icons/panel-shutdown.bmp differ diff --git a/base/usr/share/icons/weather/01d.bmp b/base/usr/share/icons/weather/01d.bmp new file mode 100644 index 00000000..67aa3f49 Binary files /dev/null and b/base/usr/share/icons/weather/01d.bmp differ diff --git a/base/usr/share/icons/weather/01n.bmp b/base/usr/share/icons/weather/01n.bmp new file mode 100644 index 00000000..22f1cd36 Binary files /dev/null and b/base/usr/share/icons/weather/01n.bmp differ diff --git a/base/usr/share/icons/weather/02d.bmp b/base/usr/share/icons/weather/02d.bmp new file mode 100644 index 00000000..3be2a47a Binary files /dev/null and b/base/usr/share/icons/weather/02d.bmp differ diff --git a/base/usr/share/icons/weather/02n.bmp b/base/usr/share/icons/weather/02n.bmp new file mode 100644 index 00000000..46563ff1 Binary files /dev/null and b/base/usr/share/icons/weather/02n.bmp differ diff --git a/base/usr/share/icons/weather/03d.bmp b/base/usr/share/icons/weather/03d.bmp new file mode 120000 index 00000000..2802226f --- /dev/null +++ b/base/usr/share/icons/weather/03d.bmp @@ -0,0 +1 @@ +02d.bmp \ No newline at end of file diff --git a/base/usr/share/icons/weather/03n.bmp b/base/usr/share/icons/weather/03n.bmp new file mode 120000 index 00000000..ba14749e --- /dev/null +++ b/base/usr/share/icons/weather/03n.bmp @@ -0,0 +1 @@ +02n.bmp \ No newline at end of file diff --git a/base/usr/share/icons/weather/04d.bmp b/base/usr/share/icons/weather/04d.bmp new file mode 100644 index 00000000..1cc47a0d Binary files /dev/null and b/base/usr/share/icons/weather/04d.bmp differ diff --git a/base/usr/share/icons/weather/04n.bmp b/base/usr/share/icons/weather/04n.bmp new file mode 100644 index 00000000..d99f1a15 Binary files /dev/null and b/base/usr/share/icons/weather/04n.bmp differ diff --git a/base/usr/share/icons/weather/09d.bmp b/base/usr/share/icons/weather/09d.bmp new file mode 100644 index 00000000..5a388ae6 Binary files /dev/null and b/base/usr/share/icons/weather/09d.bmp differ diff --git a/base/usr/share/icons/weather/09n.bmp b/base/usr/share/icons/weather/09n.bmp new file mode 120000 index 00000000..9cd57e20 --- /dev/null +++ b/base/usr/share/icons/weather/09n.bmp @@ -0,0 +1 @@ +09d.bmp \ No newline at end of file diff --git a/base/usr/share/icons/weather/10d.bmp b/base/usr/share/icons/weather/10d.bmp new file mode 100644 index 00000000..2ab7599d Binary files /dev/null and b/base/usr/share/icons/weather/10d.bmp differ diff --git a/base/usr/share/icons/weather/10n.bmp b/base/usr/share/icons/weather/10n.bmp new file mode 120000 index 00000000..275ca5e5 --- /dev/null +++ b/base/usr/share/icons/weather/10n.bmp @@ -0,0 +1 @@ +10d.bmp \ No newline at end of file diff --git a/base/usr/share/icons/weather/11d.bmp b/base/usr/share/icons/weather/11d.bmp new file mode 100644 index 00000000..0a9cb3c2 Binary files /dev/null and b/base/usr/share/icons/weather/11d.bmp differ diff --git a/base/usr/share/icons/weather/11n.bmp b/base/usr/share/icons/weather/11n.bmp new file mode 120000 index 00000000..f459c00f --- /dev/null +++ b/base/usr/share/icons/weather/11n.bmp @@ -0,0 +1 @@ +11d.bmp \ No newline at end of file diff --git a/base/usr/share/icons/weather/13d.bmp b/base/usr/share/icons/weather/13d.bmp new file mode 100644 index 00000000..3fdeed06 Binary files /dev/null and b/base/usr/share/icons/weather/13d.bmp differ diff --git a/base/usr/share/icons/weather/13n.bmp b/base/usr/share/icons/weather/13n.bmp new file mode 120000 index 00000000..19049049 --- /dev/null +++ b/base/usr/share/icons/weather/13n.bmp @@ -0,0 +1 @@ +13d.bmp \ No newline at end of file diff --git a/base/usr/share/icons/weather/50d.bmp b/base/usr/share/icons/weather/50d.bmp new file mode 100644 index 00000000..18c8550c Binary files /dev/null and b/base/usr/share/icons/weather/50d.bmp differ diff --git a/base/usr/share/icons/weather/50n.bmp b/base/usr/share/icons/weather/50n.bmp new file mode 120000 index 00000000..33f9c80b --- /dev/null +++ b/base/usr/share/icons/weather/50n.bmp @@ -0,0 +1 @@ +50d.bmp \ No newline at end of file diff --git a/base/usr/share/logo_login.bmp b/base/usr/share/logo_login.bmp new file mode 100644 index 00000000..1601146e Binary files /dev/null and b/base/usr/share/logo_login.bmp differ diff --git a/base/usr/share/panel.bmp b/base/usr/share/panel.bmp new file mode 100644 index 00000000..180edd96 Binary files /dev/null and b/base/usr/share/panel.bmp differ diff --git a/base/usr/share/pong/ball.bmp b/base/usr/share/pong/ball.bmp new file mode 100644 index 00000000..9d9a10a7 Binary files /dev/null and b/base/usr/share/pong/ball.bmp differ diff --git a/base/usr/share/pong/paddle-blue.bmp b/base/usr/share/pong/paddle-blue.bmp new file mode 100644 index 00000000..a0bc3faf Binary files /dev/null and b/base/usr/share/pong/paddle-blue.bmp differ diff --git a/base/usr/share/pong/paddle-red.bmp b/base/usr/share/pong/paddle-red.bmp new file mode 100644 index 00000000..ba08e317 Binary files /dev/null and b/base/usr/share/pong/paddle-red.bmp differ diff --git a/base/usr/share/sdf_bold.bmp b/base/usr/share/sdf_bold.bmp new file mode 100644 index 00000000..30f7b33f Binary files /dev/null and b/base/usr/share/sdf_bold.bmp differ diff --git a/base/usr/share/sdf_mono.bmp b/base/usr/share/sdf_mono.bmp new file mode 100644 index 00000000..3e896b76 Binary files /dev/null and b/base/usr/share/sdf_mono.bmp differ diff --git a/base/usr/share/sdf_mono_bold.bmp b/base/usr/share/sdf_mono_bold.bmp new file mode 100644 index 00000000..651c043c Binary files /dev/null and b/base/usr/share/sdf_mono_bold.bmp differ diff --git a/base/usr/share/sdf_mono_bold_oblique.bmp b/base/usr/share/sdf_mono_bold_oblique.bmp new file mode 100644 index 00000000..69513828 Binary files /dev/null and b/base/usr/share/sdf_mono_bold_oblique.bmp differ diff --git a/base/usr/share/sdf_mono_oblique.bmp b/base/usr/share/sdf_mono_oblique.bmp new file mode 100644 index 00000000..87080dbe Binary files /dev/null and b/base/usr/share/sdf_mono_oblique.bmp differ diff --git a/base/usr/share/sdf_thin.bmp b/base/usr/share/sdf_thin.bmp new file mode 100644 index 00000000..9fa057bf Binary files /dev/null and b/base/usr/share/sdf_thin.bmp differ diff --git a/base/usr/share/ttk/active/button-close.bmp b/base/usr/share/ttk/active/button-close.bmp new file mode 100644 index 00000000..db1ae5eb Binary files /dev/null and b/base/usr/share/ttk/active/button-close.bmp differ diff --git a/base/usr/share/ttk/active/button-maximize.bmp b/base/usr/share/ttk/active/button-maximize.bmp new file mode 100644 index 00000000..ef149485 Binary files /dev/null and b/base/usr/share/ttk/active/button-maximize.bmp differ diff --git a/base/usr/share/ttk/active/ll.bmp b/base/usr/share/ttk/active/ll.bmp new file mode 100644 index 00000000..054f155f Binary files /dev/null and b/base/usr/share/ttk/active/ll.bmp differ diff --git a/base/usr/share/ttk/active/lm.bmp b/base/usr/share/ttk/active/lm.bmp new file mode 100644 index 00000000..d7a2ea4b Binary files /dev/null and b/base/usr/share/ttk/active/lm.bmp differ diff --git a/base/usr/share/ttk/active/lr.bmp b/base/usr/share/ttk/active/lr.bmp new file mode 100644 index 00000000..7376bc3c Binary files /dev/null and b/base/usr/share/ttk/active/lr.bmp differ diff --git a/base/usr/share/ttk/active/ml.bmp b/base/usr/share/ttk/active/ml.bmp new file mode 100644 index 00000000..c8cab9a9 Binary files /dev/null and b/base/usr/share/ttk/active/ml.bmp differ diff --git a/base/usr/share/ttk/active/mr.bmp b/base/usr/share/ttk/active/mr.bmp new file mode 100644 index 00000000..a853e180 Binary files /dev/null and b/base/usr/share/ttk/active/mr.bmp differ diff --git a/base/usr/share/ttk/active/ul.bmp b/base/usr/share/ttk/active/ul.bmp new file mode 100644 index 00000000..dca7f524 Binary files /dev/null and b/base/usr/share/ttk/active/ul.bmp differ diff --git a/base/usr/share/ttk/active/um.bmp b/base/usr/share/ttk/active/um.bmp new file mode 100644 index 00000000..61e46a8b Binary files /dev/null and b/base/usr/share/ttk/active/um.bmp differ diff --git a/base/usr/share/ttk/active/ur.bmp b/base/usr/share/ttk/active/ur.bmp new file mode 100644 index 00000000..a46c941d Binary files /dev/null and b/base/usr/share/ttk/active/ur.bmp differ diff --git a/base/usr/share/ttk/inactive/button-close.bmp b/base/usr/share/ttk/inactive/button-close.bmp new file mode 100644 index 00000000..b406ab9a Binary files /dev/null and b/base/usr/share/ttk/inactive/button-close.bmp differ diff --git a/base/usr/share/ttk/inactive/button-maximize.bmp b/base/usr/share/ttk/inactive/button-maximize.bmp new file mode 100644 index 00000000..64595454 Binary files /dev/null and b/base/usr/share/ttk/inactive/button-maximize.bmp differ diff --git a/base/usr/share/ttk/inactive/ll.bmp b/base/usr/share/ttk/inactive/ll.bmp new file mode 100644 index 00000000..37d17bd2 Binary files /dev/null and b/base/usr/share/ttk/inactive/ll.bmp differ diff --git a/base/usr/share/ttk/inactive/lm.bmp b/base/usr/share/ttk/inactive/lm.bmp new file mode 100644 index 00000000..81dd77df Binary files /dev/null and b/base/usr/share/ttk/inactive/lm.bmp differ diff --git a/base/usr/share/ttk/inactive/lr.bmp b/base/usr/share/ttk/inactive/lr.bmp new file mode 100644 index 00000000..a8268191 Binary files /dev/null and b/base/usr/share/ttk/inactive/lr.bmp differ diff --git a/base/usr/share/ttk/inactive/ml.bmp b/base/usr/share/ttk/inactive/ml.bmp new file mode 100644 index 00000000..91556d31 Binary files /dev/null and b/base/usr/share/ttk/inactive/ml.bmp differ diff --git a/base/usr/share/ttk/inactive/mr.bmp b/base/usr/share/ttk/inactive/mr.bmp new file mode 100644 index 00000000..259e94b5 Binary files /dev/null and b/base/usr/share/ttk/inactive/mr.bmp differ diff --git a/base/usr/share/ttk/inactive/ul.bmp b/base/usr/share/ttk/inactive/ul.bmp new file mode 100644 index 00000000..56d05b20 Binary files /dev/null and b/base/usr/share/ttk/inactive/ul.bmp differ diff --git a/base/usr/share/ttk/inactive/um.bmp b/base/usr/share/ttk/inactive/um.bmp new file mode 100644 index 00000000..2cdb7424 Binary files /dev/null and b/base/usr/share/ttk/inactive/um.bmp differ diff --git a/base/usr/share/ttk/inactive/ur.bmp b/base/usr/share/ttk/inactive/ur.bmp new file mode 100644 index 00000000..08d8edd9 Binary files /dev/null and b/base/usr/share/ttk/inactive/ur.bmp differ diff --git a/base/usr/share/wallpaper.bmp b/base/usr/share/wallpaper.bmp new file mode 120000 index 00000000..7216627d --- /dev/null +++ b/base/usr/share/wallpaper.bmp @@ -0,0 +1 @@ +wallpapers/auckland.bmp \ No newline at end of file diff --git a/base/usr/share/wallpapers/auckland.bmp b/base/usr/share/wallpapers/auckland.bmp new file mode 100644 index 00000000..4d494bfc Binary files /dev/null and b/base/usr/share/wallpapers/auckland.bmp differ diff --git a/boot/README.md b/boot/README.md new file mode 100644 index 00000000..67677dee --- /dev/null +++ b/boot/README.md @@ -0,0 +1,14 @@ +# ToaruOS-NIH Bootloader + +This is a simple, limited BIOS and EFI bootloader for ToaruOS kernels. + +It provides an implementation of the Multiboot bootloader standard. + +The BIOS loader includes an ISO 9660 filesystem driver, and is suitable for use as an El Torito no-emulation boot image for use on a CD. + +The EFI loader is built as both a 64-bit and 32-bit EFI executable and uses the EFI interfaces for file system access, and as such is suitable for a wider variety of environments. + +Both loaders are based on the same codebase and implement the same menu system, which can be found `cstuff.c`. + +The EFI loader is built using GNU-EFI, but does not use any of its convenience library functions. + diff --git a/boot/ata.h b/boot/ata.h new file mode 100644 index 00000000..303dadc1 --- /dev/null +++ b/boot/ata.h @@ -0,0 +1,154 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * Values for ATA / PATA devices + */ + +#pragma once + +#define ATA_SR_BSY 0x80 +#define ATA_SR_DRDY 0x40 +#define ATA_SR_DF 0x20 +#define ATA_SR_DSC 0x10 +#define ATA_SR_DRQ 0x08 +#define ATA_SR_CORR 0x04 +#define ATA_SR_IDX 0x02 +#define ATA_SR_ERR 0x01 + +#define ATA_ER_BBK 0x80 +#define ATA_ER_UNC 0x40 +#define ATA_ER_MC 0x20 +#define ATA_ER_IDNF 0x10 +#define ATA_ER_MCR 0x08 +#define ATA_ER_ABRT 0x04 +#define ATA_ER_TK0NF 0x02 +#define ATA_ER_AMNF 0x01 + +#define ATA_CMD_READ_PIO 0x20 +#define ATA_CMD_READ_PIO_EXT 0x24 +#define ATA_CMD_READ_DMA 0xC8 +#define ATA_CMD_READ_DMA_EXT 0x25 +#define ATA_CMD_WRITE_PIO 0x30 +#define ATA_CMD_WRITE_PIO_EXT 0x34 +#define ATA_CMD_WRITE_DMA 0xCA +#define ATA_CMD_WRITE_DMA_EXT 0x35 +#define ATA_CMD_CACHE_FLUSH 0xE7 +#define ATA_CMD_CACHE_FLUSH_EXT 0xEA +#define ATA_CMD_PACKET 0xA0 +#define ATA_CMD_IDENTIFY_PACKET 0xA1 +#define ATA_CMD_IDENTIFY 0xEC + +#define ATAPI_CMD_READ 0xA8 +#define ATAPI_CMD_EJECT 0x1B + +#define ATA_IDENT_DEVICETYPE 0 +#define ATA_IDENT_CYLINDERS 2 +#define ATA_IDENT_HEADS 6 +#define ATA_IDENT_SECTORS 12 +#define ATA_IDENT_SERIAL 20 +#define ATA_IDENT_MODEL 54 +#define ATA_IDENT_CAPABILITIES 98 +#define ATA_IDENT_FIELDVALID 106 +#define ATA_IDENT_MAX_LBA 120 +#define ATA_IDENT_COMMANDSETS 164 +#define ATA_IDENT_MAX_LBA_EXT 200 + +#define IDE_ATA 0x00 +#define IDE_ATAPI 0x01 + +#define ATA_MASTER 0x00 +#define ATA_SLAVE 0x01 + +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 0x01 +#define ATA_REG_FEATURES 0x01 +#define ATA_REG_SECCOUNT0 0x02 +#define ATA_REG_LBA0 0x03 +#define ATA_REG_LBA1 0x04 +#define ATA_REG_LBA2 0x05 +#define ATA_REG_HDDEVSEL 0x06 +#define ATA_REG_COMMAND 0x07 +#define ATA_REG_STATUS 0x07 +#define ATA_REG_SECCOUNT1 0x08 +#define ATA_REG_LBA3 0x09 +#define ATA_REG_LBA4 0x0A +#define ATA_REG_LBA5 0x0B +#define ATA_REG_CONTROL 0x0C +#define ATA_REG_ALTSTATUS 0x0C +#define ATA_REG_DEVADDRESS 0x0D + +// Channels: +#define ATA_PRIMARY 0x00 +#define ATA_SECONDARY 0x01 + +// Directions: +#define ATA_READ 0x00 +#define ATA_WRITE 0x01 + +typedef struct { + uint16_t base; + uint16_t ctrl; + uint16_t bmide; + uint16_t nien; +} ide_channel_regs_t; + +typedef struct { + uint8_t reserved; + uint8_t channel; + uint8_t drive; + uint16_t type; + uint16_t signature; + uint16_t capabilities; + uint32_t command_sets; + uint32_t size; + uint8_t model[41]; +} ide_device_t; + +typedef struct { + uint8_t status; + uint8_t chs_first_sector[3]; + uint8_t type; + uint8_t chs_last_sector[3]; + uint32_t lba_first_sector; + uint32_t sector_count; +} partition_t; + +typedef struct { + uint16_t flags; + uint16_t unused1[9]; + char serial[20]; + uint16_t unused2[3]; + char firmware[8]; + char model[40]; + uint16_t sectors_per_int; + uint16_t unused3; + uint16_t capabilities[2]; + uint16_t unused4[2]; + uint16_t valid_ext_data; + uint16_t unused5[5]; + uint16_t size_of_rw_mult; + uint32_t sectors_28; + uint16_t unused6[38]; + uint64_t sectors_48; + uint16_t unused7[152]; +} __attribute__((packed)) ata_identify_t; + +typedef struct { + uint8_t boostrap[446]; + partition_t partitions[4]; + uint8_t signature[2]; +} __attribute__((packed)) mbr_t; + +struct ata_device { + int io_base; + int control; + int slave; + int is_atapi; + ata_identify_t identity; + unsigned int atapi_lba; + unsigned int atapi_sector_size; +}; + +typedef union { + uint8_t command_bytes[12]; + uint16_t command_words[6]; +} atapi_command_t; diff --git a/boot/atapi_imp.h b/boot/atapi_imp.h new file mode 100644 index 00000000..93cb6100 --- /dev/null +++ b/boot/atapi_imp.h @@ -0,0 +1,231 @@ +#pragma once + +static struct ata_device ata_primary_master = {.io_base = 0x1F0, .control = 0x3F6, .slave = 0}; +static struct ata_device ata_primary_slave = {.io_base = 0x1F0, .control = 0x3F6, .slave = 1}; +static struct ata_device ata_secondary_master = {.io_base = 0x170, .control = 0x376, .slave = 0}; +static struct ata_device ata_secondary_slave = {.io_base = 0x170, .control = 0x376, .slave = 1}; + +static void ata_io_wait(struct ata_device * dev) { + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); +} + +static int ata_status_wait(struct ata_device * dev, int timeout) { + int status; + if (timeout > 0) { + int i = 0; + while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY && (i < timeout)) i++; + } else { + while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY); + } + return status; +} + +static void ata_soft_reset(struct ata_device * dev) { + outportb(dev->control, 0x04); + ata_io_wait(dev); + outportb(dev->control, 0x00); +} + +static int ata_wait(struct ata_device * dev, int advanced) { + uint8_t status = 0; + + ata_io_wait(dev); + + status = ata_status_wait(dev, -1); + + if (advanced) { + status = inportb(dev->io_base + ATA_REG_STATUS); + if (status & ATA_SR_ERR) return 1; + if (status & ATA_SR_DF) return 1; + if (!(status & ATA_SR_DRQ)) return 1; + } + + return 0; +} + +static void atapi_device_init(struct ata_device * dev) { + + dev->is_atapi = 1; + + outportb(dev->io_base + 1, 1); + outportb(dev->control, 0); + + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + + outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET); + ata_io_wait(dev); + + ata_wait(dev, 0); + + uint16_t * buf = (uint16_t *)&dev->identity; + + for (int i = 0; i < 256; ++i) { + buf[i] = inports(dev->io_base); + } + + uint8_t * ptr = (uint8_t *)&dev->identity.model; + for (int i = 0; i < 39; i+=2) { + uint8_t tmp = ptr[i+1]; + ptr[i+1] = ptr[i]; + ptr[i] = tmp; + } + + /* Detect medium */ + atapi_command_t command; + memset(&command, 0, sizeof(command)); + command.command_bytes[0] = 0x25; + + uint16_t bus = dev->io_base; + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_LBA1, 0x08); + outportb(bus + ATA_REG_LBA2, 0x08); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_PACKET); + + /* poll */ + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; + } + + for (int i = 0; i < 6; ++i) { + outports(bus, command.command_words[i]); + } + + /* poll */ + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error_read; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; + if ((status & ATA_SR_DRQ)) break; + } + + uint16_t data[4]; + + for (int i = 0; i < 4; ++i) { + data[i] = inports(bus); + } + +#define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24)) + uint32_t lba, blocks;; + memcpy(&lba, &data[0], sizeof(uint32_t)); + lba = htonl(lba); + memcpy(&blocks, &data[2], sizeof(uint32_t)); + blocks = htonl(blocks); + + dev->atapi_lba = lba; + dev->atapi_sector_size = blocks; + + return; + +atapi_error_read: + return; + +atapi_error: + return; +} + +static int ata_device_detect(struct ata_device * dev) { + ata_soft_reset(dev); + ata_io_wait(dev); + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + ata_status_wait(dev, 10000); + + unsigned char cl = inportb(dev->io_base + ATA_REG_LBA1); /* CYL_LO */ + unsigned char ch = inportb(dev->io_base + ATA_REG_LBA2); /* CYL_HI */ + + if (cl == 0xFF && ch == 0xFF) { + /* Nothing here */ + return 0; + } + if ((cl == 0x00 && ch == 0x00) || + (cl == 0x3C && ch == 0xC3)) { + return 1; + } else if ((cl == 0x14 && ch == 0xEB) || + (cl == 0x69 && ch == 0x96)) { + atapi_device_init(dev); + return 2; + } + + return 0; +} + +static void ata_device_read_sectors_atapi(struct ata_device * dev, uint32_t lba, uint8_t * buf, int sectors) { + + if (!dev->is_atapi) return; + + + uint16_t bus = dev->io_base; + +_try_again: + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_LBA1, dev->atapi_sector_size & 0xFF); + outportb(bus + ATA_REG_LBA2, dev->atapi_sector_size >> 8); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_PACKET); + + /* poll */ + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; + } + + atapi_command_t command; + command.command_bytes[0] = 0x28; + command.command_bytes[1] = 0; + command.command_bytes[2] = (lba >> 0x18) & 0xFF; + command.command_bytes[3] = (lba >> 0x10) & 0xFF; + command.command_bytes[4] = (lba >> 0x08) & 0xFF; + command.command_bytes[5] = (lba >> 0x00) & 0xFF; + command.command_bytes[6] = sectors >> 16; + command.command_bytes[7] = sectors >> 8; + command.command_bytes[8] = sectors; /* bit 0 = PMI (0, last sector) */ + command.command_bytes[9] = 0; /* control */ + command.command_bytes[10] = 0; + command.command_bytes[11] = 0; + + for (int i = 0; i < 6; ++i) { + outports(bus, command.command_words[i]); + } + + uint16_t size_to_read = dev->atapi_sector_size; + + for (int i = 0; i < sectors; ++i) { + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup_cmd; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; + } + + inportsm(bus,buf,size_to_read/2); + + buf += size_to_read; + + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; + } + } + + return; + +atapi_error_on_read_setup: + print("error on setup\n"); + return; +atapi_error_on_read_setup_cmd: + print("error on cmd\n"); + return; +} + + +#define ata_device_read_sector_atapi(a,b,c) ata_device_read_sectors_atapi(a,b,c,1) diff --git a/boot/boot.s b/boot/boot.s new file mode 100644 index 00000000..0bb97a0b --- /dev/null +++ b/boot/boot.s @@ -0,0 +1,138 @@ +[bits 16] +main: + jmp far 0x000:0x7c05 +main2: + mov ax, 0x0000 + mov ds, ax + mov ss, ax + mov ax, 0x7b00 + mov sp, ax + mov ax, 0x0500 + mov es, ax + + clc + int 0x12 + mov [lower_mem], ax + + ; memory scan + mov di, 0x0 + call do_e820 + jc hang + + cli + + ; a20 + in al, 0x92 + or al, 2 + out 0x92, al + + ; basic flat GDT + xor eax, eax + mov ax, ds + shl eax, 4 + add eax, gdt_base + mov [gdtr+2], eax + mov eax, gdt_end + sub eax, gdt_base + mov [gdtr], ax + lgdt [gdtr] + + ; protected mode enable flag + mov eax, cr0 + or eax, 1 + mov cr0, eax + + ; set segments + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + ; jump to protected mode entry + extern kmain + jmp far 0x08:(kmain) + +hang: + jmp hang + +do_e820: + xor ebx, ebx ; ebx must be 0 to start + xor bp, bp ; keep an entry count in bp + mov edx, 0x0534D4150 ; Place "SMAP" into edx + mov eax, 0xe820 + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes + int 0x15 + jc short .failed ; carry set on first call means "unsupported function" + mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? + cmp eax, edx ; on success, eax must have been reset to "SMAP" + jne short .failed + test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) + je short .failed + jmp short .jmpin +.e820lp: + mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call + mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry + mov ecx, 24 ; ask for 24 bytes again + int 0x15 + jc short .e820f ; carry set means "end of list already reached" + mov edx, 0x0534D4150 ; repair potentially trashed register +.jmpin: + jcxz .skipent ; skip any 0 length entries + cmp cl, 20 ; got a 24 byte ACPI 3.X response? + jbe short .notext + test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? + je short .skipent +.notext: + mov ecx, [es:di + 8] ; get lower uint32_t of memory region length + or ecx, [es:di + 12] ; "or" it with upper uint32_t to test for zero + jz .skipent ; if length uint64_t is 0, skip entry + inc bp ; got a good entry: ++count, move to next storage spot + add di, 24 +.skipent: + test ebx, ebx ; if ebx resets to 0, list is complete + jne short .e820lp +.e820f: + mov [mmap_ent], bp ; store the entry count + clc ; there is "jc" on end of list to this point, so the carry must be cleared + ret +.failed: + stc ; "function unsupported" error exit + ret + +align 8 + +; GDT pointer +gdtr + dw 0 + dd 0 + +; GDT (null, code, data) +gdt_base + ; null + dq 0 + ; code + dw 0xFFFF + dw 0 + db 0 + db 0x9a + db 0xcf + db 0 + ; data + dw 0xffff + dw 0 + db 0 + db 0x92 + db 0xcf + db 0 +gdt_end + +; memory map entry count +global mmap_ent +mmap_ent db 0, 0 + +global lower_mem +lower_mem db 0, 0 + diff --git a/boot/cstuff.c b/boot/cstuff.c new file mode 100644 index 00000000..3acb8c70 --- /dev/null +++ b/boot/cstuff.c @@ -0,0 +1,293 @@ +#ifdef EFI_PLATFORM +# include +# include +EFI_HANDLE ImageHandleIn; +#else +# include "types.h" +#endif + +#include "ata.h" +#include "text.h" +#include "util.h" +#ifndef EFI_PLATFORM +#include "atapi_imp.h" +#include "iso9660.h" +#endif +#include "elf.h" +#include "multiboot.h" +#include "kbd.h" +#include "options.h" + +/* Basic text strings */ +#define BASE_VERSION "ToaruOS-NIH Bootloader v2.1" +#ifdef EFI_PLATFORM +# if defined(__x86_64__) +# define VERSION_TEXT BASE_VERSION " (EFI, X64)" +# else +# define VERSION_TEXT BASE_VERSION " (EFI, IA32)" +# endif +#else +# define VERSION_TEXT BASE_VERSION " (BIOS)" +#endif +#define HELP_TEXT "Press or select a menu option with \030/\031/\032/\033." +#define COPYRIGHT_TEXT "ToaruOS is free software under the NCSA license." +#define LINK_TEXT "https://toaruos.org - https://gitlab.com/toaruos" + +/* Boot command line strings */ +#define DEFAULT_ROOT_CMDLINE "root=/dev/ram0,nocache " +#define DEFAULT_GRAPHICAL_CMDLINE "start=live-session " +#define DEFAULT_SINGLE_CMDLINE "start=terminal\037-F " +#define DEFAULT_TEXT_CMDLINE "start=--vga " +#define DEFAULT_VID_CMDLINE "vid=auto,1440,900 " +#define DEFAULT_PRESET_VID_CMDLINE "vid=preset " +#define DEFAULT_NETINIT_CMDLINE "init=/dev/ram0 " +#define MIGRATE_CMDLINE "migrate " +#define DEBUG_LOG_CMDLINE "logtoserial=warning " +#define DEBUG_SERIAL_CMDLINE "kdebug " +#define DEFAULT_HEADLESS_CMDLINE "start=--headless " + +char * module_dir = "MOD"; +char * kernel_path = "KERNEL."; +char * ramdisk_path = "RAMDISK.IMG"; + +#ifdef EFI_PLATFORM +int _efi_do_mode_set = 0; +#endif + +/* Where to dump kernel data while loading */ +#define KERNEL_LOAD_START 0x300000 + +/* Module file names - need to be ordered. */ +static char * modules[] = { + "ZERO.KO", // 0 + "RANDOM.KO", // 1 + "SERIAL.KO", // 2 + "DEBUG_SH.KO", // 3 + "PROCFS.KO", // 4 + "TMPFS.KO", // 5 + "ATA.KO", // 6 + "EXT2.KO", // 7 + "ISO9660.KO", // 8 + "PS2KBD.KO", // 9 + "PS2MOUSE.KO", // 10 + "LFBVIDEO.KO", // 11 + "VBOX.KO", // 12 + "VMWARE.KO", // 13 + "VIDSET.KO", // 14 + "PACKETFS.KO", // 15 + "SND.KO", // 16 + "AC97.KO", // 17 + "NET.KO", // 18 + "PCNET.KO", // 19 + "RTL.KO", // 20 + "E1000.KO", // 21 + "PCSPKR.KO", // 22 + "PORTIO.KO", // 23 + 0 +}; + +/* Names of the available boot modes. */ +static struct bootmode boot_mode_names[] = { + {1, "normal", "Normal Boot"}, +#ifndef EFI_PLATFORM + {2, "vga", "VGA Text Mode"}, +#endif + {3, "single", "Single-User Graphical Terminal"}, + {4, "headless", "Headless"}, +}; + +/* More bootloader implementation that depends on the module config */ +#include "moremultiboot.h" + +#ifdef EFI_PLATFORM +EFI_STATUS + EFIAPI +efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +{ + InitializeLib(ImageHandle, SystemTable); + ST = SystemTable; + ImageHandleIn = ImageHandle; +#else +int kmain() { +#endif + + BOOT_OPTION(_debug, 0, "Debug output", + "Enable debug output in the bootloader and enable the", + "serial debug log in the operating system itself."); + + BOOT_OPTION(_legacy_ata, 0, "Legacy ATA driver", + "Enable the legacy ATA driver, which does not support", + "ATAPI or use DMA. May be necessary in some virtual machines."); + + BOOT_OPTION(_normal_ata, 1, "DMA ATA driver", + "Enable the normal, DMA-capable ATA driver. This is the default.", + NULL); + + BOOT_OPTION(_debug_shell, 1, "Debug shell", + "Enable the kernel debug shell. This can be accessed using", + "the `kdebug` application."); + + BOOT_OPTION(_video, 1, "Video modules", + "Enable the video modules. These are needed to modeset", + "and provide a framebuffer for the UI."); + + BOOT_OPTION(_vbox, 1, "VirtualBox Guest Additions", + "Enable integration with VirtualBox, including", + "automatic mode setting and absolute mouse pointer."); + + BOOT_OPTION(_vboxrects, 0, "VirtualBox Seamless support", + "(Requires Guest Additions) Enables support for the", + "Seamless Desktop mode in VirtualBox."); + + BOOT_OPTION(_vboxpointer, 1, "VirtualBox Pointer", + "(Requires Guest Additions) Enables support for the", + "VirtualBox hardware pointer mapping."); + + BOOT_OPTION(_vmware, 1, "VMWare driver", + "Enable the VMware / QEMU absolute mouse pointer,", + "and optional guest scaling."); + + BOOT_OPTION(_vmwareres, 1, "VMware guest size", + "(Requires VMware driver) Enables support for", + "automatically setting display size in VMware"); + + BOOT_OPTION(_sound, 1, "Audio drivers", + "Enable the audio subsystem and AC'97 drivers.", + NULL); + + BOOT_OPTION(_net, 1, "Network drivers", + "Enable the IPv4 network subsystem and various", + "network interface drivers."); + + BOOT_OPTION(_migrate, 1, "Writable root", + "Migrates the ramdisk from ext2 to an in-memory", + "temporary filesystem at boot."); + + BOOT_OPTION(_serialshell, 0, "Debug on serial", + "Start a kernel debug shell on the first", + "serial port."); + + BOOT_OPTION(_netinit, 0, "Netinit", + "Downloads a userspace filesystem from a remote", + "server and extracts it at boot."); + +#ifdef EFI_PLATFORM + BOOT_OPTION(_efilargest, 0, "Prefer largest mode.", + "When using EFI mode setting, use the largest mode.", + NULL); + + BOOT_OPTION(_efi1024, 0, "Prefer 1024x768", + "If a 1024x768x32 mode is found, set that.", + NULL); + + BOOT_OPTION(_efi1080p, 0, "Prefer 1080p", + "If a 1920x1080 mode is found, set that.", + NULL); + + BOOT_OPTION(_efiask, 0, "Ask for input on each mode.", + "Displays a y/n prompt for each possible mode.", + NULL); +#endif + + /* Loop over rendering the menu */ + show_menu(); + + /* Build our command line. */ + if (_netinit) { + strcat(cmdline, DEFAULT_NETINIT_CMDLINE); + ramdisk_path = "NETINIT."; + } else { + strcat(cmdline, DEFAULT_ROOT_CMDLINE); + + if (_migrate) { + strcat(cmdline, MIGRATE_CMDLINE); + } + } + + char * _video_command_line = DEFAULT_VID_CMDLINE; +#ifdef EFI_PLATFORM + _efi_do_mode_set = (_efilargest ? 1 : (_efi1024 ? 2 : (_efi1080p ? 3 : (_efiask ? 4 : 0)))); + if (_efi_do_mode_set) { + _video_command_line = DEFAULT_PRESET_VID_CMDLINE; + } +#endif + + if (boot_mode == 1) { + strcat(cmdline, DEFAULT_GRAPHICAL_CMDLINE); + strcat(cmdline, _video_command_line); + } else if (boot_mode == 2) { + strcat(cmdline, DEFAULT_TEXT_CMDLINE); + } else if (boot_mode == 3) { + strcat(cmdline, DEFAULT_SINGLE_CMDLINE); + strcat(cmdline, _video_command_line); + } else if (boot_mode == 4) { + strcat(cmdline, DEFAULT_HEADLESS_CMDLINE); + } + + if (_debug) { + strcat(cmdline, DEBUG_LOG_CMDLINE); + txt_debug = 1; + } + + if (_serialshell) { + strcat(cmdline, DEBUG_SERIAL_CMDLINE); + } + + if (_vbox && !_vboxrects) { + strcat(cmdline, "novboxseamless "); + } + + if (_vbox && !_vboxpointer) { + strcat(cmdline, "novboxpointer "); + } + + if (_vmware && !_vmwareres) { + strcat(cmdline, "novmwareresset "); + } + + /* Configure modules */ + if (!_normal_ata) { + modules[6] = "NONE"; + } + + if (_legacy_ata) { + modules[6] = "ATAOLD.KO"; + } + + if (!_debug_shell) { + modules[3] = "NONE"; + modules[14] = "NONE"; + } + + if (!_video) { + modules[11] = "NONE"; + modules[12] = "NONE"; + modules[13] = "NONE"; + modules[14] = "NONE"; + } + + if (!_vmware) { + modules[13] = "NONE"; + } + + if (!_vbox) { + modules[12] = "NONE"; + } + + if (!_sound) { + modules[16] = "NONE"; + modules[17] = "NONE"; + } + + if (!_net) { + modules[18] = "NONE"; + modules[19] = "NONE"; + modules[20] = "NONE"; + modules[21] = "NONE"; + } + + boot(); + + while (1) {} + return 0; +} diff --git a/boot/elf.h b/boot/elf.h new file mode 100644 index 00000000..6deb9987 --- /dev/null +++ b/boot/elf.h @@ -0,0 +1,157 @@ +#pragma once +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define EI_NIDENT 16 + +typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint32_t Elf32_Sword; +typedef uint16_t Elf32_Half; + +/* + * ELF Header + */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Header; + +/* + * e_type + */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_LOPROC 0xff0 /* [Processor Specific] */ +#define ET_HIPROC 0xfff /* [Processor Specific] */ + +/* + * Machine types + */ +#define EM_NONE 0 +#define EM_386 3 + +#define EV_NONE 0 +#define EV_CURRENT 1 + +/** Program Header */ +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +/* p_type values */ +#define PT_NULL 0 /* Unused, skip me */ +#define PT_LOAD 1 /* Loadable segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Interpreter (null-terminated string, pathname) */ +#define PT_NOTE 4 /* Auxillary information */ +#define PT_SHLIB 5 /* Reserved. */ +#define PT_PHDR 6 /* Oh, it's me. Hello! Back-reference to the header table itself */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + + +/** Section Header */ +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + uint32_t id; + uintptr_t ptr; +} Elf32_auxv; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + Elf32_Off d_off; + } d_un; +} Elf32_Dyn; + +/* sh_type values */ +#define SHT_NONE 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_NOBITS 8 +#define SHT_REL 9 + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xf) +#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_NUM 3 + +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_NUM 7 + +#define STT_LOPROC 13 +#define STT_HIPROC 15 + + diff --git a/boot/iso9660.h b/boot/iso9660.h new file mode 100644 index 00000000..153f24af --- /dev/null +++ b/boot/iso9660.h @@ -0,0 +1,187 @@ +#pragma once + +typedef struct { + char year[4]; + char month[2]; + char day[2]; + char hour[2]; + char minute[2]; + char second[2]; + char hundredths[2]; + int8_t timezone; +} __attribute__((packed)) iso_9660_datetime_t; + +typedef struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + int8_t timezone; +} __attribute__((packed)) iso_9660_rec_date_t; + +typedef struct { + uint8_t length; + uint8_t ext_length; + + uint32_t extent_start_LSB; + uint32_t extent_start_MSB; + + uint32_t extent_length_LSB; + uint32_t extent_length_MSB; + + iso_9660_rec_date_t record_date; + + uint8_t flags; + uint8_t interleave_units; + uint8_t interleave_gap; + + uint16_t volume_seq_LSB; + uint16_t volume_seq_MSB; + + uint8_t name_len; + char name[]; +} __attribute__((packed)) iso_9660_directory_entry_t; + +typedef struct { + uint8_t type; /* 0x01 */ + char id[5]; /* CD001 */ + + uint8_t version; + uint8_t _unused0; + + char system_id[32]; + char volume_id[32]; + + uint8_t _unused1[8]; + + uint32_t volume_space_LSB; + uint32_t volume_space_MSB; + + uint8_t _unused2[32]; + + uint16_t volume_set_LSB; + uint16_t volume_set_MSB; + + uint16_t volume_seq_LSB; + uint16_t volume_seq_MSB; + + uint16_t logical_block_size_LSB; + uint16_t logical_block_size_MSB; + + uint32_t path_table_size_LSB; + uint32_t path_table_size_MSB; + + uint32_t path_table_LSB; + uint32_t optional_path_table_LSB; + + uint32_t path_table_MSB; + uint32_t optional_path_table_MSB; + + /* iso_9660_directory_entry_t */ + char root[34]; + + char volume_set_id[128]; + char volume_publisher[128]; + char data_preparer[128]; + char application_id[128]; + + char copyright_file[38]; + char abstract_file[36]; + char bibliographic_file[37]; + + iso_9660_datetime_t creation; + iso_9660_datetime_t modification; + iso_9660_datetime_t expiration; + iso_9660_datetime_t effective; + + uint8_t file_structure_version; + uint8_t _unused_3; + + char application_use[]; +} __attribute__((packed)) iso_9660_volume_descriptor_t; + +#define ISO_SECTOR_SIZE 2048 + +#define FLAG_HIDDEN 0x01 +#define FLAG_DIRECTORY 0x02 +#define FLAG_ASSOCIATED 0x04 +#define FLAG_EXTENDED 0x08 +#define FLAG_PERMISSIONS 0x10 +#define FLAG_CONTINUES 0x80 + +static int root_sector = 0; +static iso_9660_volume_descriptor_t * root = (iso_9660_volume_descriptor_t *)((uint8_t *)0x20000); +static iso_9660_directory_entry_t * dir_entry = (iso_9660_directory_entry_t *)((uint8_t *)0x20800); +static uint8_t * mod_dir = (uint8_t *)0x21000; +static uint8_t * dir_entries = (uint8_t *)(0x30000); +static struct ata_device * device = 0; + +static int navigate(char * name) { + memset(dir_entries, 2048, 0xA5); + //print("reading from sector "); + //print_hex(dir_entry->extent_start_LSB); + //print("\n"); + ata_device_read_sector_atapi(device, dir_entry->extent_start_LSB, dir_entries); + ata_device_read_sector_atapi(device, dir_entry->extent_start_LSB+1, dir_entries + 2048); + ata_device_read_sector_atapi(device, dir_entry->extent_start_LSB+2, dir_entries + 4096); + + long offset = 0; + while (1) { + iso_9660_directory_entry_t * dir = (iso_9660_directory_entry_t *)(dir_entries + offset); + if (dir->length == 0) { + if (offset < dir_entry->extent_length_LSB) { + offset += 1; // this->block_size - ((uintptr_t)offset % this->block_size); + goto try_again; + } + break; + } + if (!(dir->flags & FLAG_HIDDEN)) { + char file_name[dir->name_len + 1]; + memcpy(file_name, dir->name, dir->name_len); + file_name[dir->name_len] = 0; + char * s = strchr(file_name,';'); + if (s) { + *s = '\0'; + } +#if 0 + print("Found a file: "); + print(" Name: "); + print(file_name); print("\n"); +#endif + if (!strcmp(file_name, name)) { + memcpy(dir_entry, dir, sizeof(iso_9660_directory_entry_t)); + return 1; + } + } + offset += dir->length; +try_again: + if ((long)(offset) > dir_entry->extent_length_LSB) break; + } + + return 0; +} + +static void restore_root(void) { + memcpy(dir_entry, (iso_9660_directory_entry_t *)&root->root, sizeof(iso_9660_directory_entry_t)); + +#if 0 + print("Root restored."); + print("\n Entry len: "); print_hex( dir_entry->length); + print("\n File start: "); print_hex( dir_entry->extent_start_LSB); + print("\n File len: "); print_hex( dir_entry->extent_length_LSB); + print("\n"); +#endif +} + +static void restore_mod(void) { + memcpy(dir_entry, (iso_9660_directory_entry_t *)mod_dir, sizeof(iso_9660_directory_entry_t)); +#if 0 + print("mod restored."); + print("\n Entry len: "); print_hex( dir_entry->length); + print("\n File start: "); print_hex( dir_entry->extent_start_LSB); + print("\n File len: "); print_hex( dir_entry->extent_length_LSB); + print("\n"); +#endif +} diff --git a/boot/kbd.h b/boot/kbd.h new file mode 100644 index 00000000..3ce28e44 --- /dev/null +++ b/boot/kbd.h @@ -0,0 +1,58 @@ +#pragma once + +#define KBD_SCAN_DOWN 0x50 +#define KBD_SCAN_UP 0x48 +#define KBD_SCAN_LEFT 0x4B +#define KBD_SCAN_RIGHT 0x4D +#define KBD_SCAN_ENTER 0x1C +#define KBD_SCAN_1 2 +#define KBD_SCAN_9 10 + +#ifdef EFI_PLATFORM + +static int read_scancode(void) { + EFI_INPUT_KEY Key; + unsigned long int index; + uefi_call_wrapper(ST->BootServices->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index); + uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &Key); + switch (Key.ScanCode) { + case 0: + switch (Key.UnicodeChar) { + case L'\r': + return KBD_SCAN_ENTER; + case L'1': + case L'2': + case L'3': + case L'4': + case L'5': + case L'6': + case L'7': + case L'8': + case L'9': + return Key.UnicodeChar - L'1' + KBD_SCAN_1; + case L'y': + return 'y'; + case L'n': + return 'n'; + default: + return 0xFF; + } + break; + case 0x01: return KBD_SCAN_UP; + case 0x02: return KBD_SCAN_DOWN; + case 0x03: return KBD_SCAN_RIGHT; + case 0x04: return KBD_SCAN_LEFT; + default: + return 0xFF; + } +} +#else +static int read_scancode(void) { + while (!(inportb(0x64) & 1)); + int out; + while (inportb(0x64) & 1) { + out = inportb(0x60); + } + return out; +} +#endif diff --git a/boot/link.ld b/boot/link.ld new file mode 100644 index 00000000..e81cf3c9 --- /dev/null +++ b/boot/link.ld @@ -0,0 +1,45 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * Kernel linker script for x86 + */ +OUTPUT_FORMAT("binary") +/*ENTRY(start) */ +phys = 0x7c00; + +SECTIONS +{ + . = 0x7c00; + + .text : + { + code = .; + *(.text) + } + + .rodata BLOCK(1) : ALIGN(1) + { + *(.rodata) + } + + .data BLOCK(1) : ALIGN(1) + { + data = .; + *(.data) + } + + .bss BLOCK(1) : ALIGN(1) + { + bss = .; + *(COMMON) + *(.bss) + *(.stack) + } + + end = .; + + /DISCARD/ : + { + *(.comment) + *(.eh_frame) + *(.note.gnu.build-id) + } +} diff --git a/boot/moremultiboot.h b/boot/moremultiboot.h new file mode 100644 index 00000000..3b4b00df --- /dev/null +++ b/boot/moremultiboot.h @@ -0,0 +1,912 @@ + +static mboot_mod_t modules_mboot[sizeof(modules)/sizeof(*modules)] = { + {0,0,0,1} +}; + +static struct multiboot multiboot_header = { + /* flags; */ MULTIBOOT_FLAG_CMDLINE | MULTIBOOT_FLAG_MODS | MULTIBOOT_FLAG_MEM | MULTIBOOT_FLAG_MMAP | MULTIBOOT_FLAG_LOADER, + /* mem_lower; */ 0x100000, + /* mem_upper; */ 0x640000, + /* boot_device; */ 0, + /* cmdline; */ 0, + /* mods_count; */ sizeof(modules)/sizeof(*modules), + /* mods_addr; */ 0, + /* num; */ 0, + /* size; */ 0, + /* addr; */ 0, + /* shndx; */ 0, + /* mmap_length; */ 0, + /* mmap_addr; */ 0, + /* drives_length; */ 0, + /* drives_addr; */ 0, + /* config_table; */ 0, + /* boot_loader_name; */ 0, + /* apm_table; */ 0, + /* vbe_control_info; */ 0, + /* vbe_mode_info; */ 0, + /* vbe_mode; */ 0, + /* vbe_interface_seg; */ 0, + /* vbe_interface_off; */ 0, + /* vbe_interface_len; */ 0, +}; + +static long ramdisk_off = 1; +static long ramdisk_len = 1; + +int _eax = 1; +int _ebx = 1; +int _xmain = 1; + +struct mmap_entry { + uint64_t base; + uint64_t len; + uint32_t type; + uint32_t reserved; +}; + +extern unsigned short mmap_ent; +extern unsigned short lower_mem; + +char * final_offset = NULL; + +extern char do_the_nasty[]; + +static int strlen(char * s) { + int out = 0; + while (*s) { + s++; + out++; + } + return out; +} + +#ifdef EFI_PLATFORM +static EFI_GUID efi_graphics_output_protocol_guid = + {0x9042a9de,0x23dc,0x4a38, {0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a}}; +#endif + +static void move_kernel(void) { + clear(); + print("Relocating kernel...\n"); + + Elf32_Header * header = (Elf32_Header *)KERNEL_LOAD_START; + + if (header->e_ident[0] != ELFMAG0 || + header->e_ident[1] != ELFMAG1 || + header->e_ident[2] != ELFMAG2 || + header->e_ident[3] != ELFMAG3) { + print("Kernel is invalid?\n"); + } + + uintptr_t entry = (uintptr_t)header->e_entry; + + for (uintptr_t x = 0; x < (uint32_t)header->e_phentsize * header->e_phnum; x += header->e_phentsize) { + Elf32_Phdr * phdr = (Elf32_Phdr *)((uint8_t*)KERNEL_LOAD_START + header->e_phoff + x); + if (phdr->p_type == PT_LOAD) { + //read_fs(file, phdr->p_offset, phdr->p_filesz, (uint8_t *)phdr->p_vaddr); + print("Loading a Phdr... "); + print_hex(phdr->p_vaddr); + print(" "); + print_hex(phdr->p_offset); + print(" "); + print_hex(phdr->p_filesz); + print("\n"); +#ifdef EFI_PLATFORM + EFI_PHYSICAL_ADDRESS addr = phdr->p_vaddr; + uefi_call_wrapper(ST->BootServices->AllocatePages, 3, AllocateAddress, 0x80000000, phdr->p_memsz / 4096 + 1, &addr); +#endif + memcpy((uint8_t*)(uintptr_t)phdr->p_vaddr, (uint8_t*)KERNEL_LOAD_START + phdr->p_offset, phdr->p_filesz); + long r = phdr->p_filesz; + while (r < phdr->p_memsz) { + *(char *)(phdr->p_vaddr + r) = 0; + r++; + } + } + } + + print("Setting up memory map...\n"); +#ifdef EFI_PLATFORM + mboot_memmap_t * mmap = (void*)KERNEL_LOAD_START; + memset((void*)KERNEL_LOAD_START, 0x00, 1024); + multiboot_header.mmap_addr = (uintptr_t)mmap; + + EFI_STATUS e; + UINTN mapSize = 0, mapKey, descriptorSize; + UINT32 descriptorVersion; + e = uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &mapSize, NULL, &mapKey, &descriptorSize, NULL); + + print_("Memory map size is "); print_hex_(mapSize); print_("\n"); + + EFI_MEMORY_DESCRIPTOR * efi_memory = (void*)(final_offset); + final_offset += mapSize; + while ((uintptr_t)final_offset & 0x3ff) final_offset++; + + e = uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &mapSize, efi_memory, &mapKey, &descriptorSize, NULL); + + if (EFI_ERROR(e)) { + print_("EFI error.\n"); + } + + uint64_t upper_mem = 0; + int descriptors = mapSize / descriptorSize; + for (int i = 0; i < descriptors; ++i) { + EFI_MEMORY_DESCRIPTOR * d = efi_memory; + + mmap->size = sizeof(uint64_t) * 2 + sizeof(uintptr_t); + mmap->base_addr = d->PhysicalStart; + mmap->length = d->NumberOfPages * 4096; + switch (d->Type) { + case EfiConventionalMemory: + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + case EfiACPIReclaimMemory: + mmap->type = 1; + break; + case EfiReservedMemoryType: + case EfiUnusableMemory: + case EfiMemoryMappedIO: + case EfiMemoryMappedIOPortSpace: + case EfiPalCode: + case EfiACPIMemoryNVS: + default: + mmap->type = 2; + break; + } + if (mmap->type == 1 && mmap->base_addr >= 0x100000) { + upper_mem += mmap->length; + } + mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uintptr_t)); + efi_memory = (EFI_MEMORY_DESCRIPTOR *)((char *)efi_memory + descriptorSize); + } + + multiboot_header.mem_lower = 1024; + multiboot_header.mem_upper = upper_mem / 1024; + + /* Set up framebuffer */ + if (_efi_do_mode_set) { + UINTN count; + EFI_HANDLE * handles; + EFI_GRAPHICS_OUTPUT_PROTOCOL * gfx; + EFI_STATUS status; + + status = uefi_call_wrapper(ST->BootServices->LocateHandleBuffer, + 5, ByProtocol, &efi_graphics_output_protocol_guid, NULL, &count, &handles); + if (EFI_ERROR(status)) { + print_("Error getting graphics device handle.\n"); + while (1) {}; + } + + status = uefi_call_wrapper(ST->BootServices->HandleProtocol, + 3, handles[0], &efi_graphics_output_protocol_guid, (void **)&gfx); + if (EFI_ERROR(status)) { + print_("Error getting graphics device.\n"); + while (1) {}; + } + +#if 0 + print_("Attempting to set a sane mode (32bit color, etc.)\n"); + print_("There are 0x"); print_hex_(gfx->Mode->MaxMode); print_(" modes available.\n"); + print_("This is mode 0x"); print_hex_(gfx->Mode->Mode); print_(".\n"); +#endif + + int biggest = gfx->Mode->Mode; + int big_width = 0; + int big_height = 0; + + clear_(); + + for (int i = 0; i < gfx->Mode->MaxMode; ++i) { + EFI_STATUS status; + UINTN size; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * info; + + status = uefi_call_wrapper(gfx->QueryMode, + 4, gfx, i, &size, &info); + + if (EFI_ERROR(status)) { + print_("Error getting gfx mode 0x"); print_hex_(i); print_("\n"); + } else { + print_("Mode "); print_int_(i); print_(" "); print_int_(info->HorizontalResolution); + print_("x"); print_int_(info->VerticalResolution); print_(" "); + print_int_(info->PixelFormat); print_("\n"); + if (_efi_do_mode_set == 1) { + if (info->PixelFormat == 1 && info->HorizontalResolution >= big_width) { + biggest = i; + big_width = info->HorizontalResolution; + } + } else if (_efi_do_mode_set == 2) { + if (info->PixelFormat == 1 && info->HorizontalResolution == 1024 && + info->VerticalResolution == 768) { + biggest = i; + break; + } + } else if (_efi_do_mode_set == 3) { + if (info->PixelFormat == 1 && info->HorizontalResolution == 1920 && + info->VerticalResolution == 1080) { + biggest = i; + break; + } + } else if (_efi_do_mode_set == 4) { + while (1) { + print_("y/n? "); + int resp = read_scancode(); + if (resp == 'y') { + print_("y\n"); + biggest = i; + goto done_video; + } else if (resp == 'n') { + print_("n\n"); + break; + } + print_("?\n"); + } + } + } + } + +done_video: + print_("Selected video mode was "); print_int_(biggest); print_("\n"); + uefi_call_wrapper(gfx->SetMode, 2, gfx, biggest); + + uint32_t high = gfx->Mode->FrameBufferBase >> 32; + uint32_t low = gfx->Mode->FrameBufferBase & 0xFFFFFFFF; + + print_("Framebuffer address is 0x"); print_hex_(high); print_hex_(low); print_("\n"); + + if (high) { + clear_(); + print_("Framebuffer is outside of 32-bit memory range.\n"); + print_("EFI mode setting is not available - and graphics may not work in general.\n"); + while (1) {}; + } + + multiboot_header.flags |= (1 << 12); /* Enable framebuffer flag */ + multiboot_header.framebuffer_addr = low; + multiboot_header.framebuffer_width = gfx->Mode->Info->HorizontalResolution; + multiboot_header.framebuffer_height = gfx->Mode->Info->VerticalResolution; + multiboot_header.framebuffer_pitch = gfx->Mode->Info->PixelsPerScanLine * 4; + + print_("Mode information passed to multiboot:\n"); + print_(" Address: 0x"); print_hex_(multiboot_header.framebuffer_addr); print_("\n"); + print_(" Width: "); print_int_(multiboot_header.framebuffer_width); print_("\n"); + print_(" Height: "); print_int_(multiboot_header.framebuffer_height); print_("\n"); + print_("\n"); + + } + + memcpy(final_offset, cmdline, strlen(cmdline)+1); + multiboot_header.cmdline = (uintptr_t)final_offset; + final_offset += strlen(cmdline)+1; + memcpy(final_offset, VERSION_TEXT, strlen(VERSION_TEXT)+1); + multiboot_header.boot_loader_name = (uintptr_t)final_offset; + final_offset += strlen(VERSION_TEXT)+1; + while ((uintptr_t)final_offset & 0x3ff) final_offset++; + + multiboot_header.mods_addr = (uintptr_t)final_offset; + memcpy(final_offset, &modules_mboot, sizeof(modules_mboot)); + final_offset += sizeof(modules_mboot); + while ((uintptr_t)final_offset & 0x3ff) final_offset++; + + memcpy(final_offset, &multiboot_header, sizeof(multiboot_header)); + _ebx = (uintptr_t)final_offset; + + + print("Jumping to main, good luck.\n"); +#else + print_hex(mmap_ent); + print("\n"); + memset((void*)KERNEL_LOAD_START, 0x00, 1024); + mboot_memmap_t * mmap = (void*)KERNEL_LOAD_START; + multiboot_header.mmap_addr = (uintptr_t)mmap; + multiboot_header.mods_addr = (uintptr_t)&modules_mboot; + multiboot_header.boot_loader_name = (uintptr_t)VERSION_TEXT; + + struct mmap_entry * e820 = (void*)0x5000; + + uint64_t upper_mem = 0; + for (int i = 0; i < mmap_ent; ++i) { + print("entry "); print_hex(i); print("\n"); + print("base: "); print_hex((uint32_t)e820[i].base); print("\n"); + print("type: "); print_hex(e820[i].type); print("\n"); + + mmap->size = sizeof(uint64_t) * 2 + sizeof(uintptr_t); + mmap->base_addr = e820[i].base; + mmap->length = e820[i].len; + mmap->type = e820[i].type; + if (mmap->type == 1 && mmap->base_addr >= 0x100000) { + upper_mem += mmap->length; + } + mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uintptr_t)); + } + + print("lower "); print_hex(lower_mem); print("KB\n"); + multiboot_header.mem_lower = 1024; + print("upper "); + print_hex(upper_mem >> 32); + print_hex(upper_mem); + print("\n"); + + multiboot_header.mem_upper = upper_mem / 1024; + + _ebx = (unsigned int)&multiboot_header; +#endif + + _eax = MULTIBOOT_EAX_MAGIC; + _xmain = entry; + +#ifdef EFI_PLATFORM + print_("\nExiting boot services and jumping to "); + print_hex_(_xmain); + print_(" with mboot_mag="); + print_hex_(_eax); + print_(" and mboot_ptr="); + print_hex_(_ebx); + print_("...\n"); + +#if defined(__x86_64__) + print_("&_xmain = "); print_hex_(((uintptr_t)&_xmain) >> 32); print_hex_((uint32_t)(uintptr_t)&_xmain); print_("\n"); +#endif + + if (1) { + EFI_STATUS e; + UINTN mapSize = 0, mapKey, descriptorSize; + UINT32 descriptorVersion; + uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &mapSize, NULL, &mapKey, &descriptorSize, NULL); + e = uefi_call_wrapper(ST->BootServices->ExitBootServices, 2, ImageHandleIn, mapKey); + + if (e != EFI_SUCCESS) { + print_("Exit services failed. \n"); + print_hex_(e); + } + } +#endif + +#if defined(__x86_64__) + uint64_t foobar = ((uint32_t)(uintptr_t)&do_the_nasty) | (0x10L << 32L); + + uint32_t * foo = (uint32_t *)0x7c00; + + foo[0] = _eax; + foo[1] = _ebx; + foo[2] = _xmain; + + __asm__ __volatile__ ( + "push %0\n" + "retf\n" + : : "g"(foobar)); +#else + __asm__ __volatile__ ( + "mov %1,%%eax \n" + "mov %2,%%ebx \n" + "jmp *%0" : : "g"(_xmain), "g"(_eax), "g"(_ebx) : "eax", "ebx" + ); +#endif +} + +#if defined(__x86_64__) + __asm__ ( + "do_the_nasty:\n" + "cli\n" + //"mov 0x08, %ax\n" + //"mov %ax, %ds\n" + //"mov %ax, %es\n" + //"mov %ax, %fs\n" + //"mov %ax, %gs\n" + //"mov %ax, %ss\n" + ".code32\n" + "mov %cr0, %eax\n" + "and $0x7FFeFFFF, %eax\n" + "mov %eax, %cr0\n" + // Paging is disabled + "mov $0xc0000080, %ecx\n" + "rdmsr\n" + "and $0xfffffeff, %eax\n" + "wrmsr\n" + "mov $0x640, %eax\n" + "mov %eax, %cr4\n" + "mov 0x7c00, %eax\n" + "mov 0x7c04, %ebx\n" + "mov 0x7c08, %ecx\n" + "jmp *%ecx\n" + "target: jmp target\n" + ".code64\n" + ); +#endif + +#ifndef EFI_PLATFORM +static void do_it(struct ata_device * _device) { + device = _device; + if (device->atapi_sector_size != 2048) { + print_hex(device->atapi_sector_size); + print("\n - bad sector size\n"); + return; + } + for (int i = 0x10; i < 0x15; ++i) { + ata_device_read_sector_atapi(device, i, (uint8_t *)root); + switch (root->type) { + case 1: + root_sector = i; + goto done; + case 0xFF: + return; + } + } + return; +done: + restore_root(); + + if (navigate(kernel_path)) { + print("Found kernel.\n"); + print_hex(dir_entry->extent_start_LSB); print(" "); + print_hex(dir_entry->extent_length_LSB); print("\n"); + long offset = 0; + for (int i = dir_entry->extent_start_LSB; i < dir_entry->extent_start_LSB + dir_entry->extent_length_LSB / 2048 + 1; ++i, offset += 2048) { + + ata_device_read_sector_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset); + } + while (offset % 4096) offset++; + restore_root(); + if (navigate(module_dir)) { + memcpy(mod_dir, dir_entry, sizeof(iso_9660_directory_entry_t)); + print("Scanning modules...\n"); + char ** c = modules; + int j = 0; + while (*c) { + print("load "); print(*c); print("\n"); + if (!navigate(*c)) { + print("Failed to locate module! ["); + print(*c); + multiboot_header.mods_count--; + print("]\n"); + } else { + modules_mboot[j].mod_start = KERNEL_LOAD_START + offset; + modules_mboot[j].mod_end = KERNEL_LOAD_START + offset + dir_entry->extent_length_LSB; + for (int i = dir_entry->extent_start_LSB; i < dir_entry->extent_start_LSB + dir_entry->extent_length_LSB / 2048 + 1; ++i, offset += 2048) { + ata_device_read_sector_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset); + } + while (offset % 4096) offset++; + j++; + } + c++; + restore_mod(); + } + print("Done.\n"); + restore_root(); + if (navigate(ramdisk_path)) { + //clear_(); + ramdisk_off = KERNEL_LOAD_START + offset; + ramdisk_len = dir_entry->extent_length_LSB; + modules_mboot[multiboot_header.mods_count-1].mod_start = ramdisk_off; + modules_mboot[multiboot_header.mods_count-1].mod_end = ramdisk_off + ramdisk_len; + + print_("Loading ramdisk"); + + int i = dir_entry->extent_start_LSB; + int sectors = dir_entry->extent_length_LSB / 2048 + 1; +#define SECTORS 512 + while (sectors >= SECTORS) { + print_("."); + ata_device_read_sectors_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset, SECTORS); + + sectors -= SECTORS; + offset += 2048 * SECTORS; + i += SECTORS; + } + if (sectors > 0) { + print_("!"); + ata_device_read_sectors_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset, sectors); + offset += 2048 * sectors; + } + + final_offset = (uint8_t *)KERNEL_LOAD_START + offset; + set_attr(0x07); + print("Done.\n"); + move_kernel(); + } + } else { + print("No mod directory?\n"); + } + } else { + print("boo\n"); + } + + return; +} +#endif + +struct fw_cfg_file { + uint32_t size; + uint16_t select; + uint16_t reserved; + char name[56]; +}; + +static int boot_mode = 0; + +void swap_bytes(void * in, int count) { + char * bytes = in; + if (count == 4) { + uint32_t * t = in; + *t = (bytes[0] << 24) | (bytes[1] << 12) | (bytes[2] << 8) | bytes[3]; + } else if (count == 2) { + uint16_t * t = in; + *t = (bytes[0] << 8) | bytes[1]; + } +} + +void show_menu(void) { + +#if 1 + /* Try to detect qemu headless boot */ + outports(0x510, 0x0000); + if (inportb(0x511) == 'Q' && + inportb(0x511) == 'E' && + inportb(0x511) == 'M' && + inportb(0x511) == 'U') { + uint32_t count = 0; + uint8_t * bytes = (uint8_t *)&count; + outports(0x510,0x0019); + for (int i = 0; i < 4; ++i) { + bytes[i] = inportb(0x511); + } + swap_bytes(&count, 4); +#if 0 + print_("there are "); + print_hex_(count); + print_(" entries\n"); +#endif + + unsigned int bootmode_size = 0; + int bootmode_index = -1; + for (unsigned int i = 0; i < count; ++i) { + struct fw_cfg_file file; + uint8_t * tmp = (uint8_t *)&file; + for (int j = 0; j < sizeof(struct fw_cfg_file); ++j) { + tmp[j] = inportb(0x511); + } + if (!strcmp(file.name,"opt/org.toaruos.bootmode")) { + swap_bytes(&file.size, 4); + swap_bytes(&file.select, 2); + bootmode_size = file.size; + bootmode_index = file.select; + } +#if 0 + print_("selector "); print_hex_(file.select); print_(" is "); print_hex_(file.size); print_(" bytes\n"); + print_("and its name is: "); print_(file.name); print_("\n"); +#endif + } + + if (bootmode_index != -1) { + outports(0x510, bootmode_index); + char tmp[33] = {0}; + for (int i = 0; i < 32 && i < bootmode_size; ++i) { + tmp[i] = inportb(0x511); + } + for (int i = 0; i < BASE_SEL+1; ++i) { + if (!strcmp(tmp,boot_mode_names[i].key)) { + boot_mode = boot_mode_names[i].index; + return; + } + } + print_("fw_cfg boot mode not recognized: "); + print_(tmp); + print_("\n"); + } + } +#endif + + + /* Determine number of options */ + sel_max = 0; + while (boot_options[sel_max].value) { + sel_max++; + } + sel_max += BASE_SEL + 1; + +#ifndef EFI_PLATFORM + outportb(0x3D4, 14); + outportb(0x3D5, 0xFF); + outportb(0x3D4, 15); + outportb(0x3D5, 0xFF); + + inportb(0x3DA); + outportb(0x3C0, 0x30); + char b = inportb(0x3C1); + b &= ~8; + outportb(0x3c0, b); +#endif + + clear_(); + + do { + move_cursor(0,0); + set_attr(0x1f); + print_banner(VERSION_TEXT); + set_attr(0x07); + print_("\n"); + + for (int i = 0; i < BASE_SEL+1; ++i) { + set_attr(sel == i ? 0x70 : 0x07); + print_(" "); + char tmp[] = {'0' + (i + 1), '.', ' ', '\0'}; + print_(tmp); + print_(boot_mode_names[i].title); + print_("\n"); + } + + // put a gap + set_attr(0x07); + print_("\n"); + + for (int i = 0; i < sel_max - BASE_SEL - 1; ++i) { + toggle(BASE_SEL + 1 + i, *boot_options[i].value, boot_options[i].title); + } + + set_attr(0x07); + move_cursor(x,17); + print_("\n"); + print_banner(HELP_TEXT); + print_("\n"); + + if (sel > BASE_SEL) { + print_banner(boot_options[sel-BASE_SEL-1].description_1); + print_banner(boot_options[sel-BASE_SEL-1].description_2); + print_("\n"); + } else { + print_banner(COPYRIGHT_TEXT); + print_("\n"); + print_banner(LINK_TEXT); + } + + int s = read_scancode(); + if (s == 0x50) { /* DOWN */ + if (sel > BASE_SEL && sel < sel_max - 1) { + sel = (sel + 2) % sel_max; + } else { + sel = (sel + 1) % sel_max; + } + } else if (s == 0x48) { /* UP */ + if (sel > BASE_SEL + 1) { + sel = (sel_max + sel - 2) % sel_max; + } else { + sel = (sel_max + sel - 1) % sel_max; + } + } else if (s == 0x4B) { /* LEFT */ + if (sel > BASE_SEL + 1) { + sel -= 1; + } + } else if (s == 0x4D) { /* RIGHT */ + if (sel > BASE_SEL) { + sel = (sel + 1) % sel_max; + } + } else if (s == 0x1c) { + if (sel <= BASE_SEL) { + boot_mode = boot_mode_names[sel].index; + break; + } else { + int index = sel - BASE_SEL - 1; + *boot_options[index].value = !*boot_options[index].value; + } + } else if (s >= 2 && s <= 10) { + int i = s - 2; + if (i <= BASE_SEL) { + boot_mode = boot_mode_names[i].index; + break; + } +#if 0 + } else { + print_hex_(s); +#endif + } + } while (1); +} + +#ifdef EFI_PLATFORM +/* EFI boot uses simple filesystem driver */ +static EFI_GUID efi_simple_file_system_protocol_guid = + {0x0964e5b22,0x6459,0x11d2,0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}; + +static EFI_GUID efi_loaded_image_protocol_guid = + {0x5B1B31A1,0x9562,0x11d2, {0x8E,0x3F,0x00,0xA0,0xC9,0x69,0x72,0x3B}}; + +static void boot(void) { + UINTN count; + EFI_HANDLE * handles; + EFI_LOADED_IMAGE * loaded_image; + EFI_FILE_IO_INTERFACE *efi_simple_filesystem; + EFI_FILE *root; + EFI_STATUS status; + + clear_(); + + status = uefi_call_wrapper(ST->BootServices->HandleProtocol, + 3, ImageHandleIn, &efi_loaded_image_protocol_guid, + (void **)&loaded_image); + + if (EFI_ERROR(status)) { + print_("There was an error (init)\n"); + while (1) {}; + } + + print_("Found loaded image...\n"); + + status = uefi_call_wrapper(ST->BootServices->HandleProtocol, + 3, loaded_image->DeviceHandle, &efi_simple_file_system_protocol_guid, + (void **)&efi_simple_filesystem); + + if (EFI_ERROR(status)) { + print_("There was an error.\n"); + while (1) {}; + } + + status = uefi_call_wrapper(efi_simple_filesystem->OpenVolume, + 2, efi_simple_filesystem, &root); + + if (EFI_ERROR(status)) { + print_("There was an error.\n"); + while (1) {}; + } + + EFI_FILE * file; + + CHAR16 kernel_name[16] = {0}; + { + char * c = kernel_path; + char * ascii = c; + int i = 0; + while (*ascii) { + kernel_name[i] = *ascii; + i++; + ascii++; + } + if (kernel_name[i-1] == L'.') { + kernel_name[i-1] = 0; + } + } + + /* Load kernel */ + status = uefi_call_wrapper(root->Open, + 5, root, &file, kernel_name, EFI_FILE_MODE_READ, 0); + + if (EFI_ERROR(status)) { + print_("There was an error.\n"); + while (1) {}; + } + + unsigned int offset = 0; + UINTN bytes = 134217728; + status = uefi_call_wrapper(file->Read, + 3, file, &bytes, (void *)KERNEL_LOAD_START); + + if (EFI_ERROR(status)) { + print_("There was an error.\n"); + while (1) {}; + } + + print_("Read "); print_hex_(bytes); print_(" bytes\n"); + + offset += bytes; + while (offset % 4096) offset++; + + print_("Reading modules...\n"); + + char ** c = modules; + int j = 0; + while (*c) { + if (strcmp(*c, "NONE")) { + /* Try to load module */ + CHAR16 name[16] = {0}; + name[0] = L'm'; + name[1] = L'o'; + name[2] = L'd'; + name[3] = L'\\'; + char * ascii = *c; + int i = 0; + while (*ascii) { + name[i+4] = (*ascii >= 'A' && *ascii <= 'Z') ? (*ascii - 'A' + 'a') : *ascii; + name[i+5] = 0; + i++; + ascii++; + } + for (int i = 0; name[i]; ++i) { + char c[] = {name[i], 0}; + print_(c); + } + print_("\n"); + bytes = 2097152; +_try_module_again: + status = uefi_call_wrapper(root->Open, + 5, root, &file, name, EFI_FILE_MODE_READ, 0); + if (!EFI_ERROR(status)) { + status = uefi_call_wrapper(file->Read, + 3, file, &bytes, (void *)(KERNEL_LOAD_START + (uintptr_t)offset)); + if (!EFI_ERROR(status)) { + print_("Loaded "); print_(*c); print_("\n"); + modules_mboot[j].mod_start = KERNEL_LOAD_START + offset; + modules_mboot[j].mod_end = KERNEL_LOAD_START + offset + bytes; + j++; + offset += bytes; + while (offset % 4096) offset++; + } + } else { + print_("Error opening "); print_(*c); print_(" "); print_hex_(status); print_("\n"); + while (1) { }; + } + } else { + multiboot_header.mods_count--; + } + c++; + } + + { + char * c = ramdisk_path; + CHAR16 name[16] = {0}; + char * ascii = c; + int i = 0; + while (*ascii) { + name[i] = *ascii; + i++; + ascii++; + } + if (name[i-1] == L'.') { + name[i-1] == 0; + } + bytes = 134217728; + status = uefi_call_wrapper(root->Open, + 5, root, &file, name, EFI_FILE_MODE_READ, 0); + if (!EFI_ERROR(status)) { + status = uefi_call_wrapper(file->Read, + 3, file, &bytes, (void *)(KERNEL_LOAD_START + (uintptr_t)offset)); + if (!EFI_ERROR(status)) { + print_("Loaded "); print_(c); print_("\n"); + modules_mboot[multiboot_header.mods_count-1].mod_start = KERNEL_LOAD_START + offset; + modules_mboot[multiboot_header.mods_count-1].mod_end = KERNEL_LOAD_START + offset + bytes; + offset += bytes; + while (offset % 4096) offset++; + final_offset = (uint8_t *)KERNEL_LOAD_START + offset; + } else { + print_("Failed to read ramdisk\n"); + } + } else { + print_("Error opening "); print_(c); print_("\n"); + } + } + + move_kernel(); + + +} + +#else +/* BIOS boot uses native ATAPI drivers, need to find boot drive. */ +static void boot(void) { + + clear_(); + + multiboot_header.cmdline = (uintptr_t)cmdline; + + ata_device_detect(&ata_primary_master); + ata_device_detect(&ata_primary_slave); + ata_device_detect(&ata_secondary_master); + ata_device_detect(&ata_secondary_slave); + + if (ata_primary_master.is_atapi) { + do_it(&ata_primary_master); + } + if (ata_primary_slave.is_atapi) { + do_it(&ata_primary_slave); + } + if (ata_secondary_master.is_atapi) { + do_it(&ata_secondary_master); + } + if (ata_secondary_slave.is_atapi) { + do_it(&ata_secondary_slave); + } + + while (1); +} +#endif diff --git a/boot/multiboot.h b/boot/multiboot.h new file mode 100644 index 00000000..139ce7ec --- /dev/null +++ b/boot/multiboot.h @@ -0,0 +1,96 @@ +#pragma once + +#define MULTIBOOT_MAGIC 0x1BADB002 +#define MULTIBOOT_EAX_MAGIC 0x2BADB002 +#define MULTIBOOT_FLAG_MEM 0x001 +#define MULTIBOOT_FLAG_DEVICE 0x002 +#define MULTIBOOT_FLAG_CMDLINE 0x004 +#define MULTIBOOT_FLAG_MODS 0x008 +#define MULTIBOOT_FLAG_AOUT 0x010 +#define MULTIBOOT_FLAG_ELF 0x020 +#define MULTIBOOT_FLAG_MMAP 0x040 +#define MULTIBOOT_FLAG_DRIVE 0x080 +#define MULTIBOOT_FLAG_CONFIG 0x100 +#define MULTIBOOT_FLAG_LOADER 0x200 +#define MULTIBOOT_FLAG_APM 0x400 +#define MULTIBOOT_FLAG_VBE 0x800 + +struct multiboot +{ + uint32_t flags; + uint32_t mem_lower; + uint32_t mem_upper; + uint32_t boot_device; + uint32_t cmdline; + uint32_t mods_count; + uint32_t mods_addr; + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; + uint32_t mmap_length; + uint32_t mmap_addr; + uint32_t drives_length; + uint32_t drives_addr; + uint32_t config_table; + uint32_t boot_loader_name; + uint32_t apm_table; + uint32_t vbe_control_info; + uint32_t vbe_mode_info; + uint32_t vbe_mode; + uint32_t vbe_interface_seg; + uint32_t vbe_interface_off; + uint32_t vbe_interface_len; + uint32_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; + /* Palette stuff goes here but we don't use it */ +} __attribute__ ((packed)); + +typedef struct { + uint16_t attributes; + uint8_t winA, winB; + uint16_t granularity; + uint16_t winsize; + uint16_t segmentA, segmentB; + uint32_t realFctPtr; + uint16_t pitch; + + uint16_t Xres, Yres; + uint8_t Wchar, Ychar, planes, bpp, banks; + uint8_t memory_model, bank_size, image_pages; + uint8_t reserved0; + + uint8_t red_mask, red_position; + uint8_t green_mask, green_position; + uint8_t blue_mask, blue_position; + uint8_t rsv_mask, rsv_position; + uint8_t directcolor_attributes; + + uint32_t physbase; + uint32_t reserved1; + uint16_t reserved2; +} __attribute__ ((packed)) vbe_info_t; + +typedef struct { + uint32_t mod_start; + uint32_t mod_end; + uint32_t cmdline; + uint32_t reserved; +} __attribute__ ((packed)) mboot_mod_t; + +typedef struct { + uint32_t size; + uint64_t base_addr; + uint64_t length; + uint32_t type; +} __attribute__ ((packed)) mboot_memmap_t; + +extern struct multiboot *copy_multiboot(struct multiboot *mboot_ptr); +extern void dump_multiboot(struct multiboot *mboot_ptr); +extern char * ramdisk; +extern struct multiboot * mboot_ptr; +static char cmdline[1024] = {0}; diff --git a/boot/options.h b/boot/options.h new file mode 100644 index 00000000..7199ed83 --- /dev/null +++ b/boot/options.h @@ -0,0 +1,45 @@ +static int sel_max = 0; +static int sel = 0; + +void toggle(int ndx, int value, char *str) { + set_attr(sel == ndx ? 0x70 : 0x07); + if (value) { + print_(" [X] "); + } else { + print_(" [ ] "); + } + print_(str); + if (x < 40) { + while (x < 39) { + print_(" "); + } + x = 40; + } else { + print_("\n"); + } +} + +struct option { + int * value; + char * title; + char * description_1; + char * description_2; +} boot_options[20] = {{0}}; /* can't really hold more than that */ + +static int _boot_offset = 0; +#define BOOT_OPTION(_value, default_val, option, d1, d2) \ + int _value = default_val;\ + boot_options[_boot_offset].value = &_value; \ + boot_options[_boot_offset].title = option; \ + boot_options[_boot_offset].description_1 = d1; \ + boot_options[_boot_offset].description_2 = d2; \ + _boot_offset++ + +struct bootmode { + int index; + char * key; + char * title; +}; + +#define BASE_SEL ((sizeof(boot_mode_names)/sizeof(*boot_mode_names))-1) + diff --git a/boot/text.h b/boot/text.h new file mode 100644 index 00000000..776ecf76 --- /dev/null +++ b/boot/text.h @@ -0,0 +1,147 @@ +#pragma once + +static int txt_debug = 0; + +unsigned short * textmemptr = (unsigned short *)0xB8000; +static void placech(unsigned char c, int x, int y, int attr) { +#ifdef EFI_PLATFORM + unsigned short ch; + switch (c) { + case '\030': + ch = L'↑'; + break; + case '\031': + ch = L'↓'; + break; + case '\032': + ch = L'←'; + break; + case '\033': + ch = L'→'; + break; + default: + ch = c; + break; + } + uint16_t string[] = {ch, 0}; + uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, attr); + uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x, y); + uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, string); +#else + unsigned short *where; + unsigned att = attr << 8; + where = textmemptr + (y * 80 + x); + *where = c | att; +#endif +} + +static int x = 0; +static int y = 0; +static int attr = 0x07; +static void print_(char * str) { + while (*str) { + if (*str == '\n') { + for (; x < 80; ++x) { + placech(' ', x, y, attr); + } + x = 0; + y += 1; + if (y == 24) { + y = 0; + } + } else { + placech(*str, x, y, attr); + x++; + if (x == 80) { + x = 0; + y += 1; + if (y == 24) { + y = 0; + } + } + } + str++; + } +} + +static void move_cursor(int _x, int _y) { + x = _x; + y = _y; +} + +static void set_attr(int _attr) { + attr = _attr; +} + +static void print_banner(char * str) { + if (!str) { + for (int i = 0; i < 80; ++i) { + placech(' ', i, y, attr); + } + y++; + return; + } + int len = 0; + char *c = str; + while (*c) { + len++; + c++; + } + int off = (80 - len) / 2; + + for (int i = 0; i < 80; ++i) { + placech(' ', i, y, attr); + } + for (int i = 0; i < len; ++i) { + placech(str[i], i + off, y, attr); + } + + y++; +} + +#ifdef EFI_PLATFORM +static void print_int_(unsigned int value) { + unsigned int n_width = 1; + unsigned int i = 9; + while (value > i && i < UINT32_MAX) { + n_width += 1; + i *= 10; + i += 9; + } + + char buf[n_width+1]; + buf[n_width] = 0; + i = n_width; + while (i > 0) { + unsigned int n = value / 10; + int r = value % 10; + buf[i - 1] = r + '0'; + i--; + value = n; + } + print_(buf); +} +#endif + +static void print_hex_(unsigned int value) { + char out[9] = {0}; + for (int i = 7; i > -1; i--) { + out[i] = "0123456789abcdef"[(value >> (4 * (7 - i))) & 0xF]; + } + print_(out); +} + +static void clear_() { + x = 0; + y = 0; + for (int y = 0; y < 24; ++y) { + for (int x = 0; x < 80; ++x) { + placech(' ', x, y, 0x00); + } + } +} + +#define print(s) do {if (txt_debug) {print_(s);}} while(0) +#define clear() do {if (txt_debug) {clear_();}} while(0) +#define print_hex(d) do {if (txt_debug) {print_hex_(d);}} while(0) + diff --git a/boot/types.h b/boot/types.h new file mode 100644 index 00000000..0b6d06e0 --- /dev/null +++ b/boot/types.h @@ -0,0 +1,10 @@ +#pragma once + +typedef unsigned long long uint64_t; +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +typedef signed char int8_t; +typedef unsigned long uintptr_t; + +#define NULL (0) diff --git a/boot/util.h b/boot/util.h new file mode 100644 index 00000000..37955ddc --- /dev/null +++ b/boot/util.h @@ -0,0 +1,83 @@ +#pragma once + +#define _inline inline __attribute__((always_inline)) + +static _inline unsigned short inports(unsigned short _port) { + unsigned short rv; + asm volatile ("inw %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} + +static _inline void outports(unsigned short _port, unsigned short _data) { + asm volatile ("outw %1, %0" : : "dN" (_port), "a" (_data)); +} + +static _inline unsigned int inportl(unsigned short _port) { + unsigned int rv; + asm volatile ("inl %%dx, %%eax" : "=a" (rv) : "dN" (_port)); + return rv; +} + +static _inline void outportl(unsigned short _port, unsigned int _data) { + asm volatile ("outl %%eax, %%dx" : : "dN" (_port), "a" (_data)); +} + +static _inline unsigned char inportb(unsigned short _port) { + unsigned char rv; + asm volatile ("inb %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} + +static _inline void outportb(unsigned short _port, unsigned char _data) { + asm volatile ("outb %1, %0" : : "dN" (_port), "a" (_data)); +} + + +static _inline void inportsm(unsigned short port, unsigned char * data, unsigned long size) { + asm volatile ("rep insw" : "+D" (data), "+c" (size) : "d" (port) : "memory"); +} + +static _inline void * memcpy(void * restrict dest, const void * restrict src, long n) { + asm volatile("cld; rep movsb" + : "=c"((int){0}) + : "D"(dest), "S"(src), "c"(n) + : "flags", "memory"); + return dest; +} + +static _inline void * memset(void * dest, int c, long n) { + asm volatile("cld; rep stosb" + : "=c"((int){0}) + : "D"(dest), "a"(c), "c"(n) + : "flags", "memory"); + return dest; +} + +static int strcmp(const char * l, const char * r) { + for (; *l == *r && *l; l++, r++); + return *(unsigned char *)l - *(unsigned char *)r; +} + +static char * strchr(const char * s, int c) { + while (*s) { + if (*s == c) { + return (char *)s; + } + s++; + } + return 0; +} + +static char * strcat(char *dest, const char *src) { + char * end = dest; + while (*end != '\0') { + ++end; + } + while (*src) { + *end = *src; + end++; + src++; + } + *end = '\0'; + return dest; +} diff --git a/ext/ext_cairo_renderer.c b/ext/ext_cairo_renderer.c new file mode 100644 index 00000000..ad7b590f --- /dev/null +++ b/ext/ext_cairo_renderer.c @@ -0,0 +1,249 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * Compositor Cairo renderer backend + */ + +#include +#include +#include + +struct cairo_renderer { + cairo_t * framebuffer_ctx; + cairo_surface_t * framebuffer_surface; + cairo_t * real_ctx; + cairo_surface_t * real_surface; +}; + +int renderer_alloc(yutani_globals_t * yg) { + struct cairo_renderer * c = malloc(sizeof(struct cairo_renderer)); + c->framebuffer_ctx = NULL; + c->framebuffer_surface = NULL; + c->real_ctx = NULL; + c->real_surface = NULL; + yg->renderer_ctx = c; + return 0; +} + +int renderer_init(yutani_globals_t * yg) { + struct cairo_renderer * c = yg->renderer_ctx; + + int stride = yg->backend_ctx->stride; + c->framebuffer_surface = cairo_image_surface_create_for_data( + yg->backend_framebuffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride); + c->framebuffer_ctx = cairo_create(c->framebuffer_surface); + + c->real_surface = cairo_image_surface_create_for_data( + (unsigned char *)yg->backend_ctx->buffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride); + c->real_ctx = cairo_create(c->real_surface); + + return 0; +} + +int renderer_add_clip(yutani_globals_t * yg, double x, double y, double w, double h) { + struct cairo_renderer * c = yg->renderer_ctx; + cairo_rectangle(c->framebuffer_ctx, x, y, w, h); + if (yg->width > 2490) { + x = 0; + w = yg->width; + } + cairo_rectangle(c->real_ctx, x, y, w, h); + return 0; +} + +int renderer_set_clip(yutani_globals_t * yg) { + struct cairo_renderer * c = yg->renderer_ctx; + cairo_clip(c->framebuffer_ctx); + cairo_clip(c->real_ctx); + return 0; +} + +int renderer_push_state(yutani_globals_t * yg) { + struct cairo_renderer * c = yg->renderer_ctx; + cairo_save(c->framebuffer_ctx); + cairo_save(c->real_ctx); + return 0; +} + +int renderer_pop_state(yutani_globals_t * yg) { + struct cairo_renderer * c = yg->renderer_ctx; + cairo_restore(c->framebuffer_ctx); + cairo_restore(c->real_ctx); + return 0; +} + +int renderer_destroy(yutani_globals_t * yg) { + struct cairo_renderer * c = yg->renderer_ctx; + cairo_destroy(c->framebuffer_ctx); + cairo_surface_destroy(c->framebuffer_surface); + cairo_destroy(c->real_ctx); + cairo_surface_destroy(c->real_surface); + return 0; +} + +int renderer_blit_screen(yutani_globals_t * yg) { + struct cairo_renderer * c = yg->renderer_ctx; + cairo_set_operator(c->real_ctx, CAIRO_OPERATOR_SOURCE); + cairo_translate(c->real_ctx, 0, 0); + cairo_set_source_surface(c->real_ctx, c->framebuffer_surface, 0, 0); + cairo_paint(c->real_ctx); + return 0; +} + +int renderer_blit_window(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y) { + /* Obtain the previously initialized cairo contexts */ + struct cairo_renderer * c = yg->renderer_ctx; + cairo_t * cr = c->framebuffer_ctx; + + /* Window stride is always 4 bytes per pixel... */ + int stride = window->width * 4; + + /* Initialize a cairo surface object for this window */ + cairo_surface_t * surf = cairo_image_surface_create_for_data( + window->buffer, CAIRO_FORMAT_ARGB32, window->width, window->height, stride); + + /* Save cairo context */ + cairo_save(cr); + + /* + * Offset the rendering context appropriately for the position of the window + * based on the modifier paramters + */ + cairo_identity_matrix(cr); + cairo_translate(cr, x, y); + + /* Top and bottom windows can not be rotated. */ + if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window)) { + /* Calcuate radians from degrees */ + + if (window->rotation != 0) { + double r = M_PI * (((double)window->rotation) / 180.0); + + /* Rotate the render context about the center of the window */ + cairo_translate(cr, (int)( window->width / 2), (int)( (int)window->height / 2)); + cairo_rotate(cr, r); + cairo_translate(cr, (int)(-window->width / 2), (int)(-window->height / 2)); + + /* Prefer faster filter when rendering rotated windows */ + cairo_pattern_t * p = cairo_get_source(cr); + cairo_pattern_set_filter(p, CAIRO_FILTER_FAST); + } + + if (window == yg->resizing_window) { + double x_scale = (double)yg->resizing_w / (double)yg->resizing_window->width; + double y_scale = (double)yg->resizing_h / (double)yg->resizing_window->height; + if (x_scale < 0.00001) { + x_scale = 0.00001; + } + if (y_scale < 0.00001) { + y_scale = 0.00001; + } + cairo_translate(cr, (int)yg->resizing_offset_x, (int)yg->resizing_offset_y); + cairo_scale(cr, x_scale, y_scale); + } + + } + if (window->anim_mode) { + int frame = yutani_time_since(yg, window->anim_start); + if (frame >= yutani_animation_lengths[window->anim_mode]) { + if (window->anim_mode == YUTANI_EFFECT_FADE_OUT) { + list_insert(yg->windows_to_remove, window); + goto draw_finish; + } + window->anim_mode = 0; + window->anim_start = 0; + goto draw_window; + } else { + switch (window->anim_mode) { + case YUTANI_EFFECT_FADE_OUT: + { + frame = yutani_animation_lengths[window->anim_mode] - frame; + } + case YUTANI_EFFECT_FADE_IN: + { + double time_diff = ((double)frame / (float)yutani_animation_lengths[window->anim_mode]); + + if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window) && + !(window->server_flags & YUTANI_WINDOW_FLAG_ALT_ANIMATION)) { + double x = 0.75 + time_diff * 0.25; + int t_x = (window->width * (1.0 - x)) / 2; + int t_y = (window->height * (1.0 - x)) / 2; + cairo_translate(cr, t_x, t_y); + cairo_scale(cr, x, x); + } + + cairo_set_source_surface(cr, surf, 0, 0); + if (window->opacity != 255) { + cairo_paint_with_alpha(cr, time_diff * (double)(window->opacity) / 255.0); + } else { + cairo_paint_with_alpha(cr, time_diff); + } + } + break; + default: + goto draw_window; + break; + } + } + } else { +draw_window: + /* Paint window */ + cairo_set_source_surface(cr, surf, 0, 0); + + if (window->opacity != 255) { + cairo_paint_with_alpha(cr, (float)(window->opacity)/255.0); + } else { + cairo_paint(cr); + } + } + +draw_finish: + + /* Clean up */ + cairo_surface_destroy(surf); + + /* Restore context stack */ + cairo_restore(cr); + +#if YUTANI_DEBUG_WINDOW_BOUNDS + /* + * If window bound debugging is enabled, we also draw a box + * representing the rectangular (possibly rotated) boundary + * for a window texture. + */ + if (yg->debug_bounds) { + cairo_save(cr); + + int32_t t_x, t_y; + int32_t s_x, s_y; + int32_t r_x, r_y; + int32_t q_x, q_y; + + yutani_window_to_device(window, 0, 0, &t_x, &t_y); + yutani_window_to_device(window, window->width, window->height, &s_x, &s_y); + yutani_window_to_device(window, 0, window->height, &r_x, &r_y); + yutani_window_to_device(window, window->width, 0, &q_x, &q_y); + + uint32_t x = yutani_color_for_wid(window->wid); + cairo_set_source_rgba(cr, + _RED(x) / 255.0, + _GRE(x) / 255.0, + _BLU(x) / 255.0, + 0.7 + ); + + cairo_move_to(cr, t_x, t_y); + cairo_line_to(cr, r_x, r_y); + cairo_line_to(cr, s_x, s_y); + cairo_line_to(cr, q_x, q_y); + cairo_fill(cr); + + cairo_restore(cr); + } +#endif + + + return 0; +} diff --git a/userspace/lib/shmemfonts.c b/ext/ext_freetype_fonts.c similarity index 56% rename from userspace/lib/shmemfonts.c rename to ext/ext_freetype_fonts.c index cc31f53b..91839e73 100644 --- a/userspace/lib/shmemfonts.c +++ b/ext/ext_freetype_fonts.c @@ -1,57 +1,72 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2014 Kevin Lange - */ /* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange * - * - * Shared-memory font management and access library. - * + * Extension library for freetype font rendering. */ +#include +#include +#include +#include -#include #include #include FT_FREETYPE_H #include FT_CACHE_H -#include "lib/yutani.h" -#include "lib/graphics.h" +#define SERVER_NAME "fonts" -#include "shmemfonts.h" -#include "utf8decode.h" +#define FONT_SANS_SERIF 0 +#define FONT_SANS_SERIF_BOLD 1 +#define FONT_SANS_SERIF_ITALIC 2 +#define FONT_SANS_SERIF_BOLD_ITALIC 3 +#define FONT_MONOSPACE 4 +#define FONT_MONOSPACE_BOLD 5 +#define FONT_MONOSPACE_ITALIC 6 +#define FONT_MONOSPACE_BOLD_ITALIC 7 +#define FONT_JAPANESE 8 +#define FONT_SYMBOLA 9 +#define FONTS_TOTAL 10 + +#define FONT_SIZE 12 static FT_Library library; static FT_Face faces[FONTS_TOTAL]; /* perhaps make this an array ? */ static FT_GlyphSlot slot; -static FT_UInt glyph_index; -static int initialized = 0; -static int _font_size = 12; static int selected_face = 0; - -#define SGFX(CTX,x,y,WIDTH) *((uint32_t *)&CTX[((WIDTH) * (y) + (x)) * 4]) -#define FONT_SIZE 12 - +static int _font_size = 12; static int fallbacks[] = {FONT_JAPANESE, FONT_SYMBOLA, -1}; -/* - * XXX: take font name as an argument / allow multiple fonts - */ +#define SGFX(CTX,x,y,WIDTH) *((uint32_t *)&CTX[((WIDTH) * (y) + (x)) * 4]) + static void _load_font(int i, char * name) { - char * font; + uint8_t * font; size_t s = 0; int error; char tmp[100]; - snprintf(tmp, 100, "sys.%s%s", getenv("DISPLAY"), name); + snprintf(tmp, 100, "sys.%s%s", SERVER_NAME, name); - font = (char *)syscall_shm_obtain(tmp, &s); + font = (void*)syscall_shm_obtain(tmp, &s); error = FT_New_Memory_Face(library, font, s, 0, &faces[i]); + if (error) { + fprintf(stderr, "[freetype backend] encountered error\n"); + } error = FT_Set_Pixel_Sizes(faces[i], FONT_SIZE, FONT_SIZE); + if (error) { + fprintf(stderr, "[freetype backend] encountered error\n"); + } } static void _load_font_f(int i, char * path) { int error; error = FT_New_Face(library, path, 0, &faces[i]); + if (error) { + fprintf(stderr, "[freetype backend] encountered error\n"); + } error = FT_Set_Pixel_Sizes(faces[i], FONT_SIZE, FONT_SIZE); + if (error) { + fprintf(stderr, "[freetype backend] encountered error\n"); + } } static void _load_fonts() { @@ -67,32 +82,17 @@ static void _load_fonts() { _load_font_f(FONT_SYMBOLA, "/usr/share/fonts/Symbola.ttf"); } -void init_shmemfonts() { - if (!initialized) { - FT_Init_FreeType(&library); - _load_fonts(); - selected_face = FONT_SANS_SERIF; - initialized = 1; - } +void freetype_set_font_face(int font) { + selected_face = font; } -void set_font_size(int size) { +void freetype_set_font_size(int size) { + _font_size = size; for (int i = 0; i < FONTS_TOTAL; ++i) { FT_Set_Pixel_Sizes(faces[i], size, size); } } -void set_font_face(int face_num) { - selected_face = face_num; -} - -char * shmem_font_name(int i) { - return ((FT_FaceRec *)faces[i])->family_name; -} - -/* - * Draw a character to a context. - */ static void draw_char(FT_Bitmap * bitmap, int x, int y, uint32_t fg, gfx_context_t * ctx) { int i, j, p, q; int x_max = x + bitmap->width; @@ -109,66 +109,59 @@ static void draw_char(FT_Bitmap * bitmap, int x, int y, uint32_t fg, gfx_context } } -uint32_t draw_string_width(char * string) { - slot = faces[selected_face]->glyph; - int pen_x = 0, i = 0; +void freetype_draw_char(gfx_context_t * ctx, int x, int y, uint32_t fg, uint32_t o) { + int pen_x = x, pen_y = y; int error; + slot = faces[selected_face]->glyph; + FT_UInt glyph_index; - uint8_t * s = string; - - uint32_t codepoint; - uint32_t state = 0; - - while (*s) { - uint32_t o = 0; - while (*s) { - if (!decode(&state, &codepoint, (uint8_t)*s)) { - o = (uint32_t)codepoint; - s++; - goto finished_width; - } else if (state == UTF8_REJECT) { - state = 0; - } - s++; + glyph_index = FT_Get_Char_Index( faces[selected_face], o); + if (glyph_index) { + error = FT_Load_Glyph(faces[selected_face], glyph_index, FT_LOAD_DEFAULT); + if (error) { + fprintf(stderr, "Error loading glyph for '%lu'\n", o); + return; } - -finished_width: - if (!o) continue; - - FT_UInt glyph_index; - - glyph_index = FT_Get_Char_Index( faces[selected_face], o); - if (glyph_index) { - error = FT_Load_Glyph(faces[selected_face], glyph_index, FT_LOAD_DEFAULT); + slot = (faces[selected_face])->glyph; + if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { + error = FT_Render_Glyph((faces[selected_face])->glyph, FT_RENDER_MODE_NORMAL); if (error) { - fprintf(stderr, "Error loading glyph for '%d'\n", o); - continue; - } - slot = (faces[selected_face])->glyph; - } else { - int i = 0; - while (!glyph_index && fallbacks[i] != -1) { - int fallback = fallbacks[i++]; - glyph_index = FT_Get_Char_Index( faces[fallback], o); - error = FT_Load_Glyph(faces[fallback], glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(stderr, "Error loading glyph for '%d'\n", o); - continue; - } - slot = (faces[fallback])->glyph; + fprintf(stderr, "Error rendering glyph for '%lu'\n", o); + return; } } - pen_x += slot->advance.x >> 6; + } else { + int i = 0; + while (!glyph_index && fallbacks[i] != -1) { + int fallback = fallbacks[i++]; + glyph_index = FT_Get_Char_Index( faces[fallback], o); + error = FT_Load_Glyph(faces[fallback], glyph_index, FT_LOAD_DEFAULT); + if (error) { + fprintf(stderr, "Error loading glyph for '%lu'\n", o); + return; + } + slot = (faces[fallback])->glyph; + if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { + error = FT_Render_Glyph((faces[fallback])->glyph, FT_RENDER_MODE_NORMAL); + if (error) { + fprintf(stderr, "Error rendering glyph for '%lu'\n", o); + return; + } + } + } + } - return pen_x; + + draw_char(&slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top, fg, ctx); + } -void draw_string(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string) { +int freetype_draw_string(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string) { slot = faces[selected_face]->glyph; - int pen_x = x, pen_y = y, i = 0; + int pen_x = x, pen_y = y; int error; - uint8_t * s = string; + uint8_t * s = (uint8_t *)string; uint32_t codepoint; uint32_t state = 0; @@ -195,14 +188,14 @@ finished: if (glyph_index) { error = FT_Load_Glyph(faces[selected_face], glyph_index, FT_LOAD_DEFAULT); if (error) { - fprintf(stderr, "Error loading glyph for '%d'\n", o); + fprintf(stderr, "Error loading glyph for '%lu'\n", o); continue; } slot = (faces[selected_face])->glyph; if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { error = FT_Render_Glyph((faces[selected_face])->glyph, FT_RENDER_MODE_NORMAL); if (error) { - fprintf(stderr, "Error rendering glyph for '%d'\n", o); + fprintf(stderr, "Error rendering glyph for '%lu'\n", o); continue; } } @@ -213,14 +206,14 @@ finished: glyph_index = FT_Get_Char_Index( faces[fallback], o); error = FT_Load_Glyph(faces[fallback], glyph_index, FT_LOAD_DEFAULT); if (error) { - fprintf(stderr, "Error loading glyph for '%d'\n", o); + fprintf(stderr, "Error loading glyph for '%lu'\n", o); continue; } slot = (faces[fallback])->glyph; if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { error = FT_Render_Glyph((faces[fallback])->glyph, FT_RENDER_MODE_NORMAL); if (error) { - fprintf(stderr, "Error rendering glyph for '%d'\n", o); + fprintf(stderr, "Error rendering glyph for '%lu'\n", o); continue; } } @@ -232,44 +225,105 @@ finished: pen_x += slot->advance.x >> 6; pen_y += slot->advance.y >> 6; } + return pen_x - x; } -void draw_string_shadow(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string, uint32_t shadow_color, int darkness, int offset_x, int offset_y, double radius) { +int freetype_draw_string_width(char * string) { + slot = faces[selected_face]->glyph; + int pen_x = 0; + int error; + + uint8_t * s = (uint8_t *)string; + + uint32_t codepoint; + uint32_t state = 0; + + while (*s) { + uint32_t o = 0; + while (*s) { + if (!decode(&state, &codepoint, (uint8_t)*s)) { + o = (uint32_t)codepoint; + s++; + goto finished_width; + } else if (state == UTF8_REJECT) { + state = 0; + } + s++; + } + +finished_width: + if (!o) continue; + + FT_UInt glyph_index; + + glyph_index = FT_Get_Char_Index( faces[selected_face], o); + if (glyph_index) { + error = FT_Load_Glyph(faces[selected_face], glyph_index, FT_LOAD_DEFAULT); + if (error) { + fprintf(stderr, "Error loading glyph for '%lu'\n", o); + continue; + } + slot = (faces[selected_face])->glyph; + } else { + int i = 0; + while (!glyph_index && fallbacks[i] != -1) { + int fallback = fallbacks[i++]; + glyph_index = FT_Get_Char_Index( faces[fallback], o); + error = FT_Load_Glyph(faces[fallback], glyph_index, FT_LOAD_DEFAULT); + if (error) { + fprintf(stderr, "Error loading glyph for '%lu'\n", o); + continue; + } + slot = (faces[fallback])->glyph; + } + } + pen_x += slot->advance.x >> 6; + } + return pen_x; +} + +__attribute__((constructor)) static void init_lib(void) { + FT_Init_FreeType(&library); + _load_fonts(); + selected_face = FONT_SANS_SERIF; +} + +char * freetype_font_name(int i) { + return ((FT_FaceRec *)faces[i])->family_name; +} + +FT_Face freetype_get_active_font_face(void) { + return faces[selected_face]; +} + +void freetype_draw_string_shadow(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string, uint32_t shadow_color, int darkness, int offset_x, int offset_y, double radius) { #define OFFSET_X 5 #define OFFSET_Y 5 #define WIDTH_PAD 15 #define HEIGHT_PAD 15 - gfx_context_t * tmp_c, * out_c; - sprite_t * tmp_s, * out_s; + gfx_context_t * out_c; + sprite_t * out_s; - size_t width = draw_string_width(string) + WIDTH_PAD; + size_t width = freetype_draw_string_width(string) + WIDTH_PAD; size_t height = _font_size + HEIGHT_PAD; - tmp_s = create_sprite(width, height, ALPHA_EMBEDDED); - tmp_c = init_graphics_sprite(tmp_s); - out_s = create_sprite(width, height, ALPHA_EMBEDDED); out_c = init_graphics_sprite(out_s); - draw_fill(tmp_c, rgba(0,0,0,0)); - draw_string(tmp_c, OFFSET_X + offset_x, OFFSET_Y + offset_y + _font_size, shadow_color, string); + draw_fill(out_c, rgba(0,0,0,0)); + freetype_draw_string(out_c, OFFSET_X + offset_x, OFFSET_Y + offset_y + _font_size, shadow_color, string); - blur_context(out_c, tmp_c, radius); + /* Two should work okay? */ + blur_context_box(out_c, radius); + blur_context_box(out_c, radius); - draw_string(out_c, OFFSET_X, OFFSET_Y + _font_size, fg, string); + freetype_draw_string(out_c, OFFSET_X, OFFSET_Y + _font_size, fg, string); for (int i = 0; i < darkness; ++i) { draw_sprite(ctx, out_s, x - OFFSET_X, y - OFFSET_Y - _font_size); } - sprite_free(tmp_s); - free(tmp_c); - sprite_free(out_s); free(out_c); } - -FT_Face get_active_font_face(void) { - return faces[selected_face]; -} diff --git a/hdd/bin/msk b/hdd/bin/msk deleted file mode 120000 index 2cf03403..00000000 --- a/hdd/bin/msk +++ /dev/null @@ -1 +0,0 @@ -msk.py \ No newline at end of file diff --git a/hdd/etc/default.desktop b/hdd/etc/default.desktop deleted file mode 100644 index 5ad380fe..00000000 --- a/hdd/etc/default.desktop +++ /dev/null @@ -1,3 +0,0 @@ -utilities-terminal,terminal,Terminal -folder,file_browser.py,Documents -package,gsudo package_manager.py,Packages diff --git a/hdd/etc/glogin.conf b/hdd/etc/glogin.conf deleted file mode 100644 index 44008d8c..00000000 --- a/hdd/etc/glogin.conf +++ /dev/null @@ -1,22 +0,0 @@ -[style] -; Background box -;center_box_x=1 -;center_box_y=1 -;box_left=100 -;box_top=100 -;box_right=-1 -;box_bottom=-1 -;box_color_r=0 -;box_color_g=0 -;box_color_b=0 -;box_color_a=127 -;box_width=272 -;box_height=104 -;box_roundness=4 -; Logo positioning -;logo_padding=100 - -[image] -;logo=/usr/share/logo_login.png -;wallpaper=/usr/share/wallpapers/yosemite.png - diff --git a/hdd/etc/master.passwd b/hdd/etc/master.passwd deleted file mode 100644 index db87ba6f..00000000 --- a/hdd/etc/master.passwd +++ /dev/null @@ -1,3 +0,0 @@ -root:2b64f2e3f9fee1942af9ff60d40aa5a719db33b8ba8dd4864bb4f11e25ca2bee00907de32a59429602336cac832c8f2eeff5177cc14c864dd116c8bf6ca5d9a9:0:0:Administrator:/home/root:/bin/sh:simple -local:6f01a907513e6652020598d38516b788063624b31e9f3afe9c7c0ef4ea5ab4fd4843dd3579292de5aef626d588e678c045cb3ab4d1e49b89237380140907576c:1000:1000:Local User:/home/local:/bin/sh:fancy -bash:6f01a907513e6652020598d38516b788063624b31e9f3afe9c7c0ef4ea5ab4fd4843dd3579292de5aef626d588e678c045cb3ab4d1e49b89237380140907576c:1001:1001:Bash User:/home/bash:/usr/bin/bash:fancy diff --git a/hdd/etc/passwd b/hdd/etc/passwd deleted file mode 100644 index 7ac032e9..00000000 --- a/hdd/etc/passwd +++ /dev/null @@ -1,3 +0,0 @@ -root:x:0:0:Administrator:/home/root:/bin/sh:simple -local:x:1000:1000:Local User:/home/local:/bin/sh:fancy -bash:x:1001:1001:Bash User:/home/bash:/usr/bin/bash:fancy diff --git a/hdd/etc/vimrc b/hdd/etc/vimrc deleted file mode 100644 index 3e3f5171..00000000 --- a/hdd/etc/vimrc +++ /dev/null @@ -1,468 +0,0 @@ -" vimrc -" Current author: David Majnemer -" Original author: Saleem Abdulrasool -" vim: set ts=3 sw=3 et nowrap: - -if has('multi_byte') " Make sure we have unicode support - scriptencoding utf-8 " This file is in UTF-8 - - " ---- Terminal Setup ---- - if (&termencoding == "" && (&term =~ "xterm" || &term =~ "putty")) || (&term =~ "rxvt-unicode") || (&term =~ "screen") || (&term == "toaru") - set termencoding=utf-8 - endif - if ($COLORTERM =~ "putty") - set termencoding=latin - endif - set encoding=utf-8 " Default encoding should always be UTF-8 -endif - -if (&term == "toaru") - set ttymouse=xterm2 -endif - -if (&term =~ "screen") - set ttymouse=xterm2 -endif - -" ---- General Setup ---- -set nocompatible " Don't emulate vi's limitations -set tabstop=4 " 4 spaces for tabs -set shiftwidth=4 " 4 spaces for indents -set smarttab " Tab next line based on current line -"set expandtab " Spaces for indentation -set autoindent " Automatically indent next line -if has('smartindent') - set smartindent " Indent next line based on current line -endif -"set linebreak " Display long lines wrapped at word boundaries -set incsearch " Enable incremental searching -set hlsearch " Highlight search matches -set ignorecase " Ignore case when searching... -set smartcase " ...except when we don't want it -set infercase " Attempt to figure out the correct case -set showfulltag " Show full tags when doing completion -set virtualedit=block " Only allow virtual editing in block mode -set lazyredraw " Lazy Redraw (faster macro execution) -set wildmenu " Menu on completion please -set wildmode=longest,full " Match the longest substring, complete with first -set wildignore=*.o,*~ " Ignore temp files in wildmenu -set scrolloff=3 " Show 3 lines of context during scrolls -set sidescrolloff=2 " Show 2 columns of context during scrolls -set backspace=2 " Normal backspace behavior -"set textwidth=80 " Break lines at 80 characters -set hidden " Allow flipping of buffers without saving -set noerrorbells " Disable error bells -set visualbell " Turn visual bell on -set t_vb= " Make the visual bell emit nothing -set showcmd " Show the current command - -set diffopt+=iwhite - -" work around ext2 write issues -" XXX remove this later -set viminfo= - - -" ---- Filetypes ---- -if has('syntax') - syntax on -endif - -if has('eval') - filetype on " Detect filetype by extension - filetype indent on " Enable indents based on extensions - filetype plugin on " Load filetype plugins -endif - -" ---- Folding ---- -if has('eval') - fun! WideFold() - if winwidth(0) > 90 - setlocal foldcolumn=1 - else - setlocal foldcolumn=0 - endif - endfun - - let g:detectindent_preferred_expandtab = 0 - let g:detectindent_preferred_indent = 4 - - fun! DetectDetectIndent() - try - :DetectIndent - catch - endtry - endfun - - fun! ToggleFoldColumn() - if &foldcolumn == 1 - set foldcolumn=3 - elseif &foldcolumn == 3 - set foldcolumn=0 - else - set foldcolumn=1 - endif - endfun - nnoremap :call ToggleFoldColumn() -endif - -if has('autocmd') - autocmd BufEnter * :call WideFold() - if has('eval') - autocmd BufReadPost * :call s:DetectDetectIndent() - endif - - if has('viminfo') - autocmd BufReadPost * - \ if line("'\"") > 0 && line("'\"") <= line("$") | - \ exe "normal g`\"" | - \ endif - endif -endif - -" ---- Spelling ---- -if (v:version >= 700) - set spelllang=en_us " US English Spelling please - - " Toggle spellchecking with F10 - nmap :silent set spell! - imap :silent set spell! -endif - -" Display a pretty statusline if we can -if has('title') - set title -endif - -set title -set t_fs= -set t_ts=]1; - -set laststatus=2 -set shortmess=atI -if has('statusline') - set statusline=%<%F\ %r[%{&ff}]%y%m\ %=\ Line\ %l\/%L\ Col:\ %v\ (%P) -endif - -" Enable modelines only on secure vim -if (v:version == 603 && has("patch045")) || (v:version > 603) - set modeline - set modelines=3 -else - set nomodeline -endif - -" Shamelessly stolen from Ciaran McCreesh -if has('eval') - fun! LoadColorScheme(schemes) - let l:schemes = a:schemes . ":" - - while l:schemes != "" - let l:scheme = strpart(l:schemes, 0, stridx(l:schemes, ":")) - let l:schemes = strpart(l:schemes, stridx(l:schemes, ":") + 1) - - try - exec "colorscheme" l:scheme - break - catch - endtry - endwhile - endfun - - if has("gui_running") - call LoadColorScheme("wombat:twilight256:desert") - elseif &t_Co == 256 - call LoadColorScheme("wombat:twilight256:inkpot") - elseif &t_Co == 88 - call LoadColorScheme("wombat:zellner") - else - call LoadColorScheme("darkblue:zellner") - endif -endif - -" Show trailing whitespace visually -" Shamelessly stolen from Ciaran McCreesh -if (&termencoding == "utf-8") || has("gui_running") - if v:version >= 700 - set list listchars=tab:»·,trail:·,extends:…,nbsp:‗ - else - set list listchars=tab:»·,trail:·,extends:… - endif -else - if v:version >= 700 - set list listchars=tab:>-,trail:.,extends:>,nbsp:_ - else - set list listchars=tab:>-,trail:.,extends:> - endif -endif - -if has('mouse') - " Dont copy the listchars when copying - set mouse=nvi -endif - -if has('autocmd') - " always refresh syntax from the start - autocmd BufEnter * syntax sync fromstart - - " subversion commit messages need not be backed up - autocmd BufRead svn-commit.tmp :setlocal nobackup - - " mutt does not like UTF-8 - autocmd BufRead,BufNewFile * - \ if &ft == 'mail' | set fileencoding=iso8859-1 | endif - - " fix up procmail rule detection - autocmd BufRead procmailrc :setfiletype procmail -endif - -" ---- cscope/ctags setup ---- -if has('cscope') && executable('cscope') == 1 - " Search cscope and ctags, in that order - set cscopetag - set cscopetagorder=0 - - set nocsverb - if filereadable('cscope.out') - cs add cscope.out - endif - set csverb -endif - -" ---- Key Mappings ---- - -" improved lookup -if has('eval') - fun! GoDefinition() - let pos = getpos(".") - normal! gd - if getpos(".") == pos - exe "tag " . expand("") - endif - endfun - - nmap :call GoDefinition() -endif - -if has('autocmd') - " Shortcuts - if has('eval') - fun! cabbrev() - iab #i #include - iab #I #include - - iab #d #define - iab #D #define - - iab #e #endif - iab #E #endif - endfun - - autocmd FileType c,cpp :call cabbrev() - - autocmd BufRead,BufNewFile *.mm set filetype=noweb - autocmd BufRead,BufNewFile *.scala set filetype=scala - autocmd BufRead,BufNewFile *.proto setfiletype proto - endif - - " make tab reindent in normal mode - autocmd FileType c,cpp,cs,java nmap =0 -endif - -" Append modeline after last line in buffer. -" Use substitute() (not printf()) to handle '%%s' modeline in LaTeX files. -if has('eval') - fun! AppendModeline() - let save_cursor = getpos('.') - let append = ' vim: set ts='.&tabstop.' sw='.&shiftwidth.' tw='.&textwidth.': ' - $put =substitute(&commentstring, '%s', append, '') - call setpos('.', save_cursor) - endfun - nnoremap ml :call AppendModeline() -endif - -" tab indents selection -vmap >gv - -" shift-tab unindents -vmap - -" shifted arrows are stupid -inoremap gk -noremap gk -inoremap gj -noremap gj - -" Y should yank to EOL -map Y y$ - -" vK is stupid -vmap K k - -" :W and :Q are annoying -if has('user_commands') - command! -nargs=0 -bang Q q - command! -nargs=0 -bang W w - command! -nargs=0 -bang WQ wq - command! -nargs=0 -bang Wq wq -endif - -" just continue -nmap K K - -" stolen from auctex.vim -if has('eval') - fun! EmacsKill() - if col(".") == strlen(getline(line(".")))+1 - let @" = "\" - return "\" - else - return "\D" - endif - endfun -endif - -" some emacs-isms are OK -map! -map -map! -map -imap -imap -map! -map d$ -if has('eval') - inoremap =EmacsKill() -endif - -" w!! for sudo w! -cmap w!! w !sudo tee % >/dev/null - -" clear search -"nnoremap :noh - -" Disable q and Q -map q -map Q - -" Toggle numbers with F12 -nmap :silent set number! -imap :silent set number! -noremap :set hls! - -" Don't force column 0 for # -inoremap # X# - -" Always map to backspace -" Both interix and cons use C-? as forward delete, -" besides those two exceptions, always set it to backspace -" Also let interix use ^[[U for end and ^[[H for home -map -map! -if (&term =~ "interix") - map - map! - map [H - map [U -elseif (&term =~ "^sun") - map - map! -elseif (&term !~ "cons") - map - map! -endif - -if ((&term =~ "^xterm") || (&term == "toaru")) - map [H - map! [H - map [F - map! [F - map [5D - map! [5D - map [5C - map! [5C -endif - -" Terminal.app does not support back color erase -if ($TERM_PROGRAM ==# "Apple_Terminal" && $TERM_PROGRAM_VERSION <= 273) - set t_ut= -endif - -" Python specific stuff -if has('eval') - let python_highlight_all = 1 - let python_slow_sync = 1 -endif - -" ---- OmniCpp ---- -if v:version >= 700 - if has('autocmd') - autocmd InsertLeave * if pumvisible() == 0|pclose|endif - endif - - set completeopt=menu,menuone,longest - - let OmniCpp_MayCompleteDot = 1 " autocomplete with . - let OmniCpp_MayCompleteArrow = 1 " autocomplete with -> - let OmniCpp_MayCompleteScope = 1 " autocomplete with :: - let OmniCpp_SelectFirstItem = 2 " select first item (but don't insert) - let OmniCpp_NamespaceSearch = 2 " search namespaces in this and included files - let OmniCpp_ShowPrototypeInAbbr = 1 " show function prototype (i.e. parameters) in popup window - map :!$HOME/bin/ctags -R --c++-kinds=+p --fields=+iaS --extra=+q . - " add current directory's generated tags file to available tags - set tags+=./tags -endif - -set t_RV= -nnoremap :set invpaste paste? -set pastetoggle= -set showmode - - -" ex command for toggling hex mode - define mapping if desired -command -bar Hexmode call ToggleHex() - -" helper function to toggle hex mode -function ToggleHex() - " hex mode should be considered a read-only operation - " save values for modified and read-only for restoration later, - " and clear the read-only flag for now - let l:modified=&mod - let l:oldreadonly=&readonly - let &readonly=0 - let l:oldmodifiable=&modifiable - let &modifiable=1 - if !exists("b:editHex") || !b:editHex - " save old options - let b:oldft=&ft - let b:oldbin=&bin - " set new options - setlocal binary " make sure it overrides any textwidth, etc. - let &ft="xxd" - " set status - let b:editHex=1 - " switch to hex editor - %!xxd - else - " restore old options - let &ft=b:oldft - if !b:oldbin - setlocal nobinary - endif - " set status - let b:editHex=0 - " return to normal editing - %!xxd -r - endif - " restore values for modified and read only state - let &mod=l:modified - let &readonly=l:oldreadonly - let &modifiable=l:oldmodifiable -endfunction - - -highlight ColorColumn ctermbg=1 -highlight ColorColumn guibg=Red diff --git a/hdd/home/bash/.bashrc b/hdd/home/bash/.bashrc deleted file mode 100644 index 7078a4b3..00000000 --- a/hdd/home/bash/.bashrc +++ /dev/null @@ -1,218 +0,0 @@ -# -# klange's ~/.bashrc -# - -[ -z "$PS1" ] && return - -# DEFAULTS -KLANGE_USE_GIT=false -KLANGE_USE_SVN=false -KLANGE_USE_HG=false - -if [[ "$(uname)" == "Darwin" || "$(uname)" == *CYGWIN* ]] ; then - HOSTNAME=`hostname` - alias ls="ls -G" - export PATH="/Applications/Xcode.app/Contents/Developer/usr/bin:$PATH" -else - HOSTNAME=`hostname --long` -fi - -# ~/bin -if [ -e ~/bin ]; then - export PATH=~/bin:$PATH -fi - -# SPECIAL OPTIONS AND FIXES - -export HISTCONTROL=$HISTCONTROL${HISTCONTROL+,}ignoredups -export HISTCONTROL=ignoreboth -shopt -s histappend -shopt -s checkwinsize -[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" -if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then - debian_chroot=$(cat /etc/debian_chroot) -fi - -# Fix gnome-terminal color support -if [ "$COLORTERM" == "gnome-terminal" ]; then - export TERM="xterm-256color" -elif [ "$COLORTERM" == "mate-terminal" ]; then - export TERM="xterm-256color" -elif [ "$COLORTERM" == "Terminal" ]; then - # XFCE Terminal - export TERM="xterm-256color" -elif [ "$COLORTERM" == "xfce4-terminal" ]; then - export TERM="xterm-256color" -elif [ "$FBTERM" == "1" ]; then - export TERM="fbterm" -elif [ "$TERM" == "xterm" ]; then - # If shell reports just 'xterm', it may be PuTTY - if [ -e ~/bin/answerback ]; then - export ANSWERBACK=$(~/bin/answerback) - if [ "x$ANSWERBACK" == "xPuTTY" ]; then - export TERM="xterm-256color" - export COLORTERM="putty-256color" - export LANG="C" - fi - fi -fi - -if [ "$TERMINAL_OVERRIDE" != "" ]; then - # Some things just refuse to accept their own - # configuration options for these things. - export TERM=$TERMINAL_OVERRIDE -fi - -# Tango palette for framebuffers -function color_palette () { - echo -en "\e]P02e3436" #black - echo -en "\e]P8555753" #darkgray - echo -en "\e]P1cc0000" #darkred - echo -en "\e]P9ef2929" #red - echo -en "\e]P24e9a06" #darkgreen - echo -en "\e]PA8ae234" #green - echo -en "\e]P3c4a000" #brown - echo -en "\e]PBfce94f" #yellow - echo -en "\e]P43465a4" #darkblue - echo -en "\e]PC729fcf" #blue - echo -en "\e]P575507b" #darkmagenta - echo -en "\e]PDad7fa8" #magenta - echo -en "\e]P606989a" #darkcyan - echo -en "\e]PE34e2e2" #cyan - echo -en "\e]P7ffffff" #lightgray - echo -en "\e]PFeeeeec" #white -} -if [ "$TERM" == "linux" ]; then - color_palette -fi - -if [ "$TERM" == "screen-bce" ]; then - # I use screen under 256-color-supportive things - # far more often than not, so give me 256-colors - export TERM=screen-256color -fi - -# PROMPT -function prompt_command { - local RETURN_CODE="$?" - - local COLOR_P="\033[38;5;" - local COLOR_A="m" - if [ "$TERM" == "fbterm" ] ; then - COLOR_P="\033[1;" - COLOR_A="}" - fi - local SOFT_YELLOW="\[${COLOR_P}221$COLOR_A\]" - local MEDIUM_GRAY="\[${COLOR_P}59$COLOR_A\]" - local SOFT_BLUE="\[${COLOR_P}81$COLOR_A\]" - local LIGHT_GRAY="\[${COLOR_P}188$COLOR_A\]" - local LIGHT_GOLD="\[${COLOR_P}222$COLOR_A\]" - local MEDIUM_ORANGE="\[${COLOR_P}173$COLOR_A\]" - local MEDIUM_RED="\[${COLOR_P}167$COLOR_A\]" - local MEDIUM_GREEN="\[${COLOR_P}47$COLOR_A\]" - local BRIGHT_RED="\[${COLOR_P}196$COLOR_A\]" - local LIGHT_PURPLE="\[${COLOR_P}177$COLOR_A\]" - local RESET="\[\033[0m\]" - local BOLD="\[\033[1m\]" - local SAVE="\[\033[s\]" - local RESTORE="\[\033[u\]" - - if [ "$TERM" == "linux" ] ; then - SOFT_YELLOW="\[\033[1;33m\]" - MEDIUM_GRAY="\[\033[1;30m\]" - SOFT_BLUE="\[\033[1;34m\]" - LIGHT_GRAY="\[\033[1;30m\]" - LIGHT_GOLD="\[\033[1;33m\]" - MEDIUM_ORANGE="\[\033[1;33m\]" - MEDIUM_RED="\[\033[1;31m\]" - MEDIUM_GREEN="\[\033[1;32m\]" - BRIGHT_RED="\[\033[1;31m\]" - LIGHT_PURPLE="\[\033[1;35m\]" - fi - - local ALIGN_LEFT="\033[1G" - local ALIGN_RIGHT="\033[400C" - local MAKE_SPACE="\033[16D" - - local DATE_STRING="\D{%m/%d}" - local TIME_STRING="\t" - - local CURRENT_PATH="\w" - if [ -e ~/bin/shorten_pwd ] ; then - CURRENT_PATH=`~/bin/shorten_pwd` - fi - - local TITLEBAR="" - case $TERM in - xterm*|*rxvt*|cygwin|interix|Eterm|mlterm|kterm|aterm|putty*) - if [ "${STY}" ] ; then - TITLEBAR="\[\ek\u@\h:$CURRENT_PATH\e\134\]" - else - TITLEBAR="\[\e]1;\u@\h:$CURRENT_PATH\007\e]2;\u@\h:$CURRENT_PATH\007\]" - fi - ;; - toaru*) - TITLEBAR="\[\e]1;\u@\h:$CURRENT_PATH\007\]" - ;; - screen*) - TITLEBAR="\[\ek\u@\h:$CURRENT_PATH\e\134\]" - ;; - esac - - local PROMPT_COLOR="$MEDIUM_GREEN" - if [[ ${EUID} == 0 ]] ; then - PROMPT_COLOR="$BRIGHT_RED" - fi - - local PROMPT="$BOLD" - PROMPT="$PROMPT$SAVE\[$ALIGN_RIGHT$MAKE_SPACE\]" # Ram the cursor to the right, then back 16 spaces - PROMPT="$PROMPT$MEDIUM_GRAY\[[\]$MEDIUM_ORANGE\[$DATE_STRING \]$MEDIUM_RED\[$TIME_STRING\]$MEDIUM_GRAY\[]\]" - PROMPT="$PROMPT$RESTORE" # Reset the cursor to the left side - PROMPT="$PROMPT$SOFT_YELLOW\u$MEDIUM_GRAY@$SOFT_BLUE\h " - - if [ $KLANGE_USE_GIT == true ]; then - local GIT_STATUS="$(git status 2>/dev/null)" - if [[ $GIT_STATUS != "" ]] ; then - local REFS="$(git symbolic-ref HEAD 2>/dev/null | sed 's/.*\///')" - REFS="$LIGHT_GOLD${REFS#refs/heads/}" - if [[ `echo $GIT_STATUS | grep "modified:"` != "" ]] ; then - REFS="$REFS$LIGHT_PURPLE*" # Modified - elif [[ `echo $GIT_STATUS | grep "renamed:"` != "" ]] ; then - REFS="$REFS$LIGHT_PURPLE*" # Modified as well - fi - if [[ `echo $GIT_STATUS | grep "ahead of"` != "" ]] ; then - REFS="$REFS$SOFT_BLUE^" # Staged - fi - PROMPT="$PROMPT$REFS " - fi - fi - - if [[ $RETURN_CODE != 0 ]] ; then - PROMPT="$PROMPT$MEDIUM_RED$RETURN_CODE " - fi - - PROMPT="$PROMPT$RESET$LIGHT_GRAY$CURRENT_PATH$BOLD$PROMPT_COLOR\\\$ $RESET" - PS1="$TITLEBAR$PROMPT" -} - -export PROMPT_COMMAND=prompt_command - -# COLOR SUPPOORT - -if [ -x /usr/bin/dircolors ]; then - eval "`dircolors -b`" - alias ls='ls --color=auto' -fi - -# TAB COMPLETION - -if [ -f /etc/bash_completion ]; then - . /etc/bash_completion -fi - -# Extra aliases -if [ -e ~/.bash_aliases ]; then - . ~/.bash_aliases -fi - -alias :qall="echo \"This isn't vim :P\" && exit" diff --git a/hdd/home/local/.desktop.conf b/hdd/home/local/.desktop.conf deleted file mode 100644 index 917d6721..00000000 --- a/hdd/home/local/.desktop.conf +++ /dev/null @@ -1,2 +0,0 @@ -# Configuration file for desktop, use to set wallpapers. -# wallpaper=/usr/share/wallpapers.default.png diff --git a/hdd/home/local/.dummy b/hdd/home/local/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/hdd/home/local/.weather.json b/hdd/home/local/.weather.json deleted file mode 100644 index 32acd37b..00000000 --- a/hdd/home/local/.weather.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "comment": "You can edit this file to set your own city using the weather_update.py tool." -} diff --git a/hdd/home/root/.dummy b/hdd/home/root/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/hdd/mnt/.dummy b/hdd/mnt/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/hdd/mod/.placeholder b/hdd/mod/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/hdd/proc/.dummy b/hdd/proc/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/hdd/tmp/.dummy b/hdd/tmp/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/hdd/usr/share/cursor/drag.png b/hdd/usr/share/cursor/drag.png deleted file mode 100644 index 54c05076..00000000 Binary files a/hdd/usr/share/cursor/drag.png and /dev/null differ diff --git a/hdd/usr/share/cursor/normal.png b/hdd/usr/share/cursor/normal.png deleted file mode 100644 index 813e2f31..00000000 Binary files a/hdd/usr/share/cursor/normal.png and /dev/null differ diff --git a/hdd/usr/share/cursor/resize-dlur.png b/hdd/usr/share/cursor/resize-dlur.png deleted file mode 100644 index 785e6fc7..00000000 Binary files a/hdd/usr/share/cursor/resize-dlur.png and /dev/null differ diff --git a/hdd/usr/share/cursor/resize-horizontal.png b/hdd/usr/share/cursor/resize-horizontal.png deleted file mode 100644 index 20888504..00000000 Binary files a/hdd/usr/share/cursor/resize-horizontal.png and /dev/null differ diff --git a/hdd/usr/share/cursor/resize-uldr.png b/hdd/usr/share/cursor/resize-uldr.png deleted file mode 100644 index 884c910f..00000000 Binary files a/hdd/usr/share/cursor/resize-uldr.png and /dev/null differ diff --git a/hdd/usr/share/cursor/resize-vertical.png b/hdd/usr/share/cursor/resize-vertical.png deleted file mode 100644 index eab8421f..00000000 Binary files a/hdd/usr/share/cursor/resize-vertical.png and /dev/null differ diff --git a/hdd/usr/share/decors/demo/active.png b/hdd/usr/share/decors/demo/active.png deleted file mode 100644 index f966d8e8..00000000 Binary files a/hdd/usr/share/decors/demo/active.png and /dev/null differ diff --git a/hdd/usr/share/decors/demo/close-active.png b/hdd/usr/share/decors/demo/close-active.png deleted file mode 100644 index bd22aa29..00000000 Binary files a/hdd/usr/share/decors/demo/close-active.png and /dev/null differ diff --git a/hdd/usr/share/decors/demo/close-inactive.png b/hdd/usr/share/decors/demo/close-inactive.png deleted file mode 100644 index 24d12da6..00000000 Binary files a/hdd/usr/share/decors/demo/close-inactive.png and /dev/null differ diff --git a/hdd/usr/share/decors/demo/decor.conf b/hdd/usr/share/decors/demo/decor.conf deleted file mode 100644 index 4aed9e6e..00000000 --- a/hdd/usr/share/decors/demo/decor.conf +++ /dev/null @@ -1,18 +0,0 @@ -[upper] -height=27 -left=27 -right=27 - -[middle] -height=27 -left=27 -right=27 - -[lower] -height=27 -left=27 -right=27 - -[close] -top=10 -right=10 diff --git a/hdd/usr/share/decors/demo/inactive.png b/hdd/usr/share/decors/demo/inactive.png deleted file mode 100644 index 36f65096..00000000 Binary files a/hdd/usr/share/decors/demo/inactive.png and /dev/null differ diff --git a/hdd/usr/share/fonts/DejaVuSans-Bold.ttf b/hdd/usr/share/fonts/DejaVuSans-Bold.ttf deleted file mode 100644 index 9b19d548..00000000 Binary files a/hdd/usr/share/fonts/DejaVuSans-Bold.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/DejaVuSans-BoldOblique.ttf b/hdd/usr/share/fonts/DejaVuSans-BoldOblique.ttf deleted file mode 100644 index d784804c..00000000 Binary files a/hdd/usr/share/fonts/DejaVuSans-BoldOblique.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/DejaVuSans-Oblique.ttf b/hdd/usr/share/fonts/DejaVuSans-Oblique.ttf deleted file mode 100644 index 2abd4a76..00000000 Binary files a/hdd/usr/share/fonts/DejaVuSans-Oblique.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/DejaVuSans.ttf b/hdd/usr/share/fonts/DejaVuSans.ttf deleted file mode 100644 index 428e3836..00000000 Binary files a/hdd/usr/share/fonts/DejaVuSans.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/DejaVuSansMono-Bold.ttf b/hdd/usr/share/fonts/DejaVuSansMono-Bold.ttf deleted file mode 100644 index aadc05a3..00000000 Binary files a/hdd/usr/share/fonts/DejaVuSansMono-Bold.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/DejaVuSansMono-BoldOblique.ttf b/hdd/usr/share/fonts/DejaVuSansMono-BoldOblique.ttf deleted file mode 100644 index 5d0c682e..00000000 Binary files a/hdd/usr/share/fonts/DejaVuSansMono-BoldOblique.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/DejaVuSansMono-Oblique.ttf b/hdd/usr/share/fonts/DejaVuSansMono-Oblique.ttf deleted file mode 100644 index d95c17e4..00000000 Binary files a/hdd/usr/share/fonts/DejaVuSansMono-Oblique.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/DejaVuSansMono.ttf b/hdd/usr/share/fonts/DejaVuSansMono.ttf deleted file mode 100644 index 27b7bba2..00000000 Binary files a/hdd/usr/share/fonts/DejaVuSansMono.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/Symbola.ttf b/hdd/usr/share/fonts/Symbola.ttf deleted file mode 100644 index 3aa73501..00000000 Binary files a/hdd/usr/share/fonts/Symbola.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/VLGothic.ttf b/hdd/usr/share/fonts/VLGothic.ttf deleted file mode 100644 index e4d4f68b..00000000 Binary files a/hdd/usr/share/fonts/VLGothic.ttf and /dev/null differ diff --git a/hdd/usr/share/fonts/VLPGothic.ttf b/hdd/usr/share/fonts/VLPGothic.ttf deleted file mode 100644 index 63f7efb2..00000000 Binary files a/hdd/usr/share/fonts/VLPGothic.ttf and /dev/null differ diff --git a/hdd/usr/share/help/downloaded/.dummy b/hdd/usr/share/help/downloaded/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/hdd/usr/share/help/licenses/cairo_blur.trt b/hdd/usr/share/help/licenses/cairo_blur.trt deleted file mode 100644 index 969d5968..00000000 --- a/hdd/usr/share/help/licenses/cairo_blur.trt +++ /dev/null @@ -1,24 +0,0 @@ - -

Cairo Gaussian Blur

- -Copyright © 2008 Kristian Høgsberg -Copyright © 2009 Chris Wilson - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that copyright -notice and this permission notice appear in supporting documentation, and -that the name of the copyright holders not be used in advertising or -publicity pertaining to distribution of the software without specific, -written prior permission. The copyright holders make no representations -about the suitability of this software for any purpose. It is provided "as -is" without express or implied warranty. - -THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO -EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR -CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -OF THIS SOFTWARE. - diff --git a/hdd/usr/share/help/licenses/cpudet.trt b/hdd/usr/share/help/licenses/cpudet.trt deleted file mode 100644 index 13afd298..00000000 --- a/hdd/usr/share/help/licenses/cpudet.trt +++ /dev/null @@ -1,28 +0,0 @@ - -

cpudet

- -Copyright (c) 2006-2007 - http://brynet.biz.tm - <brynet@gmail.com> -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/hdd/usr/share/help/licenses/curses.trt b/hdd/usr/share/help/licenses/curses.trt deleted file mode 100644 index d37d9705..00000000 --- a/hdd/usr/share/help/licenses/curses.trt +++ /dev/null @@ -1,31 +0,0 @@ - -

Curses / ncurses

- -------------------------------------------------------------------------------- --- Copyright (c) 1998-2004,2006 Free Software Foundation, Inc. -- --- -- --- Permission is hereby granted, free of charge, to any person obtaining a -- --- copy of this software and associated documentation files (the -- --- "Software"), to deal in the Software without restriction, including -- --- without limitation the rights to use, copy, modify, merge, publish, -- --- distribute, distribute with modifications, sublicense, and/or sell copies -- --- of the Software, and to permit persons to whom the Software is furnished -- --- to do so, subject to the following conditions: -- --- -- --- The above copyright notice and this permission notice shall be included -- --- in all copies or substantial portions of the Software. -- --- -- --- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -- --- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -- --- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -- --- NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -- --- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -- --- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -- --- USE OR OTHER DEALINGS IN THE SOFTWARE. -- --- -- --- Except as contained in this notice, the name(s) of the above copyright -- --- holders shall not be used in advertising or otherwise to promote the -- --- sale, use or other dealings in this Software without prior written -- --- authorization. -- -------------------------------------------------------------------------------- - diff --git a/hdd/usr/share/help/licenses/curses_demos.trt b/hdd/usr/share/help/licenses/curses_demos.trt deleted file mode 100644 index 8ca9ad58..00000000 --- a/hdd/usr/share/help/licenses/curses_demos.trt +++ /dev/null @@ -1,26 +0,0 @@ - -

Curses Demos

- -Copyright © 2001 by Pradeep Padala. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, distribute with modifications, -sublicense, and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name(s) of the above copyright holders -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization. - diff --git a/hdd/usr/share/help/licenses/gears.trt b/hdd/usr/share/help/licenses/gears.trt deleted file mode 100644 index ad78a8d4..00000000 --- a/hdd/usr/share/help/licenses/gears.trt +++ /dev/null @@ -1,23 +0,0 @@ - -

GL Gears

- -Copyright (C) 1999-2001 Brian Paul All Rights Reserved. - 2013 Kevin Lange - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/hdd/usr/share/help/licenses/mesa.trt b/hdd/usr/share/help/licenses/mesa.trt deleted file mode 100644 index bdcacf02..00000000 --- a/hdd/usr/share/help/licenses/mesa.trt +++ /dev/null @@ -1,22 +0,0 @@ - -

Mesa

- -Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/hdd/usr/share/help/licenses/newlib.trt b/hdd/usr/share/help/licenses/newlib.trt deleted file mode 100644 index b2812c01..00000000 --- a/hdd/usr/share/help/licenses/newlib.trt +++ /dev/null @@ -1,955 +0,0 @@ - -

Newlib

- -The newlib subdirectory is a collection of software from several sources. - -Each file may have its own copyright/license that is embedded in the source file. Unless otherwise noted in the body of the source file(s), the following copyright notices will apply to the contents of the newlib subdirectory: - - -(1) Red Hat Incorporated - -Copyright (c) 1994-2009 Red Hat, Inc. All rights reserved. - -This copyrighted material is made available to anyone wishing to use, -modify, copy, or redistribute it subject to the terms and conditions -of the BSD License. This program is distributed in the hope that -it will be useful, but WITHOUT ANY WARRANTY expressed or implied, -including the implied warranties of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. A copy of this license is available at -http://www.opensource.org/licenses. Any Red Hat trademarks that are -incorporated in the source code or documentation are not subject to -the BSD License and may only be used or replicated with the express -permission of Red Hat, Inc. - -(2) University of California, Berkeley - -Copyright (c) 1981-2000 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -OF SUCH DAMAGE. - -(3) David M. Gay (AT&T 1991, Lucent 1998) - -The author of this software is David M. Gay. - -Copyright (c) 1991 by AT&T. - -Permission to use, copy, modify, and distribute this software for any -purpose without fee is hereby granted, provided that this entire notice -is included in all copies of any software which is or includes a copy -or modification of this software and in all copies of the supporting -documentation for such software. - -THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY -REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY -OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - -------------------------------------------------------------------- - -The author of this software is David M. Gay. - -Copyright (C) 1998-2001 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - - -(4) Advanced Micro Devices - -Copyright 1989, 1990 Advanced Micro Devices, Inc. - -This software is the property of Advanced Micro Devices, Inc (AMD) which -specifically grants the user the right to modify, use and distribute this -software provided this notice is not removed or altered. All other rights -are reserved by AMD. - -AMD MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS -SOFTWARE. IN NO EVENT SHALL AMD BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL -DAMAGES IN CONNECTION WITH OR ARISING FROM THE FURNISHING, PERFORMANCE, OR -USE OF THIS SOFTWARE. - -So that all may benefit from your experience, please report any problems -or suggestions about this software to the 29K Technical Support Center at -800-29-29-AMD (800-292-9263) in the USA, or 0800-89-1131 in the UK, or -0031-11-1129 in Japan, toll free. The direct dial number is 512-462-4118. - -Advanced Micro Devices, Inc. -29K Support Products -Mail Stop 573 -5900 E. Ben White Blvd. -Austin, TX 78741 -800-292-9263 - -(5) - -(6) - -(7) Sun Microsystems - -Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - -Developed at SunPro, a Sun Microsystems, Inc. business. -Permission to use, copy, modify, and distribute this -software is freely granted, provided that this notice is preserved. - -(8) Hewlett Packard - -(c) Copyright 1986 HEWLETT-PACKARD COMPANY - -To anyone who acknowledges that this file is provided "AS IS" -without any express or implied warranty: - permission to use, copy, modify, and distribute this file -for any purpose is hereby granted without fee, provided that -the above copyright notice and this notice appears in all -copies, and that the name of Hewlett-Packard Company not be -used in advertising or publicity pertaining to distribution -of the software without specific, written prior permission. -Hewlett-Packard Company makes no representations about the -suitability of this software for any purpose. - -(9) Hans-Peter Nilsson - -Copyright (C) 2001 Hans-Peter Nilsson - -Permission to use, copy, modify, and distribute this software is -freely granted, provided that the above copyright notice, this notice -and the following disclaimer are preserved with no changes. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. - -(10) Stephane Carrez (m68hc11-elf/m68hc12-elf targets only) - -Copyright (C) 1999, 2000, 2001, 2002 Stephane Carrez (stcarrez@nerim.fr) - -The authors hereby grant permission to use, copy, modify, distribute, -and license this software and its documentation for any purpose, provided -that existing copyright notices are retained in all copies and that this -notice is included verbatim in any distributions. No written agreement, -license, or royalty fee is required for any of the authorized uses. -Modifications to this software may be copyrighted by their authors -and need not follow the licensing terms described here, provided that -the new terms are clearly indicated on the first page of each file where -they apply. - -(11) Christopher G. Demetriou - -Copyright (c) 2001 Christopher G. Demetriou -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -(12) SuperH, Inc. - -Copyright 2002 SuperH, Inc. All rights reserved - -This software is the property of SuperH, Inc (SuperH) which specifically -grants the user the right to modify, use and distribute this software -provided this notice is not removed or altered. All other rights are -reserved by SuperH. - -SUPERH MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO -THIS SOFTWARE. IN NO EVENT SHALL SUPERH BE LIABLE FOR INDIRECT, SPECIAL, -INCIDENTAL OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING FROM -THE FURNISHING, PERFORMANCE, OR USE OF THIS SOFTWARE. - -So that all may benefit from your experience, please report any problems -or suggestions about this software to the SuperH Support Center via -e-mail at softwaresupport@superh.com . - -SuperH, Inc. -405 River Oaks Parkway -San Jose -CA 95134 -USA - -(13) Royal Institute of Technology - -Copyright (c) 1999 Kungliga Tekniska Högskolan -(Royal Institute of Technology, Stockholm, Sweden). -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of KTH nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -(14) Alexey Zelkin - -Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -(15) Andrey A. Chernov - -Copyright (C) 1997 by Andrey A. Chernov, Moscow, Russia. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -(16) FreeBSD - -Copyright (c) 1997-2002 FreeBSD Project. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -(17) S. L. Moshier - -Author: S. L. Moshier. - -Copyright (c) 1984,2000 S.L. Moshier - -Permission to use, copy, modify, and distribute this software for any -purpose without fee is hereby granted, provided that this entire notice -is included in all copies of any software which is or includes a copy -or modification of this software and in all copies of the supporting -documentation for such software. - -THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION -OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS -SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - -(18) Citrus Project - -Copyright (c)1999 Citrus Project, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -(19) Todd C. Miller - -Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -(20) DJ Delorie (i386) -Copyright (C) 1991 DJ Delorie -All rights reserved. - -Redistribution, modification, and use in source and binary forms is permitted -provided that the above copyright notice and following paragraph are -duplicated in all such forms. - -This file is distributed WITHOUT ANY WARRANTY; without even the implied -warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -(21) Free Software Foundation LGPL License (*-linux* targets only) - - Copyright (C) 1990-1999, 2000, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 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., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. - -(22) Xavier Leroy LGPL License (i[3456]86-*-linux* targets only) - -Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Library General Public License for more details. - -(23) Intel (i960) - -Copyright (c) 1993 Intel Corporation - -Intel hereby grants you permission to copy, modify, and distribute this -software and its documentation. Intel grants this permission provided -that the above copyright notice appears in all copies and that both the -copyright notice and this permission notice appear in supporting -documentation. In addition, Intel grants this permission provided that -you prominently mark as "not part of the original" any modifications -made to this software or documentation, and that the name of Intel -Corporation not be used in advertising or publicity pertaining to -distribution of the software or the documentation without specific, -written prior permission. - -Intel Corporation provides this AS IS, WITHOUT ANY WARRANTY, EXPRESS OR -IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY -OR FITNESS FOR A PARTICULAR PURPOSE. Intel makes no guarantee or -representations regarding the use of, or the results of the use of, -the software and documentation in terms of correctness, accuracy, -reliability, currentness, or otherwise; and you rely on the software, -documentation and results solely at your own risk. - -IN NO EVENT SHALL INTEL BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS, -LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES -OF ANY KIND. IN NO EVENT SHALL INTEL'S TOTAL LIABILITY EXCEED THE SUM -PAID TO INTEL FOR THE PRODUCT LICENSED HEREUNDER. - -(24) Hewlett-Packard (hppa targets only) - -(c) Copyright 1986 HEWLETT-PACKARD COMPANY - -To anyone who acknowledges that this file is provided "AS IS" -without any express or implied warranty: - permission to use, copy, modify, and distribute this file -for any purpose is hereby granted without fee, provided that -the above copyright notice and this notice appears in all -copies, and that the name of Hewlett-Packard Company not be -used in advertising or publicity pertaining to distribution -of the software without specific, written prior permission. -Hewlett-Packard Company makes no representations about the -suitability of this software for any purpose. - -(25) Henry Spencer (only *-linux targets) - -Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved. -This software is not subject to any license of the American Telephone -and Telegraph Company or of the Regents of the University of California. - -Permission is granted to anyone to use this software for any purpose on -any computer system, and to alter it and redistribute it, subject -to the following restrictions: - -1. The author is not responsible for the consequences of use of this - software, no matter how awful, even if they arise from flaws in it. - -2. The origin of this software must not be misrepresented, either by - explicit claim or by omission. Since few users ever read sources, - credits must appear in the documentation. - -3. Altered versions must be plainly marked as such, and must not be - misrepresented as being the original software. Since few users - ever read sources, credits must appear in the documentation. - -4. This notice may not be removed or altered. - -(26) Mike Barcroft - -Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -(27) Konstantin Chuguev (--enable-newlib-iconv) - -Copyright (c) 1999, 2000 - Konstantin Chuguev. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - - iconv (Charset Conversion Library) v2.0 - -(28) Artem Bityuckiy (--enable-newlib-iconv) - -Copyright (c) 2003, Artem B. Bityuckiy, SoftMine Corporation. -Rights transferred to Franklin Electronic Publishers. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -(29) IBM, Sony, Toshiba (only spu-* targets) - - (C) Copyright 2001,2006, - International Business Machines Corporation, - Sony Computer Entertainment, Incorporated, - Toshiba Corporation, - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the names of the copyright holders nor the names of their - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - -(30) - Alex Tatmanjants (targets using libc/posix) - - Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> - at Electronni Visti IA, Kiev, Ukraine. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -(31) - M. Warner Losh (targets using libc/posix) - - Copyright (c) 1998, M. Warner Losh <imp@freebsd.org> - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -(32) - Andrey A. Chernov (targets using libc/posix) - - Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -(33) - Daniel Eischen (targets using libc/posix) - - Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - -(34) - Jon Beniston (only lm32-* targets) - - Contributed by Jon Beniston <jon@beniston.com> - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - -(35) - ARM Ltd (arm and thumb variant targets only) - - Copyright (c) 2009 ARM Ltd - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the company may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -(36) - Xilinx, Inc. (microblaze-* and powerpc-* targets) - -Copyright (c) 2004, 2009 Xilinx, Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -3. Neither the name of Xilinx nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -(37) Texas Instruments Incorporated (tic6x-*, *-tirtos targets) - -Copyright (c) 1996-2010,2014 Texas Instruments Incorporated -http://www.ti.com/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - Neither the name of Texas Instruments Incorporated nor the names - of its contributors may be used to endorse or promote products - derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -(38) National Semiconductor (cr16-* and crx-* targets) - -Copyright (c) 2004 National Semiconductor Corporation - -The authors hereby grant permission to use, copy, modify, distribute, -and license this software and its documentation for any purpose, provided -that existing copyright notices are retained in all copies and that this -notice is included verbatim in any distributions. No written agreement, -license, or royalty fee is required for any of the authorized uses. -Modifications to this software may be copyrighted by their authors -and need not follow the licensing terms described here, provided that -the new terms are clearly indicated on the first page of each file where -they apply. - -(39) - Adapteva, Inc. (epiphany-* targets) - -Copyright (c) 2011, Adapteva, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Adapteva nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -(40) - Altera Corportion (nios2-* targets) - -Copyright (c) 2003 Altera Corporation -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - o Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - o Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - o Neither the name of Altera Corporation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY ALTERA CORPORATION, THE COPYRIGHT HOLDER, -AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -(41) Ed Schouten - Free BSD - -Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - diff --git a/hdd/usr/share/help/licenses/pci_list.trt b/hdd/usr/share/help/licenses/pci_list.trt deleted file mode 100644 index 0435f247..00000000 --- a/hdd/usr/share/help/licenses/pci_list.trt +++ /dev/null @@ -1,21 +0,0 @@ - -

PCI device and vendor names

- -PCIHDR.H: PCI Vendors, Devices, and Class Type information - -Created automatically from the web using the following URL: -http://pcidatabase.com/ -Software to create and maintain the PCICODE List written by: -Jim Boemler (jboemler@halcyon.com) - - This header created on Fri Jan 16 09:49:40 PST 2009 - -Too many people have contributed to this list to acknowledge them all, but -a few have provided the majority of the input and deserve special mention: - Frederic Potter, who maintains a list for Linux. - Chris Aston at Madge Networks. - Thomas Dippon of Hewlett-Packard GmbH. - Jurgen ("Josh") Thelen - William H. Avery III at Altitech - Sergei Shtylyov of Brain-dead Software in Russia - diff --git a/hdd/usr/share/help/licenses/png.trt b/hdd/usr/share/help/licenses/png.trt deleted file mode 100644 index a7b27df6..00000000 --- a/hdd/usr/share/help/licenses/png.trt +++ /dev/null @@ -1,135 +0,0 @@ - -

libpng

- - -This copy of the libpng notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file png.h that is -included in the libpng distribution, the latter shall prevail. - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -If you modify libpng you may insert additional notices immediately following -this sentence. - -This code is released under the libpng license. - -libpng versions 1.0.7, July 1, 2000 through 1.6.28, January 5, 2017 are -Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are -derived from libpng-1.0.6, and are distributed according to the same -disclaimer and license as libpng-1.0.6 with the following individuals -added to the list of Contributing Authors: - - Simon-Pierre Cadieux - Eric S. Raymond - Mans Rullgard - Cosmin Truta - Gilles Vollant - James Yu - Mandar Sahastrabuddhe - -and with the following additions to the disclaimer: - - There is no warranty against interference with your enjoyment of the - library or against infringement. There is no warranty that our - efforts or the library will fulfill any of your particular purposes - or needs. This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and effort is with - the user. - -Some files in the "contrib" directory and some configure-generated -files that are distributed with libpng have other copyright owners and -are released under other open source licenses. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from -libpng-0.96, and are distributed according to the same disclaimer and -license as libpng-0.96, with the following individuals added to the list -of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, -and are distributed according to the same disclaimer and license as -libpng-0.88, with the following individuals added to the list of -Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -Some files in the "scripts" directory have other copyright owners -but are released under this license. - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - - 1. The origin of this source code must not be misrepresented. - - 2. Altered versions must be plainly marked as such and must not - be misrepresented as being the original source. - - 3. This Copyright notice may not be removed or altered from any - source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - -END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. - -TRADEMARK: - -The name "libpng" has not been registered by the Copyright owner -as a trademark in any jurisdiction. However, because libpng has -been distributed and maintained world-wide, continually since 1995, -the Copyright owner claims "common-law trademark protection" in any -jurisdiction where common-law trademark is recognized. - -OSI CERTIFICATION: - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is -a certification mark of the Open Source Initiative. OSI has not addressed -the additional disclaimers inserted at version 1.0.7. - -EXPORT CONTROL: - -The Copyright owner believes that the Export Control Classification -Number (ECCN) for libpng is EAR99, which means not subject to export -controls or International Traffic in Arms Regulations (ITAR) because -it is open source, publicly available software, that does not contain -any encryption software. See the EAR, paragraphs 734.3(b)(3) and -734.7(b). - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -January 5, 2017 - diff --git a/hdd/usr/share/help/licenses/sha2.trt b/hdd/usr/share/help/licenses/sha2.trt deleted file mode 100644 index 7148293e..00000000 --- a/hdd/usr/share/help/licenses/sha2.trt +++ /dev/null @@ -1,30 +0,0 @@ - -

SHA2 Library

- -Copyright (c) 2000-2001, Aaron D. Gifford -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of contributors -may be used to endorse or promote products derived from this software -without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - diff --git a/hdd/usr/share/help/licenses/utf8.trt b/hdd/usr/share/help/licenses/utf8.trt deleted file mode 100644 index f9ab3ee5..00000000 --- a/hdd/usr/share/help/licenses/utf8.trt +++ /dev/null @@ -1,22 +0,0 @@ - -

UTF8 decoder

- -Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/hdd/usr/share/help/licenses/zlib.trt b/hdd/usr/share/help/licenses/zlib.trt deleted file mode 100644 index b21bec28..00000000 --- a/hdd/usr/share/help/licenses/zlib.trt +++ /dev/null @@ -1,24 +0,0 @@ - -

zlib

- -Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - -Jean-loup Gailly Mark Adler -jloup@gzip.org madler@alumni.caltech.edu - diff --git a/hdd/usr/share/icons/16/applications-generic.png b/hdd/usr/share/icons/16/applications-generic.png deleted file mode 100644 index debd1985..00000000 Binary files a/hdd/usr/share/icons/16/applications-generic.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/back.png b/hdd/usr/share/icons/16/back.png deleted file mode 100644 index 2752026b..00000000 Binary files a/hdd/usr/share/icons/16/back.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/bookmark.png b/hdd/usr/share/icons/16/bookmark.png deleted file mode 100644 index fece39b7..00000000 Binary files a/hdd/usr/share/icons/16/bookmark.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/calculator.png b/hdd/usr/share/icons/16/calculator.png deleted file mode 100644 index 5fa3c6f6..00000000 Binary files a/hdd/usr/share/icons/16/calculator.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/clock.png b/hdd/usr/share/icons/16/clock.png deleted file mode 100644 index 12502268..00000000 Binary files a/hdd/usr/share/icons/16/clock.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/config.png b/hdd/usr/share/icons/16/config.png deleted file mode 100644 index b8932b7b..00000000 Binary files a/hdd/usr/share/icons/16/config.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/file.png b/hdd/usr/share/icons/16/file.png deleted file mode 100644 index b976e6ae..00000000 Binary files a/hdd/usr/share/icons/16/file.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/folder.png b/hdd/usr/share/icons/16/folder.png deleted file mode 100644 index c1e43da2..00000000 Binary files a/hdd/usr/share/icons/16/folder.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/forward.png b/hdd/usr/share/icons/16/forward.png deleted file mode 100644 index 3b299220..00000000 Binary files a/hdd/usr/share/icons/16/forward.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/help.png b/hdd/usr/share/icons/16/help.png deleted file mode 100644 index 0e171cf6..00000000 Binary files a/hdd/usr/share/icons/16/help.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/home.png b/hdd/usr/share/icons/16/home.png deleted file mode 100644 index cb6c9d58..00000000 Binary files a/hdd/usr/share/icons/16/home.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/mines.png b/hdd/usr/share/icons/16/mines.png deleted file mode 100644 index 8bb58c28..00000000 Binary files a/hdd/usr/share/icons/16/mines.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/missing.png b/hdd/usr/share/icons/16/missing.png deleted file mode 100644 index 0a81088c..00000000 Binary files a/hdd/usr/share/icons/16/missing.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/new.png b/hdd/usr/share/icons/16/new.png deleted file mode 100644 index 7d18cb1e..00000000 Binary files a/hdd/usr/share/icons/16/new.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/open.png b/hdd/usr/share/icons/16/open.png deleted file mode 100644 index 80c303af..00000000 Binary files a/hdd/usr/share/icons/16/open.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/package.png b/hdd/usr/share/icons/16/package.png deleted file mode 100644 index 06469804..00000000 Binary files a/hdd/usr/share/icons/16/package.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/refresh.png b/hdd/usr/share/icons/16/refresh.png deleted file mode 100644 index 3eea0007..00000000 Binary files a/hdd/usr/share/icons/16/refresh.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/save.png b/hdd/usr/share/icons/16/save.png deleted file mode 100644 index e6b947d8..00000000 Binary files a/hdd/usr/share/icons/16/save.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/star.png b/hdd/usr/share/icons/16/star.png deleted file mode 100644 index ef286409..00000000 Binary files a/hdd/usr/share/icons/16/star.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/up.png b/hdd/usr/share/icons/16/up.png deleted file mode 100644 index b3c20e0a..00000000 Binary files a/hdd/usr/share/icons/16/up.png and /dev/null differ diff --git a/hdd/usr/share/icons/16/utilities-terminal.png b/hdd/usr/share/icons/16/utilities-terminal.png deleted file mode 100644 index e93a33eb..00000000 Binary files a/hdd/usr/share/icons/16/utilities-terminal.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/applications-generic.png b/hdd/usr/share/icons/24/applications-generic.png deleted file mode 100644 index 641761c2..00000000 Binary files a/hdd/usr/share/icons/24/applications-generic.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/applications-painting.png b/hdd/usr/share/icons/24/applications-painting.png deleted file mode 100644 index 6b92ba7b..00000000 Binary files a/hdd/usr/share/icons/24/applications-painting.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/applications-simulation.png b/hdd/usr/share/icons/24/applications-simulation.png deleted file mode 100644 index f474cb25..00000000 Binary files a/hdd/usr/share/icons/24/applications-simulation.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/calculator.png b/hdd/usr/share/icons/24/calculator.png deleted file mode 100644 index e3931737..00000000 Binary files a/hdd/usr/share/icons/24/calculator.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/clock.png b/hdd/usr/share/icons/24/clock.png deleted file mode 100644 index abb2cac3..00000000 Binary files a/hdd/usr/share/icons/24/clock.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/drawlines.png b/hdd/usr/share/icons/24/drawlines.png deleted file mode 100644 index ecc1b9a7..00000000 Binary files a/hdd/usr/share/icons/24/drawlines.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/exit.png b/hdd/usr/share/icons/24/exit.png deleted file mode 100644 index 4d1a5d5d..00000000 Binary files a/hdd/usr/share/icons/24/exit.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/file.png b/hdd/usr/share/icons/24/file.png deleted file mode 100644 index 1ac29c57..00000000 Binary files a/hdd/usr/share/icons/24/file.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/folder.png b/hdd/usr/share/icons/24/folder.png deleted file mode 100644 index 41c5fab2..00000000 Binary files a/hdd/usr/share/icons/24/folder.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/gears.png b/hdd/usr/share/icons/24/gears.png deleted file mode 100644 index 701c0f58..00000000 Binary files a/hdd/usr/share/icons/24/gears.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/help.png b/hdd/usr/share/icons/24/help.png deleted file mode 100644 index 1744d051..00000000 Binary files a/hdd/usr/share/icons/24/help.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/julia.png b/hdd/usr/share/icons/24/julia.png deleted file mode 100644 index 8b457d6b..00000000 Binary files a/hdd/usr/share/icons/24/julia.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/mouse-relative.png b/hdd/usr/share/icons/24/mouse-relative.png deleted file mode 100644 index 553ea514..00000000 Binary files a/hdd/usr/share/icons/24/mouse-relative.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/mouse-status.png b/hdd/usr/share/icons/24/mouse-status.png deleted file mode 100644 index d3ab6f33..00000000 Binary files a/hdd/usr/share/icons/24/mouse-status.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/net-active.png b/hdd/usr/share/icons/24/net-active.png deleted file mode 100644 index d778416b..00000000 Binary files a/hdd/usr/share/icons/24/net-active.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/net-disconnected.png b/hdd/usr/share/icons/24/net-disconnected.png deleted file mode 100644 index ac2be5bf..00000000 Binary files a/hdd/usr/share/icons/24/net-disconnected.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/package.png b/hdd/usr/share/icons/24/package.png deleted file mode 100644 index 909be463..00000000 Binary files a/hdd/usr/share/icons/24/package.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/pixman-demo.png b/hdd/usr/share/icons/24/pixman-demo.png deleted file mode 100644 index a2ec9511..00000000 Binary files a/hdd/usr/share/icons/24/pixman-demo.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/plasma.png b/hdd/usr/share/icons/24/plasma.png deleted file mode 100644 index 46951e99..00000000 Binary files a/hdd/usr/share/icons/24/plasma.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/select-wallpaper.png b/hdd/usr/share/icons/24/select-wallpaper.png deleted file mode 100644 index 4f919f3b..00000000 Binary files a/hdd/usr/share/icons/24/select-wallpaper.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/snow.png b/hdd/usr/share/icons/24/snow.png deleted file mode 100644 index 45b8f202..00000000 Binary files a/hdd/usr/share/icons/24/snow.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/star.png b/hdd/usr/share/icons/24/star.png deleted file mode 100644 index 36dc9463..00000000 Binary files a/hdd/usr/share/icons/24/star.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/utilities-terminal.png b/hdd/usr/share/icons/24/utilities-terminal.png deleted file mode 100644 index 73eb306b..00000000 Binary files a/hdd/usr/share/icons/24/utilities-terminal.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/volume-full.png b/hdd/usr/share/icons/24/volume-full.png deleted file mode 100644 index dd46a911..00000000 Binary files a/hdd/usr/share/icons/24/volume-full.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/volume-low.png b/hdd/usr/share/icons/24/volume-low.png deleted file mode 100644 index b001c5a8..00000000 Binary files a/hdd/usr/share/icons/24/volume-low.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/volume-medium.png b/hdd/usr/share/icons/24/volume-medium.png deleted file mode 100644 index 9c9c5a5e..00000000 Binary files a/hdd/usr/share/icons/24/volume-medium.png and /dev/null differ diff --git a/hdd/usr/share/icons/24/volume-mute.png b/hdd/usr/share/icons/24/volume-mute.png deleted file mode 100644 index f169e613..00000000 Binary files a/hdd/usr/share/icons/24/volume-mute.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/applications-generic.png b/hdd/usr/share/icons/48/applications-generic.png deleted file mode 100644 index c180ad93..00000000 Binary files a/hdd/usr/share/icons/48/applications-generic.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/applications-painting.png b/hdd/usr/share/icons/48/applications-painting.png deleted file mode 100644 index c2a2afbc..00000000 Binary files a/hdd/usr/share/icons/48/applications-painting.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/applications-simulation.png b/hdd/usr/share/icons/48/applications-simulation.png deleted file mode 100644 index 26f58aa4..00000000 Binary files a/hdd/usr/share/icons/48/applications-simulation.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/calculator.png b/hdd/usr/share/icons/48/calculator.png deleted file mode 100644 index 954df6b3..00000000 Binary files a/hdd/usr/share/icons/48/calculator.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/clock.png b/hdd/usr/share/icons/48/clock.png deleted file mode 100644 index 085e5eb6..00000000 Binary files a/hdd/usr/share/icons/48/clock.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/drawlines.png b/hdd/usr/share/icons/48/drawlines.png deleted file mode 100644 index 6b5c7b8d..00000000 Binary files a/hdd/usr/share/icons/48/drawlines.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/exit.png b/hdd/usr/share/icons/48/exit.png deleted file mode 100644 index 40b73f14..00000000 Binary files a/hdd/usr/share/icons/48/exit.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/file.png b/hdd/usr/share/icons/48/file.png deleted file mode 100644 index cb27f1f6..00000000 Binary files a/hdd/usr/share/icons/48/file.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/folder.png b/hdd/usr/share/icons/48/folder.png deleted file mode 100644 index d6a9ff36..00000000 Binary files a/hdd/usr/share/icons/48/folder.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/gears.png b/hdd/usr/share/icons/48/gears.png deleted file mode 100644 index 1d802baf..00000000 Binary files a/hdd/usr/share/icons/48/gears.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/help.png b/hdd/usr/share/icons/48/help.png deleted file mode 100644 index 94d9d0ed..00000000 Binary files a/hdd/usr/share/icons/48/help.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/julia.png b/hdd/usr/share/icons/48/julia.png deleted file mode 100644 index 5a083f41..00000000 Binary files a/hdd/usr/share/icons/48/julia.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/mines.png b/hdd/usr/share/icons/48/mines.png deleted file mode 100644 index 1317555a..00000000 Binary files a/hdd/usr/share/icons/48/mines.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/package-uninstalled.png b/hdd/usr/share/icons/48/package-uninstalled.png deleted file mode 100644 index fe934629..00000000 Binary files a/hdd/usr/share/icons/48/package-uninstalled.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/package.png b/hdd/usr/share/icons/48/package.png deleted file mode 100644 index 79f3fbeb..00000000 Binary files a/hdd/usr/share/icons/48/package.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/pixman-demo.png b/hdd/usr/share/icons/48/pixman-demo.png deleted file mode 100644 index b92ddae3..00000000 Binary files a/hdd/usr/share/icons/48/pixman-demo.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/plasma.png b/hdd/usr/share/icons/48/plasma.png deleted file mode 100644 index 174cd844..00000000 Binary files a/hdd/usr/share/icons/48/plasma.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/select-wallpaper.png b/hdd/usr/share/icons/48/select-wallpaper.png deleted file mode 100644 index 513a59f3..00000000 Binary files a/hdd/usr/share/icons/48/select-wallpaper.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/snow.png b/hdd/usr/share/icons/48/snow.png deleted file mode 100644 index 38dba78d..00000000 Binary files a/hdd/usr/share/icons/48/snow.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/star.png b/hdd/usr/share/icons/48/star.png deleted file mode 100644 index 9fec85dc..00000000 Binary files a/hdd/usr/share/icons/48/star.png and /dev/null differ diff --git a/hdd/usr/share/icons/48/utilities-terminal.png b/hdd/usr/share/icons/48/utilities-terminal.png deleted file mode 100644 index 584907a2..00000000 Binary files a/hdd/usr/share/icons/48/utilities-terminal.png and /dev/null differ diff --git a/hdd/usr/share/icons/panel-shutdown.png b/hdd/usr/share/icons/panel-shutdown.png deleted file mode 100644 index 8cdf7c93..00000000 Binary files a/hdd/usr/share/icons/panel-shutdown.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/01d.png b/hdd/usr/share/icons/weather/01d.png deleted file mode 100644 index 2752e83f..00000000 Binary files a/hdd/usr/share/icons/weather/01d.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/01n.png b/hdd/usr/share/icons/weather/01n.png deleted file mode 100644 index 7fdd3319..00000000 Binary files a/hdd/usr/share/icons/weather/01n.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/02d.png b/hdd/usr/share/icons/weather/02d.png deleted file mode 100644 index 675345d7..00000000 Binary files a/hdd/usr/share/icons/weather/02d.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/02n.png b/hdd/usr/share/icons/weather/02n.png deleted file mode 100644 index 527f928d..00000000 Binary files a/hdd/usr/share/icons/weather/02n.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/03d.png b/hdd/usr/share/icons/weather/03d.png deleted file mode 120000 index 4568cc8a..00000000 --- a/hdd/usr/share/icons/weather/03d.png +++ /dev/null @@ -1 +0,0 @@ -02d.png \ No newline at end of file diff --git a/hdd/usr/share/icons/weather/03n.png b/hdd/usr/share/icons/weather/03n.png deleted file mode 120000 index d3dfe499..00000000 --- a/hdd/usr/share/icons/weather/03n.png +++ /dev/null @@ -1 +0,0 @@ -02n.png \ No newline at end of file diff --git a/hdd/usr/share/icons/weather/04d.png b/hdd/usr/share/icons/weather/04d.png deleted file mode 100644 index cd35ac0b..00000000 Binary files a/hdd/usr/share/icons/weather/04d.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/04n.png b/hdd/usr/share/icons/weather/04n.png deleted file mode 100644 index f32d7bdf..00000000 Binary files a/hdd/usr/share/icons/weather/04n.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/09d.png b/hdd/usr/share/icons/weather/09d.png deleted file mode 100644 index b4648a1d..00000000 Binary files a/hdd/usr/share/icons/weather/09d.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/09n.png b/hdd/usr/share/icons/weather/09n.png deleted file mode 120000 index cca1f5de..00000000 --- a/hdd/usr/share/icons/weather/09n.png +++ /dev/null @@ -1 +0,0 @@ -09d.png \ No newline at end of file diff --git a/hdd/usr/share/icons/weather/10d.png b/hdd/usr/share/icons/weather/10d.png deleted file mode 100644 index 7c15092d..00000000 Binary files a/hdd/usr/share/icons/weather/10d.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/10n.png b/hdd/usr/share/icons/weather/10n.png deleted file mode 120000 index 6e012271..00000000 --- a/hdd/usr/share/icons/weather/10n.png +++ /dev/null @@ -1 +0,0 @@ -10d.png \ No newline at end of file diff --git a/hdd/usr/share/icons/weather/11d.png b/hdd/usr/share/icons/weather/11d.png deleted file mode 100644 index 3eb25928..00000000 Binary files a/hdd/usr/share/icons/weather/11d.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/11n.png b/hdd/usr/share/icons/weather/11n.png deleted file mode 120000 index b227917d..00000000 --- a/hdd/usr/share/icons/weather/11n.png +++ /dev/null @@ -1 +0,0 @@ -11d.png \ No newline at end of file diff --git a/hdd/usr/share/icons/weather/13d.png b/hdd/usr/share/icons/weather/13d.png deleted file mode 100644 index ca562fce..00000000 Binary files a/hdd/usr/share/icons/weather/13d.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/13n.png b/hdd/usr/share/icons/weather/13n.png deleted file mode 120000 index 94e5a525..00000000 --- a/hdd/usr/share/icons/weather/13n.png +++ /dev/null @@ -1 +0,0 @@ -13d.png \ No newline at end of file diff --git a/hdd/usr/share/icons/weather/50d.png b/hdd/usr/share/icons/weather/50d.png deleted file mode 100644 index dd9f14b8..00000000 Binary files a/hdd/usr/share/icons/weather/50d.png and /dev/null differ diff --git a/hdd/usr/share/icons/weather/50n.png b/hdd/usr/share/icons/weather/50n.png deleted file mode 120000 index e3ba9612..00000000 --- a/hdd/usr/share/icons/weather/50n.png +++ /dev/null @@ -1 +0,0 @@ -50d.png \ No newline at end of file diff --git a/hdd/usr/share/logo_login.png b/hdd/usr/share/logo_login.png deleted file mode 100644 index 05e49c93..00000000 Binary files a/hdd/usr/share/logo_login.png and /dev/null differ diff --git a/hdd/usr/share/panel.png b/hdd/usr/share/panel.png deleted file mode 100644 index 0a733627..00000000 Binary files a/hdd/usr/share/panel.png and /dev/null differ diff --git a/hdd/usr/share/pong/ball.png b/hdd/usr/share/pong/ball.png deleted file mode 100644 index 90e31596..00000000 Binary files a/hdd/usr/share/pong/ball.png and /dev/null differ diff --git a/hdd/usr/share/pong/paddle-blue.png b/hdd/usr/share/pong/paddle-blue.png deleted file mode 100644 index 517c94ef..00000000 Binary files a/hdd/usr/share/pong/paddle-blue.png and /dev/null differ diff --git a/hdd/usr/share/pong/paddle-red.png b/hdd/usr/share/pong/paddle-red.png deleted file mode 100644 index 67ca88bc..00000000 Binary files a/hdd/usr/share/pong/paddle-red.png and /dev/null differ diff --git a/hdd/usr/share/toaru_logo.svg b/hdd/usr/share/toaru_logo.svg deleted file mode 100644 index 61d60516..00000000 --- a/hdd/usr/share/toaru_logo.svg +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/hdd/usr/share/ttk/active/button-close.png b/hdd/usr/share/ttk/active/button-close.png deleted file mode 100644 index 14690d0c..00000000 Binary files a/hdd/usr/share/ttk/active/button-close.png and /dev/null differ diff --git a/hdd/usr/share/ttk/active/ll.png b/hdd/usr/share/ttk/active/ll.png deleted file mode 100644 index e050e2f8..00000000 Binary files a/hdd/usr/share/ttk/active/ll.png and /dev/null differ diff --git a/hdd/usr/share/ttk/active/lm.png b/hdd/usr/share/ttk/active/lm.png deleted file mode 100644 index 10fc1ffc..00000000 Binary files a/hdd/usr/share/ttk/active/lm.png and /dev/null differ diff --git a/hdd/usr/share/ttk/active/lr.png b/hdd/usr/share/ttk/active/lr.png deleted file mode 100644 index b7bc0812..00000000 Binary files a/hdd/usr/share/ttk/active/lr.png and /dev/null differ diff --git a/hdd/usr/share/ttk/active/ml.png b/hdd/usr/share/ttk/active/ml.png deleted file mode 100644 index af38812f..00000000 Binary files a/hdd/usr/share/ttk/active/ml.png and /dev/null differ diff --git a/hdd/usr/share/ttk/active/mr.png b/hdd/usr/share/ttk/active/mr.png deleted file mode 100644 index 43622b5f..00000000 Binary files a/hdd/usr/share/ttk/active/mr.png and /dev/null differ diff --git a/hdd/usr/share/ttk/active/ul.png b/hdd/usr/share/ttk/active/ul.png deleted file mode 100644 index 586c7dee..00000000 Binary files a/hdd/usr/share/ttk/active/ul.png and /dev/null differ diff --git a/hdd/usr/share/ttk/active/um.png b/hdd/usr/share/ttk/active/um.png deleted file mode 100644 index cf3ad9cc..00000000 Binary files a/hdd/usr/share/ttk/active/um.png and /dev/null differ diff --git a/hdd/usr/share/ttk/active/ur.png b/hdd/usr/share/ttk/active/ur.png deleted file mode 100644 index ffcb7ec8..00000000 Binary files a/hdd/usr/share/ttk/active/ur.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/button-close.png b/hdd/usr/share/ttk/inactive/button-close.png deleted file mode 100644 index a2d0a75f..00000000 Binary files a/hdd/usr/share/ttk/inactive/button-close.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/ll.png b/hdd/usr/share/ttk/inactive/ll.png deleted file mode 100644 index 06493522..00000000 Binary files a/hdd/usr/share/ttk/inactive/ll.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/lm.png b/hdd/usr/share/ttk/inactive/lm.png deleted file mode 100644 index cc4a78df..00000000 Binary files a/hdd/usr/share/ttk/inactive/lm.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/lr.png b/hdd/usr/share/ttk/inactive/lr.png deleted file mode 100644 index 4dddcc5e..00000000 Binary files a/hdd/usr/share/ttk/inactive/lr.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/ml.png b/hdd/usr/share/ttk/inactive/ml.png deleted file mode 100644 index 8d0ac658..00000000 Binary files a/hdd/usr/share/ttk/inactive/ml.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/mr.png b/hdd/usr/share/ttk/inactive/mr.png deleted file mode 100644 index 457296ab..00000000 Binary files a/hdd/usr/share/ttk/inactive/mr.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/ul.png b/hdd/usr/share/ttk/inactive/ul.png deleted file mode 100644 index 32570926..00000000 Binary files a/hdd/usr/share/ttk/inactive/ul.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/um.png b/hdd/usr/share/ttk/inactive/um.png deleted file mode 100644 index 4ec051bc..00000000 Binary files a/hdd/usr/share/ttk/inactive/um.png and /dev/null differ diff --git a/hdd/usr/share/ttk/inactive/ur.png b/hdd/usr/share/ttk/inactive/ur.png deleted file mode 100644 index 27d796d5..00000000 Binary files a/hdd/usr/share/ttk/inactive/ur.png and /dev/null differ diff --git a/hdd/usr/share/ttk/toast/default.png b/hdd/usr/share/ttk/toast/default.png deleted file mode 100644 index a7ec4a62..00000000 Binary files a/hdd/usr/share/ttk/toast/default.png and /dev/null differ diff --git a/hdd/usr/share/wallpapers/default b/hdd/usr/share/wallpapers/default deleted file mode 120000 index f0a00d1d..00000000 --- a/hdd/usr/share/wallpapers/default +++ /dev/null @@ -1 +0,0 @@ -moon.png \ No newline at end of file diff --git a/hdd/usr/share/wallpapers/fuji.png b/hdd/usr/share/wallpapers/fuji.png deleted file mode 100644 index 295c1098..00000000 Binary files a/hdd/usr/share/wallpapers/fuji.png and /dev/null differ diff --git a/hdd/usr/share/wallpapers/grandcanyon.png b/hdd/usr/share/wallpapers/grandcanyon.png deleted file mode 100644 index 00600594..00000000 Binary files a/hdd/usr/share/wallpapers/grandcanyon.png and /dev/null differ diff --git a/hdd/usr/share/wallpapers/moon.png b/hdd/usr/share/wallpapers/moon.png deleted file mode 100644 index a0ec8f04..00000000 Binary files a/hdd/usr/share/wallpapers/moon.png and /dev/null differ diff --git a/hdd/usr/share/wallpapers/paris.png b/hdd/usr/share/wallpapers/paris.png deleted file mode 100644 index 5bfd1213..00000000 Binary files a/hdd/usr/share/wallpapers/paris.png and /dev/null differ diff --git a/hdd/usr/share/wallpapers/southbay.png b/hdd/usr/share/wallpapers/southbay.png deleted file mode 100644 index e74efe9e..00000000 Binary files a/hdd/usr/share/wallpapers/southbay.png and /dev/null differ diff --git a/hdd/usr/share/wallpapers/sumida.png b/hdd/usr/share/wallpapers/sumida.png deleted file mode 100644 index ab1b563a..00000000 Binary files a/hdd/usr/share/wallpapers/sumida.png and /dev/null differ diff --git a/hdd/usr/share/wallpapers/yokohama.png b/hdd/usr/share/wallpapers/yokohama.png deleted file mode 100644 index 7e22aab4..00000000 Binary files a/hdd/usr/share/wallpapers/yokohama.png and /dev/null differ diff --git a/hdd/usr/share/wallpapers/yosemite.png b/hdd/usr/share/wallpapers/yosemite.png deleted file mode 100644 index e491b2b2..00000000 Binary files a/hdd/usr/share/wallpapers/yosemite.png and /dev/null differ diff --git a/hdd/usr/share/wizard-arrow.png b/hdd/usr/share/wizard-arrow.png deleted file mode 100644 index 01345e8e..00000000 Binary files a/hdd/usr/share/wizard-arrow.png and /dev/null differ diff --git a/kernel/cpu/gdt.c b/kernel/cpu/gdt.c index f736f4d8..aec13deb 100644 --- a/kernel/cpu/gdt.c +++ b/kernel/cpu/gdt.c @@ -1,15 +1,15 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2013 Kevin Lange + * Copyright (C) 2011-2018 K Lange * Copyright (C) 2015 Dale Weiler * * Global Descriptor Tables module * */ -#include -#include -#include +#include +#include +#include typedef struct { /* Limits */ diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c index 10bc4ee0..46e4f223 100644 --- a/kernel/cpu/idt.c +++ b/kernel/cpu/idt.c @@ -1,14 +1,14 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2013 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * Copyright (C) 2015 Dale Weiler * * Interrupt Descriptor Tables * */ -#include -#include +#include +#include typedef struct { uint16_t base_low; diff --git a/kernel/cpu/irq.c b/kernel/cpu/irq.c index 19057580..bbb06db4 100644 --- a/kernel/cpu/irq.c +++ b/kernel/cpu/irq.c @@ -1,16 +1,16 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * Copyright (C) 2015 Dale Weiler * * Interrupt Requests * */ -#include -#include -#include -#include +#include +#include +#include +#include /* Programmable interrupt controller */ #define PIC1 0x20 @@ -85,14 +85,22 @@ void int_enable(void) { static void (*irqs[IRQ_CHAIN_SIZE])(void); static irq_handler_chain_t irq_routines[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL }; +static char * _irq_handler_descriptions[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL }; -void irq_install_handler(size_t irq, irq_handler_chain_t handler) { +char * get_irq_handler(int irq, int chain) { + if (irq >= IRQ_CHAIN_SIZE) return NULL; + if (chain >= IRQ_CHAIN_DEPTH) return NULL; + return _irq_handler_descriptions[IRQ_CHAIN_SIZE * chain + irq]; +} + +void irq_install_handler(size_t irq, irq_handler_chain_t handler, char * desc) { /* Disable interrupts when changing handlers */ SYNC_CLI(); for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { if (irq_routines[i * IRQ_CHAIN_SIZE + irq]) continue; irq_routines[i * IRQ_CHAIN_SIZE + irq] = handler; + _irq_handler_descriptions[i * IRQ_CHAIN_SIZE + irq ] = desc; break; } SYNC_STI(); @@ -153,7 +161,8 @@ void irq_handler(struct regs *r) { if (r->int_no <= 47 && r->int_no >= 32) { for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { irq_handler_chain_t handler = irq_routines[i * IRQ_CHAIN_SIZE + (r->int_no - 32)]; - if (handler && handler(r)) { + if (!handler) break; + if (handler(r)) { goto done; } } diff --git a/kernel/cpu/isr.c b/kernel/cpu/isr.c index c3652277..699cce10 100644 --- a/kernel/cpu/isr.c +++ b/kernel/cpu/isr.c @@ -1,15 +1,15 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * Copyright (C) 2015 Dale Weiler * * Interrupt Service Requests */ -#include -#include -#include -#include +#include +#include +#include +#include /* The count is treated as is when setting up IDT gates. However there is an * additional ISR for the system call vector which is handled explicitly since diff --git a/kernel/devices/cmos.c b/kernel/devices/cmos.c index 6b5e2880..5f776c0d 100644 --- a/kernel/devices/cmos.c +++ b/kernel/devices/cmos.c @@ -1,13 +1,13 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * CMOS Driver * */ -#include +#include /* CMOS values are stored like so: * Say it's 8:42 AM, then the values are stored as: diff --git a/kernel/devices/fpu.c b/kernel/devices/fpu.c index 4407805d..3c51fbc5 100644 --- a/kernel/devices/fpu.c +++ b/kernel/devices/fpu.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2013 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * FPU and SSE context handling. * @@ -15,8 +15,8 @@ * FPU states are per kernel thread. * */ -#include -#include +#include +#include #define NO_LAZY_FPU diff --git a/kernel/devices/pci.c b/kernel/devices/pci.c index b398b024..19dadb78 100644 --- a/kernel/devices/pci.c +++ b/kernel/devices/pci.c @@ -1,15 +1,14 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * ToAruOS PCI Initialization */ -#include -#include -#include - +#include +#include +#include void pci_write_field(uint32_t device, int field, int size, uint32_t value) { outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); @@ -36,19 +35,61 @@ uint16_t pci_find_type(uint32_t dev) { return (pci_read_field(dev, PCI_CLASS, 1) << 8) | pci_read_field(dev, PCI_SUBCLASS, 1); } +struct { + uint16_t id; + const char * name; +} _pci_vendors[] = { + {0x1022, "AMD"}, + {0x106b, "Apple, Inc."}, + {0x1234, "Bochs/QEMU"}, + {0x1274, "Ensoniq"}, + {0x15ad, "VMWare"}, + {0x8086, "Intel Corporation"}, + {0x80EE, "VirtualBox"}, +}; + +struct { + uint16_t ven_id; + uint16_t dev_id; + const char * name; +} _pci_devices[] = { + {0x1022, 0x2000, "PCNet Ethernet Controller (pcnet)"}, + {0x106b, 0x003f, "OHCI Controller"}, + {0x1234, 0x1111, "VGA BIOS Graphics Extensions"}, + {0x1274, 0x1371, "Creative Labs CT2518 (ensoniq audio)"}, + {0x15ad, 0x0740, "VM Communication Interface"}, + {0x15ad, 0x0405, "SVGA II Adapter"}, + {0x15ad, 0x0790, "PCI bridge"}, + {0x15ad, 0x07a0, "PCI Express Root Port"}, + {0x8086, 0x100e, "Gigabit Ethernet Controller (e1000)"}, + {0x8086, 0x100f, "Gigabit Ethernet Controller (e1000)"}, + {0x8086, 0x1237, "PCI & Memory"}, + {0x8086, 0x2415, "AC'97 Audio Chipset"}, + {0x8086, 0x7000, "PCI-to-ISA Bridge"}, + {0x8086, 0x7010, "IDE Interface"}, + {0x8086, 0x7110, "PIIX4 ISA"}, + {0x8086, 0x7111, "PIIX4 IDE"}, + {0x8086, 0x7113, "Power Management Controller"}, + {0x8086, 0x7190, "Host Bridge"}, + {0x8086, 0x7191, "AGP Bridge"}, + {0x80EE, 0xBEEF, "Bochs/QEMU-compatible Graphics Adapter"}, + {0x80EE, 0xCAFE, "Guest Additions Device"}, +}; + + const char * pci_vendor_lookup(unsigned short vendor_id) { - for (unsigned int i = 0; i < PCI_VENTABLE_LEN; ++i) { - if (PciVenTable[i].VenId == vendor_id) { - return PciVenTable[i].VenFull; + for (unsigned int i = 0; i < sizeof(_pci_vendors)/sizeof(_pci_vendors[0]); ++i) { + if (_pci_vendors[i].id == vendor_id) { + return _pci_vendors[i].name; } } return ""; } const char * pci_device_lookup(unsigned short vendor_id, unsigned short device_id) { - for (unsigned int i = 0; i < PCI_DEVTABLE_LEN; ++i) { - if (PciDevTable[i].VenId == vendor_id && PciDevTable[i].DevId == device_id) { - return PciDevTable[i].ChipDesc; + for (unsigned int i = 0; i < sizeof(_pci_devices)/sizeof(_pci_devices[0]); ++i) { + if (_pci_devices[i].ven_id == vendor_id && _pci_devices[i].dev_id == device_id) { + return _pci_devices[i].name; } } return ""; @@ -111,3 +152,47 @@ void pci_scan(pci_func_t f, int type, void * extra) { } } +static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) { + *((uint32_t *)extra) = device; + } +} +static uint32_t pci_isa = 0; +static uint8_t pci_remaps[4] = {0}; +void pci_remap(void) { + pci_scan(&find_isa_bridge, -1, &pci_isa); + if (pci_isa) { + for (int i = 0; i < 4; ++i) { + pci_remaps[i] = pci_read_field(pci_isa, 0x60+i, 1); + } + uint32_t out = 0; + memcpy(&out, &pci_remaps, 4); + pci_write_field(pci_isa, 0x60, 4, out); + } +} + +int pci_get_interrupt(uint32_t device) { + + if (pci_isa) { + uint32_t irq_pin = pci_read_field(device, 0x3D, 1); + if (irq_pin == 0) { + /* ??? */ + debug_print(ERROR, "PCI device does not specific interrupt line"); + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); + } + int pirq = (irq_pin + pci_extract_slot(device) - 2) % 4; + int int_line = pci_read_field(device, PCI_INTERRUPT_LINE, 1); + debug_print(ERROR, "slot is %d, irq pin is %d, so pirq is %d and that maps to %d? int_line=%d", pci_extract_slot(device), irq_pin, pirq, pci_remaps[pirq], int_line); + if (pci_remaps[pirq] == 0x80) { + debug_print(ERROR, "not mapped, remapping?\n"); + pci_remaps[pirq] = int_line; + uint32_t out = 0; + memcpy(&out, &pci_remaps, 4); + pci_write_field(pci_isa, 0x60, 4, out); + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); + } + return pci_remaps[pirq]; + } else { + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); + } +} diff --git a/kernel/devices/timer.c b/kernel/devices/timer.c index a50f5578..59775260 100644 --- a/kernel/devices/timer.c +++ b/kernel/devices/timer.c @@ -1,13 +1,13 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2013 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * Programmable Interrupt Timer */ -#include -#include -#include +#include +#include +#include #define PIT_A 0x40 #define PIT_B 0x41 @@ -84,7 +84,7 @@ void relative_time(unsigned long seconds, unsigned long subseconds, unsigned lon void timer_install(void) { debug_print(NOTICE,"Initializing interval timer"); boot_time = read_cmos(); - irq_install_handler(TIMER_IRQ, timer_handler); + irq_install_handler(TIMER_IRQ, timer_handler, "pit timer"); timer_phase(SUBTICKS_PER_TICK); /* 100Hz */ } diff --git a/kernel/ds/bitset.c b/kernel/ds/bitset.c index 503ef650..c42b877c 100644 --- a/kernel/ds/bitset.c +++ b/kernel/ds/bitset.c @@ -1,10 +1,10 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Dale Weiler - * 2015 Kevin Lange + * Copyright (C) 2015-2018 K. Lange + * 2015 Dale Weiler */ -#include "bitset.h" +#include #define CEIL(NUMBER, BASE) \ (((NUMBER) + (BASE) - 1) & ~((BASE) - 1)) diff --git a/kernel/ds/hashmap.c b/kernel/ds/hashmap.c deleted file mode 100644 index 34ed54b1..00000000 --- a/kernel/ds/hashmap.c +++ /dev/null @@ -1,217 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -#include "list.h" -#include "hashmap.h" - -unsigned int hashmap_string_hash(void * _key) { - unsigned int hash = 0; - char * key = (char *)_key; - int c; - /* This is the so-called "sdbm" hash. It comes from a piece of - * public domain code from a clone of ndbm. */ - while ((c = *key++)) { - hash = c + (hash << 6) + (hash << 16) - hash; - } - return hash; -} - -int hashmap_string_comp(void * a, void * b) { - return !strcmp(a,b); -} - -void * hashmap_string_dupe(void * key) { - return strdup(key); -} - -unsigned int hashmap_int_hash(void * key) { - return (unsigned int)key; -} - -int hashmap_int_comp(void * a, void * b) { - return (int)a == (int)b; -} - -void * hashmap_int_dupe(void * key) { - return key; -} - -static void hashmap_int_free(void * ptr) { - return; -} - - -hashmap_t * hashmap_create(int size) { - hashmap_t * map = malloc(sizeof(hashmap_t)); - - map->hash_func = &hashmap_string_hash; - map->hash_comp = &hashmap_string_comp; - map->hash_key_dup = &hashmap_string_dupe; - map->hash_key_free = &free; - map->hash_val_free = &free; - - map->size = size; - map->entries = malloc(sizeof(hashmap_entry_t *) * size); - memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size); - - return map; -} - -hashmap_t * hashmap_create_int(int size) { - hashmap_t * map = malloc(sizeof(hashmap_t)); - - map->hash_func = &hashmap_int_hash; - map->hash_comp = &hashmap_int_comp; - map->hash_key_dup = &hashmap_int_dupe; - map->hash_key_free = &hashmap_int_free; - map->hash_val_free = &free; - - map->size = size; - map->entries = malloc(sizeof(hashmap_entry_t *) * size); - memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size); - - return map; -} - -void * hashmap_set(hashmap_t * map, void * key, void * value) { - unsigned int hash = map->hash_func(key) % map->size; - - hashmap_entry_t * x = map->entries[hash]; - if (!x) { - hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t)); - e->key = map->hash_key_dup(key); - e->value = value; - e->next = NULL; - map->entries[hash] = e; - return NULL; - } else { - hashmap_entry_t * p = NULL; - do { - if (map->hash_comp(x->key, key)) { - void * out = x->value; - x->value = value; - return out; - } else { - p = x; - x = x->next; - } - } while (x); - hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t)); - e->key = map->hash_key_dup(key); - e->value = value; - e->next = NULL; - - p->next = e; - return NULL; - } -} - -void * hashmap_get(hashmap_t * map, void * key) { - unsigned int hash = map->hash_func(key) % map->size; - - hashmap_entry_t * x = map->entries[hash]; - if (!x) { - return NULL; - } else { - do { - if (map->hash_comp(x->key, key)) { - return x->value; - } - x = x->next; - } while (x); - return NULL; - } -} - -void * hashmap_remove(hashmap_t * map, void * key) { - unsigned int hash = map->hash_func(key) % map->size; - - hashmap_entry_t * x = map->entries[hash]; - if (!x) { - return NULL; - } else { - if (map->hash_comp(x->key, key)) { - void * out = x->value; - map->entries[hash] = x->next; - map->hash_key_free(x->key); - map->hash_val_free(x); - return out; - } else { - hashmap_entry_t * p = x; - x = x->next; - do { - if (map->hash_comp(x->key, key)) { - void * out = x->value; - p->next = x->next; - map->hash_key_free(x->key); - map->hash_val_free(x); - return out; - } - p = x; - x = x->next; - } while (x); - } - return NULL; - } -} - -int hashmap_has(hashmap_t * map, void * key) { - unsigned int hash = map->hash_func(key) % map->size; - - hashmap_entry_t * x = map->entries[hash]; - if (!x) { - return 0; - } else { - do { - if (map->hash_comp(x->key, key)) { - return 1; - } - x = x->next; - } while (x); - return 0; - } - -} - -list_t * hashmap_keys(hashmap_t * map) { - list_t * l = list_create(); - - for (unsigned int i = 0; i < map->size; ++i) { - hashmap_entry_t * x = map->entries[i]; - while (x) { - list_insert(l, x->key); - x = x->next; - } - } - - return l; -} - -list_t * hashmap_values(hashmap_t * map) { - list_t * l = list_create(); - - for (unsigned int i = 0; i < map->size; ++i) { - hashmap_entry_t * x = map->entries[i]; - while (x) { - list_insert(l, x->value); - x = x->next; - } - } - - return l; -} - -void hashmap_free(hashmap_t * map) { - for (unsigned int i = 0; i < map->size; ++i) { - hashmap_entry_t * x = map->entries[i], * p; - while (x) { - p = x; - x = x->next; - map->hash_key_free(p->key); - map->hash_val_free(p); - } - } - free(map->entries); -} diff --git a/kernel/ds/hashmap.c b/kernel/ds/hashmap.c new file mode 120000 index 00000000..0336fc20 --- /dev/null +++ b/kernel/ds/hashmap.c @@ -0,0 +1 @@ +lib/hashmap.c \ No newline at end of file diff --git a/kernel/ds/list.c b/kernel/ds/list.c deleted file mode 100644 index 37a0f477..00000000 --- a/kernel/ds/list.c +++ /dev/null @@ -1,248 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange - * - * General-purpose list implementations. - */ - -#include "list.h" - -#ifdef _KERNEL_ -# include -#else -# include -# include -#endif - -void list_destroy(list_t * list) { - /* Free all of the contents of a list */ - node_t * n = list->head; - while (n) { - free(n->value); - n = n->next; - } -} - -void list_free(list_t * list) { - /* Free the actual structure of a list */ - node_t * n = list->head; - while (n) { - node_t * s = n->next; - free(n); - n = s; - } -} - -void list_append(list_t * list, node_t * node) { - assert(!(node->next || node->prev) && "Node is already in a list."); - node->next = NULL; - /* Insert a node onto the end of a list */ - node->owner = list; - if (!list->length) { - list->head = node; - list->tail = node; - node->prev = NULL; - node->next = NULL; - list->length++; - return; - } - list->tail->next = node; - node->prev = list->tail; - list->tail = node; - list->length++; -} - -node_t * list_insert(list_t * list, void * item) { - /* Insert an item into a list */ - node_t * node = malloc(sizeof(node_t)); - node->value = item; - node->next = NULL; - node->prev = NULL; - node->owner = NULL; - list_append(list, node); - - return node; -} - -void list_append_after(list_t * list, node_t * before, node_t * node) { - assert(!(node->next || node->prev) && "Node is already in a list."); - node->owner = list; - if (!list->length) { - list_append(list, node); - return; - } - if (before == NULL) { - node->next = list->head; - node->prev = NULL; - list->head->prev = node; - list->head = node; - list->length++; - return; - } - if (before == list->tail) { - list->tail = node; - } else { - before->next->prev = node; - node->next = before->next; - } - node->prev = before; - before->next = node; - list->length++; -} - -node_t * list_insert_after(list_t * list, node_t * before, void * item) { - node_t * node = malloc(sizeof(node_t)); - node->value = item; - node->next = NULL; - node->prev = NULL; - node->owner = NULL; - list_append_after(list, before, node); - return node; -} - -void list_append_before(list_t * list, node_t * after, node_t * node) { - assert(!(node->next || node->prev) && "Node is already in a list."); - node->owner = list; - if (!list->length) { - list_append(list, node); - return; - } - if (after == NULL) { - node->next = NULL; - node->prev = list->tail; - list->tail->next = node; - list->tail = node; - list->length++; - return; - } - if (after == list->head) { - list->head = node; - } else { - after->prev->next = node; - node->prev = after->prev; - } - node->next = after; - after->prev = node; - list->length++; -} - -node_t * list_insert_before(list_t * list, node_t * after, void * item) { - node_t * node = malloc(sizeof(node_t)); - node->value = item; - node->next = NULL; - node->prev = NULL; - node->owner = NULL; - list_append_before(list, after, node); - return node; -} - -list_t * list_create(void) { - /* Create a fresh list */ - list_t * out = malloc(sizeof(list_t)); - out->head = NULL; - out->tail = NULL; - out->length = 0; - return out; -} - -node_t * list_find(list_t * list, void * value) { - foreach(item, list) { - if (item->value == value) { - return item; - } - } - return NULL; -} - -int list_index_of(list_t * list, void * value) { - int i = 0; - foreach(item, list) { - if (item->value == value) { - return i; - } - i++; - } - return -1; /* not find */ -} - -void list_remove(list_t * list, size_t index) { - /* remove index from the list */ - if (index > list->length) return; - size_t i = 0; - node_t * n = list->head; - while (i < index) { - n = n->next; - i++; - } - list_delete(list, n); -} - -void list_delete(list_t * list, node_t * node) { - /* remove node from the list */ - assert(node->owner == list && "Tried to remove a list node from a list it does not belong to."); - if (node == list->head) { - list->head = node->next; - } - if (node == list->tail) { - list->tail = node->prev; - } - if (node->prev) { - node->prev->next = node->next; - } - if (node->next) { - node->next->prev = node->prev; - } - node->prev = NULL; - node->next = NULL; - node->owner = NULL; - list->length--; -} - -node_t * list_pop(list_t * list) { - /* Remove and return the last value in the list - * If you don't need it, you still probably want to free it! - * Try free(list_pop(list)); ! - * */ - if (!list->tail) return NULL; - node_t * out = list->tail; - list_delete(list, out); - return out; -} - -node_t * list_dequeue(list_t * list) { - if (!list->head) return NULL; - node_t * out = list->head; - list_delete(list, out); - return out; -} - -list_t * list_copy(list_t * original) { - /* Create a new copy of original */ - list_t * out = list_create(); - node_t * node = original->head; - while (node) { - list_insert(out, node->value); - } - return out; -} - -void list_merge(list_t * target, list_t * source) { - /* Destructively merges source into target */ - foreach(node, source) { - node->owner = target; - } - if (source->head) { - source->head->prev = target->tail; - } - if (target->tail) { - target->tail->next = source->head; - } else { - target->head = source->head; - } - if (source->tail) { - target->tail = source->tail; - } - target->length += source->length; - free(source); -} diff --git a/kernel/ds/list.c b/kernel/ds/list.c new file mode 120000 index 00000000..8fd1da36 --- /dev/null +++ b/kernel/ds/list.c @@ -0,0 +1 @@ +lib/list.c \ No newline at end of file diff --git a/kernel/ds/ringbuffer.c b/kernel/ds/ringbuffer.c index 632411d3..94c67721 100644 --- a/kernel/ds/ringbuffer.c +++ b/kernel/ds/ringbuffer.c @@ -1,11 +1,11 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2018 K. Lange */ -#include -#include -#include +#include +#include +#include size_t ring_buffer_unread(ring_buffer_t * ring_buffer) { if (ring_buffer->read_ptr == ring_buffer->write_ptr) { @@ -49,7 +49,7 @@ static inline void ring_buffer_increment_write(ring_buffer_t * ring_buffer) { } } -static void ring_buffer_alert_waiters(ring_buffer_t * ring_buffer) { +void ring_buffer_alert_waiters(ring_buffer_t * ring_buffer) { if (ring_buffer->alert_waiters) { while (ring_buffer->alert_waiters->head) { node_t * node = list_dequeue(ring_buffer->alert_waiters); diff --git a/kernel/ds/tree.c b/kernel/ds/tree.c deleted file mode 100644 index 92225f8c..00000000 --- a/kernel/ds/tree.c +++ /dev/null @@ -1,192 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange - * - * General-purpose tree implementation - */ - -#include "tree.h" - -#ifdef _KERNEL_ -# include -#else -# include -# include -#endif - -tree_t * tree_create(void) { - /* Create a new tree */ - tree_t * out = malloc(sizeof(tree_t)); - out->nodes = 0; - out->root = NULL; - return out; -} - -void tree_set_root(tree_t * tree, void * value) { - /* Set the root node for a new tree. */ - tree_node_t * root = tree_node_create(value); - tree->root = root; - tree->nodes = 1; -} - -void tree_node_destroy(tree_node_t * node) { - /* Free the contents of a node and its children, but not the nodes themselves */ - foreach(child, node->children) { - tree_node_destroy((tree_node_t *)child->value); - } - free(node->value); -} - -void tree_destroy(tree_t * tree) { - /* Free the contents of a tree, but not the nodes */ - if (tree->root) { - tree_node_destroy(tree->root); - } -} - -void tree_node_free(tree_node_t * node) { - /* Free a node and its children, but not their contents */ - if (!node) return; - foreach(child, node->children) { - tree_node_free(child->value); - } - free(node); -} - -void tree_free(tree_t * tree) { - /* Free all of the nodes in a tree, but not their contents */ - tree_node_free(tree->root); -} - -tree_node_t * tree_node_create(void * value) { - /* Create a new tree node pointing to the given value */ - tree_node_t * out = malloc(sizeof(tree_node_t)); - out->value = value; - out->children = list_create(); - out->parent = NULL; - return out; -} - -void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node) { - /* Insert a node as a child of parent */ - list_insert(parent->children, node); - node->parent = parent; - tree->nodes++; -} - -tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value) { - /* Insert a (fresh) node as a child of parent */ - tree_node_t * out = tree_node_create(value); - tree_node_insert_child_node(tree, parent, out); - return out; -} - -tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle) { - /* Recursive node part of tree_find_parent */ - tree_node_t * found = NULL; - foreach(child, haystack->children) { - if (child->value == needle) { - return haystack; - } - found = tree_node_find_parent((tree_node_t *)child->value, needle); - if (found) { - break; - } - } - return found; -} - -tree_node_t * tree_find_parent(tree_t * tree, tree_node_t * node) { - /* Return the parent of a node, inefficiently. */ - if (!tree->root) return NULL; - return tree_node_find_parent(tree->root, node); -} - -size_t tree_count_children(tree_node_t * node) { - /* return the number of children this node has */ - if (!node) return 0; - if (!node->children) return 0; - size_t out = node->children->length; - foreach(child, node->children) { - out += tree_count_children((tree_node_t *)child->value); - } - return out; -} - -void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node) { - /* remove a node when we know its parent; update node counts for the tree */ - tree->nodes -= tree_count_children(node) + 1; - list_delete(parent->children, list_find(parent->children, node)); - tree_node_free(node); -} - -void tree_node_remove(tree_t * tree, tree_node_t * node) { - /* remove an entire branch given its root */ - tree_node_t * parent = node->parent; - if (!parent) { - if (node == tree->root) { - tree->nodes = 0; - tree->root = NULL; - tree_node_free(node); - } - } - tree_node_parent_remove(tree, parent, node); -} - -void tree_remove(tree_t * tree, tree_node_t * node) { - /* Remove this node and move its children into its parent's list of children */ - tree_node_t * parent = node->parent; - /* This is something we just can't do. We don't know how to merge our - * children into our "parent" because then we'd have more than one root node. - * A good way to think about this is actually what this tree struct - * primarily exists for: processes. Trying to remove the root is equivalent - * to trying to kill init! Which is bad. We immediately fault on such - * a case anyway ("Tried to kill init, shutting down!"). - */ - if (!parent) return; - tree->nodes--; - list_delete(parent->children, list_find(parent->children, node)); - foreach(child, node->children) { - /* Reassign the parents */ - ((tree_node_t *)child->value)->parent = parent; - } - list_merge(parent->children, node->children); - free(node); -} - -void tree_remove_reparent_root(tree_t * tree, tree_node_t * node) { - /* Remove this node and move its children into the root children */ - tree_node_t * parent = node->parent; - if (!parent) return; - tree->nodes--; - list_delete(parent->children, list_find(parent->children, node)); - foreach(child, node->children) { - /* Reassign the parents */ - ((tree_node_t *)child->value)->parent = tree->root; - } - list_merge(tree->root->children, node->children); - free(node); -} - -void tree_break_off(tree_t * tree, tree_node_t * node) { - tree_node_t * parent = node->parent; - if (!parent) return; - list_delete(parent->children, list_find(parent->children, node)); -} - -tree_node_t * tree_node_find(tree_node_t * node, void * search, tree_comparator_t comparator) { - if (comparator(node->value,search)) { - return node; - } - tree_node_t * found; - foreach(child, node->children) { - found = tree_node_find((tree_node_t *)child->value, search, comparator); - if (found) return found; - } - return NULL; -} - -tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator) { - return tree_node_find(tree->root, value, comparator); -} diff --git a/kernel/ds/tree.c b/kernel/ds/tree.c new file mode 120000 index 00000000..d526bb2f --- /dev/null +++ b/kernel/ds/tree.c @@ -0,0 +1 @@ +lib/tree.c \ No newline at end of file diff --git a/kernel/fs/pipe.c b/kernel/fs/pipe.c index 1c24f9d9..6a35d37d 100644 --- a/kernel/fs/pipe.c +++ b/kernel/fs/pipe.c @@ -1,17 +1,17 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2014 Kevin Lange + * Copyright (C) 2012-2018 K. Lange * * Buffered Pipe * */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #define DEBUG_PIPES 0 @@ -102,7 +102,7 @@ uint32_t read_pipe(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buf if (pipe->dead) { debug_print(WARNING, "Pipe is dead?"); - send_signal(getpid(), SIGPIPE); + send_signal(getpid(), SIGPIPE, 1); return 0; } @@ -146,7 +146,7 @@ uint32_t write_pipe(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *bu if (pipe->dead) { debug_print(WARNING, "Pipe is dead?"); - send_signal(getpid(), SIGPIPE); + send_signal(getpid(), SIGPIPE, 1); return 0; } diff --git a/kernel/fs/ramdisk.c b/kernel/fs/ramdisk.c index 6075913e..13cd2230 100644 --- a/kernel/fs/ramdisk.c +++ b/kernel/fs/ramdisk.c @@ -1,19 +1,19 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * Ramdisk driver. * * Provide raw block access to files loaded into kernel memory. */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include static uint32_t read_ramdisk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); static uint32_t write_ramdisk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); @@ -84,7 +84,7 @@ static fs_node_t * ramdisk_device_create(int device_number, uintptr_t location, sprintf(fnode->name, "ram%d", device_number); fnode->uid = 0; fnode->gid = 0; - fnode->mask = 0660; + fnode->mask = 0770; fnode->length = size; fnode->flags = FS_BLOCKDEVICE; fnode->read = read_ramdisk; diff --git a/kernel/fs/tty.c b/kernel/fs/tty.c index 3918fe7b..def80011 100644 --- a/kernel/fs/tty.c +++ b/kernel/fs/tty.c @@ -1,17 +1,17 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2018 K. Lange */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -#include -#include -#include +#include +#include #define TTY_BUFFER_SIZE 4096 //4096 @@ -62,30 +62,72 @@ static void clear_input_buffer(pty_t * pty) { pty->canon_buffer[0] = '\0'; } -static void output_process(pty_t * pty, uint8_t c) { - if (ring_buffer_available(pty->out) < 2) return; /* uh oh */ +static void output_process_slave(pty_t * pty, uint8_t c) { if (c == '\n' && (pty->tios.c_oflag & ONLCR)) { - uint8_t d = '\r'; - OUT(d); + c = '\n'; + OUT(c); + c = '\r'; + OUT(c); + return; } + + if (c == '\r' && (pty->tios.c_oflag & ONLRET)) { + return; + } + + if (c >= 'a' && c <= 'z' && (pty->tios.c_oflag & OLCUC)) { + c = c + 'a' - 'A'; + OUT(c); + return; + } + OUT(c); } -static void output_process_slave(pty_t * pty, uint8_t c) { - if (c == '\n' && (pty->tios.c_oflag & ONLCR)) { - uint8_t d = '\r'; - OUT(d); - } - OUT(c); +static void output_process(pty_t * pty, uint8_t c) { + if (ring_buffer_available(pty->out) < 2) return; /* uh oh */ + output_process_slave(pty, c); } static void input_process(pty_t * pty, uint8_t c) { + if (pty->tios.c_lflag & ISIG) { + if (c == pty->tios.c_cc[VINTR]) { + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '^'); + output_process(pty, '@' + c); + output_process(pty, '\n'); + } + clear_input_buffer(pty); + if (pty->fg_proc) { + send_signal(pty->fg_proc, SIGINT, 1); + } + return; + } + if (c == pty->tios.c_cc[VQUIT]) { + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '^'); + output_process(pty, '@' + c); + output_process(pty, '\n'); + } + clear_input_buffer(pty); + if (pty->fg_proc) { + send_signal(pty->fg_proc, SIGQUIT, 1); + } + return; + } + /* VSUSP */ + } +#if 0 + if (pty->tios.c_lflag & IXON ) { + /* VSTOP, VSTART */ + } +#endif if (pty->tios.c_lflag & ICANON) { if (c == pty->tios.c_cc[VKILL]) { while (pty->canon_buflen > 0) { pty->canon_buflen--; pty->canon_buffer[pty->canon_buflen] = '\0'; - if (pty->tios.c_lflag & ECHO) { + if ((pty->tios.c_lflag & ECHO) && (pty->tios.c_lflag & ECHOK)) { output_process(pty, '\010'); output_process(pty, ' '); output_process(pty, '\010'); @@ -98,7 +140,7 @@ static void input_process(pty_t * pty, uint8_t c) { if (pty->canon_buflen > 0) { pty->canon_buflen--; pty->canon_buffer[pty->canon_buflen] = '\0'; - if (pty->tios.c_lflag & ECHO) { + if ((pty->tios.c_lflag & ECHO) && (pty->tios.c_lflag & ECHOE)) { output_process(pty, '\010'); output_process(pty, ' '); output_process(pty, '\010'); @@ -106,30 +148,6 @@ static void input_process(pty_t * pty, uint8_t c) { } return; } - if (c == pty->tios.c_cc[VINTR]) { - if (pty->tios.c_lflag & ECHO) { - output_process(pty, '^'); - output_process(pty, '@' + c); - output_process(pty, '\n'); - } - clear_input_buffer(pty); - if (pty->fg_proc) { - send_signal(pty->fg_proc, SIGINT); - } - return; - } - if (c == pty->tios.c_cc[VQUIT]) { - if (pty->tios.c_lflag & ECHO) { - output_process(pty, '^'); - output_process(pty, '@' + c); - output_process(pty, '\n'); - } - clear_input_buffer(pty); - if (pty->fg_proc) { - send_signal(pty->fg_proc, SIGQUIT); - } - return; - } if (c == pty->tios.c_cc[VEOF]) { if (pty->canon_buflen) { dump_input_buffer(pty); @@ -138,6 +156,27 @@ static void input_process(pty_t * pty, uint8_t c) { } return; } + + /* ISTRIP: Strip eighth bit */ + if (pty->tios.c_iflag & ISTRIP) { + c &= 0x7F; + } + + /* IGNCR: Ignore carriage return. */ + if ((pty->tios.c_iflag & IGNCR) && c == '\r') { + return; + } + + /* INLCR: Translate NL to CR. */ + if ((pty->tios.c_iflag & INLCR) && c == '\n') { + c = '\r'; + } + + /* ICRNL: Convert carriage return. */ + if ((pty->tios.c_iflag & ICRNL) && c == '\r') { + c = '\n'; + } + if (pty->canon_buflen < pty->canon_bufsize) { pty->canon_buffer[pty->canon_buflen] = c; pty->canon_buflen++; @@ -146,6 +185,9 @@ static void input_process(pty_t * pty, uint8_t c) { output_process(pty, c); } if (c == '\n') { + if (!(pty->tios.c_lflag & ECHO) && (pty->tios.c_lflag & ECHONL)) { + output_process(pty, c); + } pty->canon_buffer[pty->canon_buflen-1] = c; dump_input_buffer(pty); return; @@ -405,7 +447,7 @@ pty_t * pty_new(struct winsize * size) { pty->tios.c_iflag = ICRNL | BRKINT; pty->tios.c_oflag = ONLCR | OPOST; pty->tios.c_lflag = ECHO | ECHOE | ECHOK | ICANON | ISIG | IEXTEN; - pty->tios.c_cflag = CREAD; + pty->tios.c_cflag = CREAD | CS8; pty->tios.c_cc[VEOF] = 4; /* ^D */ pty->tios.c_cc[VEOL] = 0; /* Not set */ pty->tios.c_cc[VERASE] = '\b'; diff --git a/kernel/fs/unixpipe.c b/kernel/fs/unixpipe.c index 93c04567..ba3a4b8f 100644 --- a/kernel/fs/unixpipe.c +++ b/kernel/fs/unixpipe.c @@ -1,16 +1,16 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -#include -#include +#include #define UNIX_PIPE_BUFFER 512 @@ -53,10 +53,7 @@ static uint32_t write_unixpipe(fs_node_t * node, uint32_t offset, uint32_t size, while (written < size) { if (self->read_closed) { /* SIGPIPE to current process */ - signal_t * sig = malloc(sizeof(signal_t)); - sig->handler = current_process->signals.functions[SIGPIPE]; - sig->signum = SIGPIPE; - handle_signal((process_t *)current_process, sig); + send_signal(getpid(), SIGPIPE, 1); return written; } @@ -90,6 +87,9 @@ static void close_write_pipe(fs_node_t * node) { debug_print(NOTICE, "Both ends now closed, should clean up."); } else { ring_buffer_interrupt(self->buffer); + if (!ring_buffer_unread(self->buffer)) { + ring_buffer_alert_waiters(self->buffer); + } } } @@ -98,6 +98,7 @@ static int check_pipe(fs_node_t * node) { if (ring_buffer_unread(self->buffer) > 0) { return 0; } + if (self->write_closed) return 0; return 1; } diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 8ca64039..dc9ec0b8 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -1,20 +1,21 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * Copyright (C) 2014 Lioncash * Copyright (C) 2012 Tianyi Wang * * Virtual File System * */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + +#include +#include #define MAX_SYMLINK_DEPTH 8 #define MAX_SYMLINK_SIZE 4096 @@ -28,7 +29,7 @@ hashmap_t * fs_types = NULL; int has_permission(fs_node_t * node, int permission_bit) { if (!node) return 0; - if (current_process->user == 0) { + if (current_process->user == 0 && permission_bit != 01) { /* even root needs exec to exec */ return 1; } @@ -87,7 +88,7 @@ static struct dirent * readdir_mapper(fs_node_t *node, uint32_t index) { static fs_node_t * vfs_mapper(void) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->mask = 0666; + fnode->mask = 0555; fnode->flags = FS_DIRECTORY; fnode->readdir = readdir_mapper; return fnode; @@ -97,26 +98,26 @@ static fs_node_t * vfs_mapper(void) { * selectcheck_fs: Check if a read from this file would block. */ int selectcheck_fs(fs_node_t * node) { - if (!node) return -1; + if (!node) return -ENOENT; if (node->selectcheck) { return node->selectcheck(node); } - return -1; + return -EINVAL; } /** * selectwait_fs: Inform a node that it should alert the current_process. */ int selectwait_fs(fs_node_t * node, void * process) { - if (!node) return -1; + if (!node) return -ENOENT; if (node->selectwait) { return node->selectwait(node, process); } - return -1; + return -EINVAL; } /** @@ -129,13 +130,13 @@ int selectwait_fs(fs_node_t * node, void * process) { * @returns Bytes read */ uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - if (!node) return -1; + if (!node) return -ENOENT; if (node->read) { uint32_t ret = node->read(node, offset, size, buffer); return ret; } else { - return -1; + return -EINVAL; } } @@ -149,13 +150,13 @@ uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffe * @returns Bytes written */ uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - if (!node) return -1; + if (!node) return -ENOENT; if (node->write) { uint32_t ret = node->write(node, offset, size, buffer); return ret; } else { - return -1; + return -EINVAL; } } @@ -285,12 +286,12 @@ fs_node_t *finddir_fs(fs_node_t *node, char *name) { * @returns Depends on `request` */ int ioctl_fs(fs_node_t *node, int request, void * argp) { - if (!node) return -1; + if (!node) return -ENOENT; if (node->ioctl) { return node->ioctl(node, request, argp); } else { - return -1; /* TODO Should actually be ENOTTY, but we're bad at error numbers */ + return -EINVAL; } } @@ -323,7 +324,7 @@ int create_file_fs(char *name, uint16_t permission) { f_path++; } - debug_print(WARNING, "creating file %s within %s (hope these strings are good)", f_path, parent_path); + debug_print(NOTICE, "creating file %s within %s (hope these strings are good)", f_path, parent_path); parent = kopen(parent_path, 0); free(parent_path); @@ -331,7 +332,7 @@ int create_file_fs(char *name, uint16_t permission) { if (!parent) { debug_print(WARNING, "failed to open parent"); free(path); - return -1; + return -ENOENT; } if (!has_permission(parent, 02)) { @@ -339,14 +340,17 @@ int create_file_fs(char *name, uint16_t permission) { return -EACCES; } + int ret = 0; if (parent->create) { - parent->create(parent, f_path, permission); + ret = parent->create(parent, f_path, permission); + } else { + ret = -EINVAL; } free(path); free(parent); - return 0; + return ret; } int unlink_fs(char * name) { @@ -377,17 +381,25 @@ int unlink_fs(char * name) { if (!parent) { free(path); - return -1; + return -ENOENT; } + if (!has_permission(parent, 02)) { + free(path); + free(parent); + return -EACCES; + } + + int ret = 0; if (parent->unlink) { - parent->unlink(parent, f_path); + ret = parent->unlink(parent, f_path); + } else { + ret = -EINVAL; } free(path); free(parent); - - return 0; + return ret; } int mkdir_fs(char *name, uint16_t permission) { @@ -428,11 +440,14 @@ int mkdir_fs(char *name, uint16_t permission) { if (_exists) { return -EEXIST; } - return -1; + return -ENOENT; } + int ret = 0; if (parent->mkdir) { - parent->mkdir(parent, f_path, permission); + ret = parent->mkdir(parent, f_path, permission); + } else { + ret = -EINVAL; } free(path); @@ -441,7 +456,7 @@ int mkdir_fs(char *name, uint16_t permission) { if (_exists) { return -EEXIST; } - return 0; + return ret; } fs_node_t *clone_fs(fs_node_t *source) { @@ -480,26 +495,29 @@ int symlink_fs(char * target, char * name) { if (!parent) { free(path); - return -1; + return -ENOENT; } + int ret = 0; if (parent->symlink) { - parent->symlink(parent, target, f_path); + ret = parent->symlink(parent, target, f_path); + } else { + ret = -EINVAL; } free(path); close_fs(parent); - return 0; + return ret; } int readlink_fs(fs_node_t *node, char * buf, uint32_t size) { - if (!node) return -1; + if (!node) return -ENOENT; if (node->readlink) { return node->readlink(node, buf, size); } else { - return -1; + return -EINVAL; } } diff --git a/kernel/gdt.S b/kernel/gdt.S index 0be46895..01c11877 100644 --- a/kernel/gdt.S +++ b/kernel/gdt.S @@ -14,6 +14,7 @@ gdt_flush: mov %ax, %es mov %ax, %fs mov %ax, %ss + mov %ax, %gs ljmp $0x08, $.flush .flush: diff --git a/kernel/include/errno_defs.h b/kernel/include/errno_defs.h deleted file mode 120000 index a9ba4ed0..00000000 --- a/kernel/include/errno_defs.h +++ /dev/null @@ -1 +0,0 @@ -../../toolchain/patches/newlib/toaru/sys/errno_defs.h \ No newline at end of file diff --git a/kernel/include/hashmap.h b/kernel/include/hashmap.h deleted file mode 100644 index ccac4afd..00000000 --- a/kernel/include/hashmap.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "list.h" - -#ifdef _KERNEL_ -# include -#else -# include -# include -# include -#endif - -typedef unsigned int (*hashmap_hash_t) (void * key); -typedef int (*hashmap_comp_t) (void * a, void * b); -typedef void (*hashmap_free_t) (void *); -typedef void * (*hashmap_dupe_t) (void *); - -typedef struct hashmap_entry { - char * key; - void * value; - struct hashmap_entry * next; -} hashmap_entry_t; - -typedef struct hashmap { - hashmap_hash_t hash_func; - hashmap_comp_t hash_comp; - hashmap_dupe_t hash_key_dup; - hashmap_free_t hash_key_free; - hashmap_free_t hash_val_free; - size_t size; - hashmap_entry_t ** entries; -} hashmap_t; - -hashmap_t * hashmap_create(int size); -hashmap_t * hashmap_create_int(int size); -void * hashmap_set(hashmap_t * map, void * key, void * value); -void * hashmap_get(hashmap_t * map, void * key); -void * hashmap_remove(hashmap_t * map, void * key); -int hashmap_has(hashmap_t * map, void * key); -list_t * hashmap_keys(hashmap_t * map); -list_t * hashmap_values(hashmap_t * map); -void hashmap_free(hashmap_t * map); - -unsigned int hashmap_string_hash(void * key); -int hashmap_string_comp(void * a, void * b); -void * hashmap_string_dupe(void * key); - diff --git a/kernel/include/ioctl.h b/kernel/include/ioctl.h deleted file mode 120000 index 036a869d..00000000 --- a/kernel/include/ioctl.h +++ /dev/null @@ -1 +0,0 @@ -../../toolchain/patches/newlib/toaru/sys/ioctl.h \ No newline at end of file diff --git a/kernel/include/list.h b/kernel/include/list.h deleted file mode 100644 index c1840138..00000000 --- a/kernel/include/list.h +++ /dev/null @@ -1,50 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * General-purpose list implementations. - */ -#pragma once - -#ifdef _KERNEL_ -# include -#else -# include -# include -# include -#endif - -typedef struct node { - struct node * next; - struct node * prev; - void * value; - void * owner; -} __attribute__((packed)) node_t; - -typedef struct { - node_t * head; - node_t * tail; - size_t length; -} __attribute__((packed)) list_t; - -void list_destroy(list_t * list); -void list_free(list_t * list); -void list_append(list_t * list, node_t * item); -node_t * list_insert(list_t * list, void * item); -list_t * list_create(void); -node_t * list_find(list_t * list, void * value); -int list_index_of(list_t * list, void * value); -void list_remove(list_t * list, size_t index); -void list_delete(list_t * list, node_t * node); -node_t * list_pop(list_t * list); -node_t * list_dequeue(list_t * list); -list_t * list_copy(list_t * original); -void list_merge(list_t * target, list_t * source); - -void list_append_after(list_t * list, node_t * before, node_t * node); -node_t * list_insert_after(list_t * list, node_t * before, void * item); - -void list_append_before(list_t * list, node_t * after, node_t * node); -node_t * list_insert_before(list_t * list, node_t * after, void * item); - -#define foreach(i, list) for (node_t * i = (list)->head; i != NULL; i = i->next) -#define foreachr(i, list) for (node_t * i = (list)->tail; i != NULL; i = i->prev) - diff --git a/kernel/include/mod/sound.h b/kernel/include/mod/sound.h deleted file mode 120000 index 398a6ca9..00000000 --- a/kernel/include/mod/sound.h +++ /dev/null @@ -1 +0,0 @@ -../../../userspace/lib/sound.h \ No newline at end of file diff --git a/kernel/include/pci_list.h b/kernel/include/pci_list.h deleted file mode 100644 index c1f480cd..00000000 --- a/kernel/include/pci_list.h +++ /dev/null @@ -1,7057 +0,0 @@ - - -#if 0 - -PCIHDR.H: PCI Vendors, Devices, and Class Type information - -Created automatically from the web using the following URL: -http://pcidatabase.com/ -Software to create and maintain the PCICODE List written by: -Jim Boemler (jboemler@halcyon.com) - - This header created on Fri Jan 16 09:49:40 PST 2009 - -Too many people have contributed to this list to acknowledge them all, but -a few have provided the majority of the input and deserve special mention: - Frederic Potter, who maintains a list for Linux. - Chris Aston at Madge Networks. - Thomas Dippon of Hewlett-Packard GmbH. - Jurgen ("Josh") Thelen - William H. Avery III at Altitech - Sergei Shtylyov of Brain-dead Software in Russia -#endif - -// NOTE that the 0xFFFF of 0xFF entries at the end of some tables below are -// not properly list terminators, but are actually the printable definitions -// of values that are legitimately found on the PCI bus. The size -// definitions should be used for loop control when the table is searched. - -typedef struct _PCI_VENTABLE -{ - unsigned short VenId ; - const char * VenShort ; - const char * VenFull ; -} PCI_VENTABLE, *PPCI_VENTABLE ; - -PCI_VENTABLE PciVenTable [] = -{ - { 0x0033, "", "Paradyne Corp." } , - { 0x003D, "well", "master" } , - { 0x0070, "Hauppauge1", "Hauppauge Computer Works Inc." } , - { 0x0100, "ncipher", "Ncipher Corp. Ltd" } , - { 0x0123, "", "General Dynamics" } , - { 0x0315, "", "SK - Electronics Co., Ltd." } , - { 0x0A89, "BREA", "BREA Technologies Inc." } , - { 0x0E11, "Compaq", "Compaq Computer Corp." } , - { 0x1000, "LSI", "LSI Logic" } , - { 0x1001, "KOLTER", "Kolter Electronic - Germany" } , - { 0x1002, "ATI", "ATI Technologies Inc." } , - { 0x1003, "ULSI", "ULSI" } , - { 0x1004, "VLSI", "VLSI Technology" } , - { 0x1006, "Reply", "Reply Group" } , - { 0x1007, "NetFrame", "Netframe Systems Inc." } , - { 0x1008, "Epson", "Epson" } , - { 0x100A, "Phoenix", "Phoenix Technologies Ltd." } , - { 0x100B, "NSC", "National Semiconductors" } , - { 0x100C, "Tseng", "Tseng Labs" } , - { 0x100D, "AST", "AST Research" } , - { 0x100E, "Weitek", "Weitek" } , - { 0x1010, "VLogic", "Video Logic Ltd." } , - { 0x1011, "DEC", "Digital Equipment Corporation" } , - { 0x1012, "Micronics", "Micronics Computers Inc." } , - { 0x1013, "Cirrus", "Cirrus Logic" } , - { 0x1014, "IBM", "International Business Machines Corp." } , - { 0x1016, "Fujitsu ICL", "Fujitsu ICL Computers" } , - { 0x1017, "Spea", "Spea Software AG" } , - { 0x1018, "Unisys", "Unisys Systems" } , - { 0x1019, "ECS", "Elitegroup Computer System" } , - { 0x101A, "NCR", "NCR Corporation" } , - { 0x101B, "Vitesse", "Vitesse Semiconductor" } , - { 0x101E, "AMI", "American Megatrends Inc." } , - { 0x101F, "PictureTel", "PictureTel Corp." } , - { 0x1020, "Hitachi", "Hitachi Computer Electronics" } , - { 0x1021, "OKI", "Oki Electric Industry" } , - { 0x1022, "AMD", "Advanced Micro Devices" } , - { 0x1023, "machdo", "TRIDENT MICRO" } , - { 0x1025, "Acer", "Acer Incorporated" } , - { 0x1028, "Dell", "Dell Computer Corporation" } , - { 0x102A, "LSI", "LSI Logic Headland Division" } , - { 0x102B, "Matrox", "Matrox Electronic Systems Ltd." } , - { 0x102C, "C&T", "Asiliant (Chips And Technologies)" } , - { 0x102D, "Wyse", "Wyse Technologies" } , - { 0x102E, "Olivetti", "Olivetti Advanced Technology" } , - { 0x102F, "A305-S6829", "Toshiba America" } , - { 0x1030, "TMC", "TMC Research" } , - { 0x1031, "miro", "miro Computer Products AG" } , - { 0x1033, "NEC", "NEC Electronics" } , - { 0x1034, "Burndy", "Burndy Corporation" } , - { 0x1036, "FDomain", "Future Domain" } , - { 0x1037, "Hitachi", "Hitachi Micro Systems Inc" } , - { 0x1038, "AMP", "AMP Incorporated" } , - { 0x1039, "SiS 630", "Silicon Integrated Systems" } , - { 0x103A, "Seiko", "Seiko Epson Corporation" } , - { 0x103B, "Tatung", "Tatung Corp. Of America" } , - { 0x103C, "HP", "Hewlett-Packard Company" } , - { 0x103E, "Solliday", "Solliday Engineering" } , - { 0x103F, "Logic Mod.", "Logic Modeling" } , - { 0x1041, "Computrend", "Computrend" } , - { 0x1043, "Asustek", "Asustek Computer Inc." } , - { 0x1044, "DPT", "Distributed Processing Tech" } , - { 0x1045, "OPTi", "OPTi Inc." } , - { 0x1046, "IPC", "IPC Corporation LTD" } , - { 0x1047, "Genoa", "Genoa Systems Corp." } , - { 0x1048, "ELSA", "ELSA GmbH" } , - { 0x1049, "Fountain", "Fountain Technology" } , - { 0x104A, "STM", "STMicroelectronics" } , - { 0x104B, "", "Mylex / Buslogic" } , - { 0x104C, "TI", "Texas Instruments" } , - { 0x104D, "Sony", "Sony Corporation" } , - { 0x104E, "Oak", "Oak Technology" } , - { 0x104F, "Co-Time", "Co-Time Computer Ltd." } , - { 0x1050, "Winbond", "Winbond Electronics Corp." } , - { 0x1051, "Anigma", "Anigma Corp." } , - { 0x1053, "Young", "Young Micro Systems" } , - { 0x1054, "Hitachi", "Hitachi Ltd" } , - { 0x1055, "SMSC", "Standard Microsystems Corp." } , - { 0x1056, "ICL", "ICL" } , - { 0x1057, "Motorola", "Motorola" } , - { 0x1058, "E&TR", "Electronics & Telecommunication Res" } , - { 0x1059, "Kontron", "Kontron Canada" } , - { 0x105A, "Promise", "Promise Technology" } , - { 0x105B, "Foxconn", "Foxconn International Inc." } , - { 0x105C, "Wipro", "Wipro Infotech Limited" } , - { 0x105D, "Number-Nine", "Number Nine Visual Technology" } , - { 0x105E, "Vtech", "Vtech Engineering Canada Ltd." } , - { 0x105F, "Infotronic", "Infotronic America Inc." } , - { 0x1060, "UMC", "United Microelectronics" } , - { 0x1061, "8x8", "8x8 Inc." } , - { 0x1062, "Maspar", "Maspar Computer Corp." } , - { 0x1063, "OOA", "Ocean Office Automation" } , - { 0x1064, "Alcatel", "Alcatel Cit" } , - { 0x1065, "TM", "Texas Microsystems" } , - { 0x1066, "Picopower", "Picopower Technology" } , - { 0x1067, "Mitsubishi", "Mitsubishi Electronics" } , - { 0x1068, "Div. Tech.", "Diversified Technology" } , - { 0x106A, "Aten", "Aten Research Inc." } , - { 0x106B, "Apple", "Power Mac G5 Quad" } , - { 0x106C, "Hyundai", "Hyundai Electronics America" } , - { 0x106D, "Sequent", "Sequent Computer Systems" } , - { 0x106E, "DFI", "DFI Inc." } , - { 0x106F, "CityGate", "City Gate Development LTD" } , - { 0x1070, "Daewoo", "Daewoo Telecom Ltd." } , - { 0x1071, "Mitac", "Mitac" } , - { 0x1072, "GIT", "GIT Co. Ltd." } , - { 0x1073, "Yamaha", "Yamaha Corporation" } , - { 0x1074, "Nexgen", "Nexgen Microsystems" } , - { 0x1075, "AIR", "Advanced Integration Research" } , - { 0x1077, "QLogic", "QLogic Corporation" } , - { 0x1078, "Cyrix", "Cyrix Corporation" } , - { 0x1079, "I-Bus", "I-Bus" } , - { 0x107A, "Networth", "Networth controls" } , - { 0x107B, "Gateway", "Gateway 2000" } , - { 0x107C, "Goldstar", "Goldstar Co. Ltd." } , - { 0x107D, "Leadtek", "Leadtek Research" } , - { 0x107E, "Interphase", "Testernec" } , - { 0x107F, "DTC", "Data Technology Corporation" } , - { 0x1080, "Cypress", "Cypress Semiconductor" } , - { 0x1081, "Radius Inc.", "Radius Inc." } , - { 0x1082, "EFA", "EFA Corporation Of America" } , - { 0x1083, "Forex", "Forex Computer Corporation" } , - { 0x1084, "Parador", "Parador" } , - { 0x1085, "Tulip", "Tulip Computers Int'l BV" } , - { 0x1086, "J. Bond", "J. Bond Computer Systems" } , - { 0x1087, "Cache", "Cache Computer" } , - { 0x1088, "MS Son.", "Microcomputer Systems (M) Son" } , - { 0x1089, "DG", "Data General Corporation" } , - { 0x108A, "Bit3", "SBS Operations" } , - { 0x108C, "Oakleigh", "Oakleigh Systems Inc." } , - { 0x108D, "Olicom", "Olicom" } , - { 0x108E, "Sun", "Sun Microsystems" } , - { 0x108F, "Systemsoft", "Systemsoft Corporation" } , - { 0x1090, "Encore", "Encore Computer Corporation" } , - { 0x1091, "Intergraph", "Intergraph Corporation" } , - { 0x1092, "Diamond", "Diamond Computer Systems" } , - { 0x1093, "Nat. Inst.", "National Instruments" } , - { 0x1094, "FIC", "First Int'l Computers" } , - { 0x1095, "Silicon Image", "Silicon Image, Inc." } , - { 0x1096, "Alacron", "Alacron" } , - { 0x1097, "Appian", "Appian Graphics" } , - { 0x1098, "Quantum", "Quantum Designs Ltd." } , - { 0x1099, "Samsung", "Samsung Electronics Co. Ltd." } , - { 0x109A, "Packard-Bell", "Packard Bell" } , - { 0x109B, "Gemlight", "Gemlight Computer Ltd." } , - { 0x109C, "Megachips", "Megachips Corporation" } , - { 0x109D, "Zida", "Zida Technologies Ltd." } , - { 0x109E, "Brooktree", "Brooktree Corporation" } , - { 0x109F, "Trigem", "Trigem Computer Inc." } , - { 0x10A0, "Meidensha", "Meidensha Corporation" } , - { 0x10A1, "Juko", "Juko Electronics Inc. Ltd." } , - { 0x10A2, "Quantum", "Quantum Corporation" } , - { 0x10A3, "Everex", "Everex Systems Inc." } , - { 0x10A4, "Globe", "Globe Manufacturing Sales" } , - { 0x10A5, "Racal", "Racal Interlan" } , - { 0x10A8, "Sierra", "Sierra Semiconductor" } , - { 0x10A9, "SG", "Silicon Graphics" } , - { 0x10AB, "Digicom", "Digicom" } , - { 0x10AC, "Honeywell", "Honeywell IASD" } , - { 0x10AD, "Winbond", "Winbond Systems Labs" } , - { 0x10AE, "Cornerstone", "Cornerstone Technology" } , - { 0x10AF, "MCS", "Micro Computer Systems Inc." } , - { 0x10B0, "CardExpert", "CardExpert Technology" } , - { 0x10B1, "Cabletron", "Cabletron Systems Inc." } , - { 0x10B2, "Raytheon", "Raytheon Company" } , - { 0x10B3, "Databook", "Databook Inc." } , - { 0x10B4, "STB", "STB Systems" } , - { 0x10B5, "PLX", "PLX Technology Inc." } , - { 0x10B6, "Madge", "Madge Networks" } , - { 0x10B7, "3Com", "3Com Corporation" } , - { 0x10B8, "SMC", "Standard Microsystems Corporation" } , - { 0x10B9, "Ali", "Ali Corporation" } , - { 0x10BA, "Mitsubishi", "Mitsubishi Electronics Corp." } , - { 0x10BB, "Dapha", "Dapha Electronics Corporation" } , - { 0x10BC, "ALR", "Advanced Logic Research Inc." } , - { 0x10BD, "Surecom", "Surecom Technology" } , - { 0x10BE, "Tseng", "Tsenglabs International Corp." } , - { 0x10BF, "MOST", "MOST Corp." } , - { 0x10C0, "Boca", "Boca Research Inc." } , - { 0x10C1, "ICM", "ICM Corp. Ltd." } , - { 0x10C2, "Auspex", "Auspex Systems Inc." } , - { 0x10C3, "Samsung", "Samsung Semiconductors" } , - { 0x10C4, "wim", "Award Software Int'l Inc." } , - { 0x10C5, "Xerox", "Xerox Corporation" } , - { 0x10C6, "Rambus", "Rambus Inc." } , - { 0x10C8, "Neomagic", "Neomagic Corporation" } , - { 0x10C9, "Dataexpert", "Dataexpert Corporation" } , - { 0x10CA, "Fujitsu", "Fujitsu Siemens" } , - { 0x10CB, "Omron", "Omron Corporation" } , - { 0x10CD, "AdvanSys", "Advanced System Products" } , - { 0x10CF, "Fujitsu", "Fujitsu Ltd." } , - { 0x10D1, "Future+", "Future+ Systems" } , - { 0x10D2, "Molex", "Molex Incorporated" } , - { 0x10D3, "Jabil", "Jabil Circuit Inc." } , - { 0x10D4, "Hualon", "Hualon Microelectronics" } , - { 0x10D5, "Autologic", "Autologic Inc." } , - { 0x10D6, "Wilson .co .ltd", "Wilson .co .ltd" } , - { 0x10D7, "BCM", "BCM Advanced Research" } , - { 0x10D8, "APL", "Advanced Peripherals Labs" } , - { 0x10D9, "Macronix", "Macronix International Co. Ltd." } , - { 0x10DB, "Rohm", "Rohm Research" } , - { 0x10DC, "CERN", "CERN-European Lab. for Particle Physics" } , - { 0x10DD, "E&S", "Evans & Sutherland" } , - { 0x10DE, "NVIDIA", "NVIDIA" } , - { 0x10DF, "Emulex", "Emulex Corporation" } , - { 0x10E1, "Tekram", "Tekram Technology Corp. Ltd." } , - { 0x10E2, "Aptix", "Aptix Corporation" } , - { 0x10E3, "Tundra", "Tundra Semiconductor Corp." } , - { 0x10E4, "Tandem", "Tandem Computers" } , - { 0x10E5, "MIC", "Micro Industries Corporation" } , - { 0x10E6, "Gainbery", "Gainbery Computer Products Inc." } , - { 0x10E7, "Vadem", "Vadem" } , - { 0x10E8, "AMCC", "Applied Micro Circuits Corp." } , - { 0x10E9, "Alps", "Alps Electronic Corp. Ltd." } , - { 0x10EA, "Tvia", "Tvia, Inc." } , - { 0x10EB, "Artist", "Artist Graphics" } , - { 0x10EC, "Realtek", "Realtek Semiconductor" } , - { 0x10ED, "Ascii", "Ascii Corporation" } , - { 0x10EE, "Xilinx", "Xilinx Corporation" } , - { 0x10EF, "Racore", "Racore Computer Products" } , - { 0x10F0, "Real-Time Graphics & Video", "Curtiss-Wright Controls Embedded Computing" } , - { 0x10F1, "Tyan", "Tyan Computer" } , - { 0x10F2, "Achme", "Achme Computer Inc. - GONE !!!!" } , - { 0x10F3, "Alaris", "Alaris Inc." } , - { 0x10F4, "S-Mos", "S-Mos Systems" } , - { 0x10F5, "NKK", "NKK Corporation" } , - { 0x10F6, "CES", "Creative Electronic Systems SA" } , - { 0x10F7, "Matsushita", "Matsushita Electric Industrial Corp." } , - { 0x10F8, "Altos", "Altos India Ltd." } , - { 0x10F9, "PC-Direct", "PC Direct" } , - { 0x10FA, "Truevision", "Truevision" } , - { 0x10FB, "Thesys", "Thesys Microelectronic's" } , - { 0x10FC, "I-O", "I-O Data Device Inc." } , - { 0x10FD, "Soyo", "Soyo Technology Corp. Ltd." } , - { 0x10FE, "Fast", "Fast Electronic GmbH" } , - { 0x10FF, "Ncube", "Ncube" } , - { 0x1100, "Jazz", "Jazz Multimedia" } , - { 0x1101, "Initio", "Initio Corporation" } , - { 0x1102, "Creative Labs", "Creative Technology LTD." } , - { 0x1103, "Highpoint", "Triones Technologies Inc. (HighPoint)" } , - { 0x1104, "Rasterops", "Rasterops" } , - { 0x1105, "Sigma", "Sigma Designs Inc." } , - { 0x1106, "VIA", "VIA Technology" } , - { 0x1107, "Stratus", "Stratus Computer" } , - { 0x1108, "Proteon", "Proteon Inc." } , - { 0x1109, "Cogent", "Adaptec/Cogent Data Technologies" } , - { 0x110A, "Siemens", "Siemens Nixdorf AG" } , - { 0x110B, "Chromatic", "Chromatic Research Inc" } , - { 0x110C, "Mini-Max", "Mini-Max Technology Inc." } , - { 0x110D, "ZNYX", "ZNYX Corporation" } , - { 0x110E, "CPU Tech.", "CPU Technology" } , - { 0x110F, "Ross", "Ross Technology" } , - { 0x1112, "Osicom", "Osicom Technologies Inc." } , - { 0x1113, "Accton", "Accton Technology Corporation" } , - { 0x1114, "Atmel", "Atmel Corp." } , - { 0x1116, "Data Translation", "Data Translation, Inc." } , - { 0x1117, "Datacube", "Datacube Inc." } , - { 0x1118, "Berg", "Berg Electronics" } , - { 0x1119, "Vortex", "ICP vortex Computersysteme GmbH" } , - { 0x111A, "Eff. Net.", "Efficent Networks" } , - { 0x111C, "Tricord", "Tricord Systems Inc." } , - { 0x111D, "IDT", "Integrated Device Technology Inc." } , - { 0x111F, "PDI", "Precision Digital Images" } , - { 0x1120, "EMC", "EMC Corp." } , - { 0x1121, "Zilog", "Zilog" } , - { 0x1123, "EDI", "Excellent Design Inc." } , - { 0x1124, "Leutron", "Leutron Vision AG" } , - { 0x1125, "Eurocore", "Eurocore/Vigra" } , - { 0x1127, "FORE RUNNER LE", "FORE Systems" } , - { 0x1129, "Firmworks", "Firmworks" } , - { 0x112A, "Hermes", "Hermes Electronics Co. Ltd." } , - { 0x112C, "Zenith", "Zenith Data Systems" } , - { 0x112D, "Ravicad", "Ravicad" } , - { 0x112E, "Infomedia", "Infomedia" } , - { 0x1130, "Computervision", "Computervision" } , - { 0x1131, "72c0ai913629", "Philips Semiconductors" } , - { 0x1132, "Mitel", "Mitel Corp." } , - { 0x1133, "EIC", "Eicon Networks Corporation" } , - { 0x1134, "MCS", "Mercury Computer Systems Inc." } , - { 0x1135, "Fuji", "Fuji Xerox Co Ltd" } , - { 0x1136, "Momentum", "Momentum Data Systems" } , - { 0x1137, "Cisco", "Cisco Systems Inc" } , - { 0x1138, "Ziatech", "Ziatech Corporation" } , - { 0x1139, "Dyn. Pict.", "Dynamic Pictures Inc" } , - { 0x113A, "FWB", "FWB Inc" } , - { 0x113B, "NCD", "Network Computing Devices" } , - { 0x113C, "Cyclone", "Cyclone Microsystems Inc." } , - { 0x113D, "Leading Edge", "Leading Edge Products Inc" } , - { 0x113E, "Sanyo", "Sanyo Electric Co" } , - { 0x113F, "Equinox", "Equinox Systems" } , - { 0x1140, "Intervoice", "Intervoice Inc" } , - { 0x1141, "Crest", "Crest Microsystem Inc" } , - { 0x1142, "Alliance", "Alliance Semiconductor" } , - { 0x1143, "Netpower", "Netpower Inc" } , - { 0x1144, "Cinn. Mil.", "Cincinnati Milacron" } , - { 0x1145, "Workbit", "Workbit Corp" } , - { 0x1146, "Force", "Force Computers" } , - { 0x1147, "Interface", "Interface Corp" } , - { 0x1148, "Marvell", "Marvell Semiconductor Germany GmbH" } , - { 0x1149, "Win System", "Win System Corporation" } , - { 0x114A, "VMIC", "VMIC" } , - { 0x114B, "Canopus", "Canopus corporation" } , - { 0x114C, "Annabooks", "Annabooks" } , - { 0x114D, "IC Corp.", "IC Corporation" } , - { 0x114E, "Nikon", "Nikon Systems Inc" } , - { 0x114F, "Digi", "Digi International" } , - { 0x1150, "TMC", "Thinking Machines Corporation" } , - { 0x1151, "JAE", "JAE Electronics Inc." } , - { 0x1153, "Land Win", "Land Win Electronic Corp" } , - { 0x1154, "Melco", "Melco Inc" } , - { 0x1155, "Pine", "Pine Technology Ltd" } , - { 0x1156, "Periscope", "Periscope Engineering" } , - { 0x1157, "Avsys", "Avsys Corporation" } , - { 0x1158, "Voarx", "Voarx R&D Inc" } , - { 0x1159, "Mutech", "Mutech" } , - { 0x115A, "Harlequin", "Harlequin Ltd" } , - { 0x115B, "Parallax", "Parallax Graphics" } , - { 0x115C, "Photron", "Photron Ltd." } , - { 0x115D, "Xircom", "Xircom" } , - { 0x115E, "Peer", "Peer Protocols Inc" } , - { 0x115F, "Maxtorr", "Maxtor Corporation" } , - { 0x1160, "Megasoft", "Megasoft Inc" } , - { 0x1161, "PFU", "PFU Ltd" } , - { 0x1162, "OA Lab", "OA Laboratory Co Ltd" } , - { 0x1163, "Rendition", "Rendition Inc" } , - { 0x1164, "APT", "Advanced Peripherals Tech" } , - { 0x1165, "Imagraph", "Imagraph Corporation" } , - { 0x1166, "BRCM/ServerWorks", "Broadcom / ServerWorks" } , - { 0x1167, "Mutoh", "Mutoh Industries Inc" } , - { 0x1168, "Thine", "Thine Electronics Inc" } , - { 0x1169, "CDAC", "Centre f/Dev. of Adv. Computing" } , - { 0x116A, "Luminex", "Luminex Software, Inc" } , - { 0x116B, "Connectware", "Connectware Inc" } , - { 0x116C, "Int Res.", "Intelligent Resources" } , - { 0x116E, "EFI", "Electronics for Imaging" } , - { 0x1170, "Inventec", "Inventec Corporation" } , - { 0x1172, "Altera", "Altera Corporation" } , - { 0x1173, "Adobe", "Adobe Systems" } , - { 0x1174, "Bridgeport", "Bridgeport Machines" } , - { 0x1175, "Mitron", "Mitron Computer Inc." } , - { 0x1176, "SBE", "SBE" } , - { 0x1177, "Silicon Eng.", "Silicon Engineering" } , - { 0x1178, "Alfa", "Alfa Inc" } , - { 0x1179, "Toshiba", "Toshiba America Info Systems" } , - { 0x117A, "A-Trend", "A-Trend Technology" } , - { 0x117B, "LG", "LG (Lucky Goldstar) Electronics Inc." } , - { 0x117C, "Atto", "Atto Technology" } , - { 0x117D, "B&D", "Becton & Dickinson" } , - { 0x117E, "T/R", "T/R Systems" } , - { 0x117F, "ICS", "Integrated Circuit Systems" } , - { 0x1180, "Ricoh", "Ricoh Company, Ltd." } , - { 0x1183, "Fujikura", "Fujikura Ltd" } , - { 0x1184, "Forks", "Forks Inc" } , - { 0x1185, "Dataworld", "Dataworld" } , - { 0x1186, "D-Link", "D-Link System Inc" } , - { 0x1187, "ATL", "Advanced Technology Laboratories" } , - { 0x1188, "Shima", "Shima Seiki Manufacturing Ltd." } , - { 0x1189, "Matsushita", "Matsushita Electronics" } , - { 0x118A, "Hilevel", "Hilevel Technology" } , - { 0x118B, "Hypertec", "Hypertec Pty Ltd" } , - { 0x118C, "Corollary", "Corollary Inc" } , - { 0x118D, "BitFlow", "BitFlow Inc" } , - { 0x118E, "Hermstedt", "Hermstedt AG" } , - { 0x118F, "Green", "Green Logic" } , - { 0x1190, "Tripace", "Tripace" } , - { 0x1191, "Acard", "Acard Technology Corp." } , - { 0x1192, "Densan", "Densan Co. Ltd" } , - { 0x1194, "Toucan", "Toucan Technology" } , - { 0x1195, "Ratoc", "Ratoc System Inc" } , - { 0x1196, "Hytec", "Hytec Electronics Ltd" } , - { 0x1197, "Gage", "Gage Applied Technologies" } , - { 0x1198, "Lambda", "Lambda Systems Inc" } , - { 0x1199, "Attachmate", "Attachmate Corp." } , - { 0x119A, "Mind Share", "Mind/Share Inc." } , - { 0x119B, "Omega", "Omega Micro Inc." } , - { 0x119C, "ITI", "Information Technology Inst." } , - { 0x119D, "Bug", "Bug Sapporo Japan" } , - { 0x119E, "Fujitsu", "Fujitsu Microelectronics Ltd." } , - { 0x119F, "Bull", "Bull Hn Information Systems" } , - { 0x11A1, "Hamamatsu", "Hamamatsu Photonics K.K." } , - { 0x11A2, "Sierra", "Sierra Research and Technology" } , - { 0x11A3, "Deuretzbacher", "Deuretzbacher GmbH & Co. Eng. KG" } , - { 0x11A4, "Barco", "Barco" } , - { 0x11A5, "MicroUnity", "MicroUnity Systems Engineering Inc." } , - { 0x11A6, "Pure Data", "Pure Data" } , - { 0x11A7, "Power Comp.", "Power Computing Corp." } , - { 0x11A8, "Systech", "Systech Corp." } , - { 0x11A9, "InnoSys", "InnoSys Inc." } , - { 0x11AA, "Actel", "Actel" } , - { 0x11AB, "Marvell", "Marvell Semiconductor" } , - { 0x11AC, "Canon", "Canon Information Systems" } , - { 0x11AD, "Lite-On", "Lite-On Technology Corp." } , - { 0x11AE, "Scitex", "Scitex Corporation Ltd" } , - { 0x11AF, "Avid", "Avid Technology, Inc." } , - { 0x11B0, "QuickLogic", "Quicklogic Corp" } , - { 0x11B1, "Apricot", "Apricot Computers" } , - { 0x11B2, "Kodak", "Eastman Kodak" } , - { 0x11B3, "Barr", "Barr Systems Inc." } , - { 0x11B4, "Leitch", "Leitch Technology International" } , - { 0x11B5, "Radstone", "Radstone Technology Ltd." } , - { 0x11B6, "United Video", "United Video Corp" } , - { 0x11B7, "Motorola", "Motorola" } , - { 0x11B8, "Xpoint", "Xpoint Technologies Inc" } , - { 0x11B9, "Pathlight", "Pathlight Technology Inc." } , - { 0x11BA, "Videotron", "Videotron Corp" } , - { 0x11BB, "Pyramid", "Pyramid Technology" } , - { 0x11BC, "Net. Periph.", "Network Peripherals Inc" } , - { 0x11BD, "NABOHO", "lota" } , - { 0x11BE, "IMI", "International Microcircuits Inc" } , - { 0x11BF, "Astrodesign", "Astrodesign Inc." } , - { 0x11C1, "Agere", "Erick Medina" } , - { 0x11C2, "Sand", "Sand Microelectronics" } , - { 0x11C4, "Doc. Tech.", "Document Technologies Ind." } , - { 0x11C5, "Shiva", "Shiva Corporatin" } , - { 0x11C6, "Dainippon", "Dainippon Screen Mfg. Co" } , - { 0x11C7, "D.C.M.", "D.C.M. Data Systems" } , - { 0x11C8, "Dolphin", "Dolphin Interconnect Solutions" } , - { 0x11C9, "MAGMA", "MAGMA" } , - { 0x11CA, "LSI Sys.", "LSI Systems Inc" } , - { 0x11CB, "Specialix", "Specialix International Ltd." } , - { 0x11CC, "M&K", "Michels & Kleberhoff Computer GmbH" } , - { 0x11CD, "HAL", "HAL Computer Systems Inc." } , - { 0x11CE, "PRI", "Primary Rate Inc" } , - { 0x11CF, "PEC", "Pioneer Electronic Corporation" } , - { 0x11D0, "BAE", "BAE SYSTEMS - Manassas" } , - { 0x11D1, "AuraVision", "AuraVision Corporation" } , - { 0x11D2, "Intercom", "Intercom Inc." } , - { 0x11D3, "Trancell", "Trancell Systems Inc" } , - { 0x11D4, "ADI", "Analog Devices, Inc." } , - { 0x11D5, "Tahoma", "Tahoma Technology" } , - { 0x11D6, "Tekelec", "Tekelec Technologies" } , - { 0x11D7, "Trenton", "TRENTON Technology, Inc." } , - { 0x11D8, "ITD", "Image Technologies Development" } , - { 0x11D9, "Tec", "Tec Corporation" } , - { 0x11DA, "Novell", "Novell" } , - { 0x11DB, "Sega", "Sega Enterprises Ltd" } , - { 0x11DC, "Questra", "Questra Corp" } , - { 0x11DD, "Crosfield", "Crosfield Electronics Ltd" } , - { 0x11DE, "Zoran", "Zoran Corporation" } , - { 0x11E1, "Gec Plessey", "Gec Plessey Semi Inc" } , - { 0x11E2, "Samsung", "Samsung Information Systems America" } , - { 0x11E3, "QuickLogic", "Quicklogic Corp" } , - { 0x11E4, "Second Wave", "Second Wave Inc" } , - { 0x11E5, "IIX", "IIX Consulting" } , - { 0x11E6, "Mitsui", "Mitsui-Zosen System Research" } , - { 0x11E8, "DPSI", "Digital Processing Systems Inc" } , - { 0x11E9, "Highwater", "Highwater Designs Ltd" } , - { 0x11EA, "Elsag", "Elsag Bailey" } , - { 0x11EB, "Formation", "Formation, Inc" } , - { 0x11EC, "Coreco", "Coreco Inc" } , - { 0x11ED, "Mediamatics", "Mediamatics" } , - { 0x11EE, "Dome", "Dome Imaging Systems Inc" } , - { 0x11EF, "Nicolet", "Nicolet Technologies BV" } , - { 0x11F0, "Compu-Shack", "Compu-Shack GmbH" } , - { 0x11F2, "Pic-Tel", "Picture Tel Japan KK" } , - { 0x11F3, "Keithley", "Keithley Metrabyte" } , - { 0x11F4, "Kinetic", "Kinetic Systems Corporation" } , - { 0x11F5, "Comp Dev", "Computing Devices Intl" } , - { 0x11F6, "Powermatic", "Powermatic Data Systems Ltd" } , - { 0x11F7, "S-A", "Scientific Atlanta" } , - { 0x11F8, "PMC-Sierra", "PMC-Sierra Inc." } , - { 0x11F9, "I-Cube", "I-Cube Inc" } , - { 0x11FA, "Kasan", "Kasan Electronics Co Ltd" } , - { 0x11FB, "Datel", "Datel Inc" } , - { 0x11FD, "High Street", "High Street Consultants" } , - { 0x11FE, "Comtrol", "Comtrol Corp" } , - { 0x11FF, "Scion", "Scion Corp" } , - { 0x1200, "CSS", "CSS Corp" } , - { 0x1201, "Vista", "Vista Controls Corp" } , - { 0x1202, "Network Gen", "Network General Corp" } , - { 0x1203, "Agfa", "Bayer Corporation Agfa Div" } , - { 0x1204, "Lattice", "Lattice Semiconductor Corp" } , - { 0x1205, "Array", "Array Corp" } , - { 0x1206, "Amdahl", "Amdahl Corp" } , - { 0x1208, "Parsytec", "Parsytec GmbH" } , - { 0x1209, "Sci Sys", "Sci Systems Inc" } , - { 0x120A, "Synaptel", "Synaptel" } , - { 0x120B, "Adaptive", "Adaptive Solutions" } , - { 0x120D, "Comp Labs", "Compression Labs Inc." } , - { 0x120E, "Cyclades", "Cyclades Corporation" } , - { 0x120F, "Essential", "Essential Communications" } , - { 0x1210, "Hyperparallel", "Hyperparallel Technologies" } , - { 0x1211, "Braintech", "Braintech Inc" } , - { 0x1213, "AISI", "Applied Intelligent Systems Inc" } , - { 0x1214, "Perf Tech", "Performance Technologies Inc" } , - { 0x1215, "Interware", "Interware Co Ltd" } , - { 0x1216, "Purup Eskofot", "Purup-Eskofot A/S" } , - { 0x1217, "O2Micro", "O2Micro Inc" } , - { 0x1218, "Hybricon", "Hybricon Corp" } , - { 0x1219, "First Virtual", "First Virtual Corp" } , - { 0x121A, "3dfx", "3dfx Interactive Inc" } , - { 0x121B, "ATM", "Advanced Telecommunications Modules" } , - { 0x121C, "Nippon Texa", "Nippon Texa Co Ltd" } , - { 0x121D, "Lippert", "Lippert Automationstechnik GmbH" } , - { 0x121E, "CSPI", "CSPI" } , - { 0x121F, "Arcus", "Arcus Technology Inc" } , - { 0x1220, "Ariel", "Ariel Corporation" } , - { 0x1221, "Contec", "Contec Microelectronics Europe BV" } , - { 0x1222, "Ancor", "Ancor Communications Inc" } , - { 0x1223, "Emerson Network Power", "Emerson Network Power, Embedded Computing" } , - { 0x1224, "Int. Img.", "Interactive Images" } , - { 0x1225, "Power IO", "Power I/O Inc." } , - { 0x1227, "Tech-Source", "Tech-Source" } , - { 0x1228, "Norsk", "Norsk Elektro Optikk A/S" } , - { 0x1229, "Data Kin", "Data Kinesis Inc." } , - { 0x122A, "Int. Telecom", "Integrated Telecom" } , - { 0x122B, "LG Ind.", "LG Industrial Systems Co. Ltd." } , - { 0x122C, "sci-worx", "sci-worx GmbH" } , - { 0x122D, "Aztech", "Aztech System Ltd" } , - { 0x122E, "Xyratex", "Xyratex" } , - { 0x122F, "Andrew", "Andrew Corp." } , - { 0x1230, "Fishcamp", "Fishcamp Engineering" } , - { 0x1231, "WMI", "Woodward McCoach Inc." } , - { 0x1233, "Bus-Tech", "Bus-Tech Inc." } , - { 0x1234, "Bochs", "Bochs" } , - { 0x1236, "Sigma Designs", "Sigma Designs, Inc" } , - { 0x1237, "Alta Tech", "Alta Technology Corp." } , - { 0x1238, "Adtran", "Adtran" } , - { 0x1239, "3DO", "The 3DO Company" } , - { 0x123A, "Visicom", "Visicom Laboratories Inc." } , - { 0x123B, "Seeq", "Seeq Technology Inc." } , - { 0x123C, "Century Sys", "Century Systems Inc." } , - { 0x123D, "EDT", "Engineering Design Team Inc." } , - { 0x123F, "C-Cube", "C-Cube Microsystems" } , - { 0x1240, "Marathon", "Marathon Technologies Corp." } , - { 0x1241, "DSC", "DSC Communications" } , - { 0x1242, "JNI", "JNI Corporation" } , - { 0x1243, "Delphax", "Delphax" } , - { 0x1244, "AVM", "AVM AUDIOVISUELLES MKTG & Computer GmbH" } , - { 0x1245, "APD", "APD S.A." } , - { 0x1246, "Dipix", "Dipix Technologies Inc" } , - { 0x1247, "Xylon", "Xylon Research Inc." } , - { 0x1248, "Central Data", "Central Data Corp." } , - { 0x1249, "Samsung", "Samsung Electronics Co. Ltd." } , - { 0x124A, "AEG", "AEG Electrocom GmbH" } , - { 0x124C, "Solitron", "Solitron Technologies Inc." } , - { 0x124D, "Stallion", "Stallion Technologies" } , - { 0x124E, "Cylink", "Cylink" } , - { 0x124F, "Infortrend", "Infortrend Technology Inc" } , - { 0x1250, "Hitachi", "Hitachi Microcomputer System Ltd." } , - { 0x1251, "VLSI Sol.", "VLSI Solution OY" } , - { 0x1253, "Guzik", "Guzik Technical Enterprises" } , - { 0x1254, "Linear Systems", "Linear Systems Ltd." } , - { 0x1255, "Optibase", "Optibase Ltd." } , - { 0x1256, "Perceptive", "Perceptive Solutions Inc." } , - { 0x1257, "Vertex", "Vertex Networks Inc." } , - { 0x1258, "Gilbarco", "Gilbarco Inc." } , - { 0x1259, "Allied Tsyn", "Allied Telesyn International" } , - { 0x125A, "ABB Pwr", "ABB Power Systems" } , - { 0x125B, "Asix", "Asix Electronics Corp." } , - { 0x125C, "Aurora", "Aurora Technologies Inc." } , - { 0x125D, "ESS", "ESS Technology" } , - { 0x125E, "Specvideo", "Specialvideo Engineering SRL" } , - { 0x125F, "Concurrent", "Concurrent Technologies Inc." } , - { 0x1260, "Intersil", "Intersil Corporation" } , - { 0x1261, "Matsushita", "Matsushita-Kotobuki Electronics Indu" } , - { 0x1262, "ES Comp.", "ES Computer Co. Ltd." } , - { 0x1263, "Sonic Sol.", "Sonic Solutions" } , - { 0x1264, "Aval Nag.", "Aval Nagasaki Corp." } , - { 0x1265, "Casio", "Casio Computer Co. Ltd." } , - { 0x1266, "Microdyne", "Microdyne Corp." } , - { 0x1267, "SA Telecom", "S.A. Telecommunications" } , - { 0x1268, "Tektronix", "Tektronix" } , - { 0x1269, "SGS Thomson", "Thomson-CSF/TTM" } , - { 0x126A, "Lexmark", "Lexmark International Inc." } , - { 0x126B, "Adax", "Adax Inc." } , - { 0x126C, "Nortel", "Nortel Networks Corp." } , - { 0x126D, "Splash", "Splash Technology Inc." } , - { 0x126E, "Sumitomo", "Sumitomo Metal Industries Ltd." } , - { 0x126F, "Sil Motion", "Silicon Motion" } , - { 0x1270, "Olympus", "Olympus Optical Co. Ltd." } , - { 0x1271, "GW Instr.", "GW Instruments" } , - { 0x1272, "Telematics", "Telematics International" } , - { 0x1273, "Hughes", "Hughes Network Systems" } , - { 0x1274, "Ensoniq", "Ensoniq" } , - { 0x1275, "NetApp", "Network Appliance" } , - { 0x1276, "Sw Net Tech", "Switched Network Technologies Inc." } , - { 0x1277, "Comstream", "Comstream" } , - { 0x1278, "Transtech", "Transtech Parallel Systems" } , - { 0x1279, "Transmeta", "Transmeta Corp." } , - { 0x127B, "Pixera", "Pixera Corp" } , - { 0x127C, "Crosspoint", "Crosspoint Solutions Inc." } , - { 0x127D, "Vela", "Vela Research LP" } , - { 0x127E, "Winnow", "Winnov L.P." } , - { 0x127F, "Fujifilm", "Fujifilm" } , - { 0x1280, "Photoscript", "Photoscript Group Ltd." } , - { 0x1281, "Yokogawa", "Yokogawa Electronic Corp." } , - { 0x1282, "Davicom", "Davicom Semiconductor Inc." } , - { 0x1283, " Zamora", "Waldo" } , - { 0x1285, "Plat Tech", "Platform Technologies Inc." } , - { 0x1286, "MAZeT", "MAZeT GmbH" } , - { 0x1287, "LuxSonor", "LuxSonor Inc." } , - { 0x1288, "Timestep", "Timestep Corp." } , - { 0x1289, "AVC Tech", "AVC Technology Inc." } , - { 0x128A, "Asante", "Asante Technologies Inc." } , - { 0x128B, "Transwitch", "Transwitch Corp." } , - { 0x128C, "Retix", "Retix Corp." } , - { 0x128D, "G2 Net", "G2 Networks Inc." } , - { 0x128F, "Tateno", "Tateno Dennou Inc." } , - { 0x1290, "Sord", "Sord Computer Corp." } , - { 0x1291, "NCS Comp", "NCS Computer Italia" } , - { 0x1292, "Tritech", "Tritech Microelectronics Intl PTE" } , - { 0x1293, "M Reality", "Media Reality Technology" } , - { 0x1294, "Rhetorex", "Rhetorex Inc." } , - { 0x1295, "Imagenation", "Imagenation Corp." } , - { 0x1296, "Kofax", "Kofax Image Products" } , - { 0x1297, "Shuttle Computer", "Shuttle Computer" } , - { 0x1298, "Spellcaster", "Spellcaster Telecommunications Inc." } , - { 0x1299, "Know Tech", "Knowledge Technology Laboratories" } , - { 0x129A, "VMETRO", "VMETRO Inc." } , - { 0x129B, "Img Access", "Image Access" } , - { 0x129D, "CompCore", "CompCore Multimedia Inc." } , - { 0x129E, "Victor Jpn", "Victor Co. of Japan Ltd." } , - { 0x129F, "OEC Med", "OEC Medical Systems Inc." } , - { 0x12A0, "A-B", "Allen Bradley Co." } , - { 0x12A1, "Simpact", "Simpact Inc" } , - { 0x12A2, "NewGen", "NewGen Systems Corp." } , - { 0x12A3, "Lucent", "Lucent Technologies AMR" } , - { 0x12A4, "NTT Elect", "NTT Electronics Technology Co." } , - { 0x12A5, "Vision Dyn", "Vision Dynamics Ltd." } , - { 0x12A6, "Scalable", "Scalable Networks Inc." } , - { 0x12A7, "AMO", "AMO GmbH" } , - { 0x12A8, "News Datacom", "News Datacom" } , - { 0x12A9, "Xiotech", "Xiotech Corp." } , - { 0x12AA, "SDL", "SDL Communications Inc." } , - { 0x12AB, "Yuan Yuan", "Yuan Yuan Enterprise Co. Ltd." } , - { 0x12AC, "MeasureX", "MeasureX Corp." } , - { 0x12AD, "MULTIDATA", "MULTIDATA GmbH" } , - { 0x12AE, "Alteon", "Alteon Networks Inc." } , - { 0x12AF, "TDK USA", "TDK USA Corp." } , - { 0x12B0, "Jorge Sci", "Jorge Scientific Corp." } , - { 0x12B1, "GammaLink", "GammaLink" } , - { 0x12B2, "Gen Signal", "General Signal Networks" } , - { 0x12B3, "Inter-Face", "Inter-Face Co. Ltd." } , - { 0x12B4, "Future Tel", "Future Tel Inc." } , - { 0x12B5, "Granite", "Granite Systems Inc." } , - { 0x12B7, "Acumen", "Acumen" } , - { 0x12B8, "Korg", "Korg" } , - { 0x12B9, "3Com", "3Com Corporation" } , - { 0x12BA, "Bittware", "Bittware, Inc" } , - { 0x12BB, "Nippon Uni", "Nippon Unisoft Corp." } , - { 0x12BC, "Array Micro", "Array Microsystems" } , - { 0x12BD, "Computerm", "Computerm Corp." } , - { 0x12BF, "Fujifilm", "Fujifilm Microdevices" } , - { 0x12C0, "Infimed", "Infimed" } , - { 0x12C1, "GMM Res", "GMM Research Corp." } , - { 0x12C2, "Mentec", "Mentec Ltd." } , - { 0x12C3, "Holtek", "Holtek Microelectronics Inc." } , - { 0x12C4, "Connect Tech", "Connect Tech Inc." } , - { 0x12C5, "PicturEl", "Picture Elements Inc." } , - { 0x12C6, "Mitani", "Mitani Corp." } , - { 0x12C7, "Dialogic", "Dialogic Corp." } , - { 0x12C8, "G Force", "G Force Co. Ltd." } , - { 0x12C9, "Gigi Ops", "Gigi Operations" } , - { 0x12CA, "ICE", "Integrated Computing Engines, Inc." } , - { 0x12CB, "Antex", "Antex Electronics Corp." } , - { 0x12CC, "Pluto", "Pluto Technologies International" } , - { 0x12CD, "Aims Lab", "Aims Lab" } , - { 0x12CE, "Netspeed", "Netspeed Inc." } , - { 0x12CF, "Prophet", "Prophet Systems Inc." } , - { 0x12D0, "GDE Sys", "GDE Systems Inc." } , - { 0x12D1, "PsiTech", "PsiTech" } , - { 0x12D3, "Vingmed", "Vingmed Sound A/S" } , - { 0x12D4, "Ulticom", "Ulticom, Inc." } , - { 0x12D5, "Equator", "Equator Technologies" } , - { 0x12D6, "Analogic", "Analogic Corp." } , - { 0x12D7, "Biotronic", "Biotronic SRL" } , - { 0x12D8, "Pericom", "Pericom Semiconductor" } , - { 0x12D9, "Aculab", "Aculab Plc." } , - { 0x12DA, "TrueTime", "TrueTime" } , - { 0x12DB, "Annapolis", "Annapolis Micro Systems Inc." } , - { 0x12DC, "Symicron", "Symicron Computer Communication Ltd." } , - { 0x12DD, "MGI", "Management Graphics Inc." } , - { 0x12DE, "Rainbow", "Rainbow Technologies" } , - { 0x12DF, "SBS Tech", "SBS Technologies Inc." } , - { 0x12E0, "Chase", "Chase Research PLC" } , - { 0x12E1, "Nintendo", "Nintendo Co. Ltd." } , - { 0x12E2, "Datum", "Datum Inc. Bancomm-Timing Division" } , - { 0x12E3, "Imation", "Imation Corp. - Medical Imaging Syst" } , - { 0x12E4, "Brooktrout", "Brooktrout Technology Inc." } , - { 0x12E6, "Cirel", "Cirel Systems" } , - { 0x12E7, "Sebring", "Sebring Systems Inc" } , - { 0x12E8, "CRISC", "CRISC Corp." } , - { 0x12E9, "GE Spacenet", "GE Spacenet" } , - { 0x12EB, "Aureal", "Aureal Semiconductor" } , - { 0x12EC, "3A Intl", "3A International Inc." } , - { 0x12ED, "Optivision", "Optivision Inc." } , - { 0x12EE, "Orange Micro", "Orange Micro, Inc." } , - { 0x12EF, "Vienna", "Vienna Systems" } , - { 0x12F0, "Pentek", "Pentek" } , - { 0x12F1, "Sorenson", "Sorenson Vision Inc." } , - { 0x12F2, "Gammagraphx", "Gammagraphx Inc." } , - { 0x12F4, "Megatel", "Megatel" } , - { 0x12F5, "Forks", "Forks" } , - { 0x12F7, "Cognex", "Cognex" } , - { 0x12F8, "Electronic-Design", "Electronic-Design GmbH" } , - { 0x12F9, "FFT", "FourFold Technologies" } , - { 0x12FB, "SSP", "Spectrum Signal Processing" } , - { 0x12FC, "CEC", "Capital Equipment Corp" } , - { 0x12FE, "esd", "esd Electronic System Design GmbH" } , - { 0x1303, "II", "Innovative Integration" } , - { 0x1304, "", "Juniper Networks Inc." } , - { 0x1307, "ComputerBoards", "ComputerBoards" } , - { 0x1308, "Jato", "Jato Technologies Inc." } , - { 0x130A, "Mitsubishi", "Mitsubishi Electric Microcomputer" } , - { 0x130B, "Colorgraphic", "Colorgraphic Communications Corp" } , - { 0x130F, "", "Advanet Inc." } , - { 0x1310, "", "Gespac" } , - { 0x1312, "Microscan", "Microscan Systems Inc" } , - { 0x1313, "", "Yaskawa Electric Co." } , - { 0x1316, "", "Teradyne Inc." } , - { 0x1317, "ADMtek", "ADMtek Inc" } , - { 0x1318, "Packet Engines", "Packet Engines, Inc." } , - { 0x1319, "Forte Media2", "Forte Media" } , - { 0x131F, "", "SIIG" } , - { 0x1325, "", "Salix Technologies Inc" } , - { 0x1326, "", "Seachange International" } , - { 0x1328, "CIFELLI", "CIFELLI SYSTEMS CORPORATION" } , - { 0x1331, "RadiSys", "RadiSys Corporation" } , - { 0x1332, "VMetro", "VMetro" } , - { 0x1335, "Videomail", "Videomail Inc." } , - { 0x133D, "", "Prisa Networks" } , - { 0x133F, "", "SCM Microsystems" } , - { 0x1342, "", "Promax Systems Inc" } , - { 0x1344, "Micron", "Micron Technology, Inc." } , - { 0x1347, "Spectracom", "Spectracom Corporation" } , - { 0x134A, "DTC", "DTC Technology Corp." } , - { 0x134B, "", "ARK Research Corp." } , - { 0x134C, "", "Chori Joho System Co. Ltd" } , - { 0x134D, "PCTEL", "PCTEL Inc." } , - { 0x135A, "", "Brain Boxes Limited" } , - { 0x135B, "", "Giganet Inc." } , - { 0x135C, "", "Quatech Inc" } , - { 0x135D, "ABB Network Partn", "ABB Network Partner AB" } , - { 0x135E, "Sealevel", "Sealevel Systems Inc." } , - { 0x135F, "", "I-Data International A-S" } , - { 0x1360, "Meinberg Funkuhren", "Meinberg Funkuhren GmbH & Co. KG" } , - { 0x1361, "", "Soliton Systems K.K." } , - { 0x1363, "", "Phoenix Technologies Ltd" } , - { 0x1365, "Hypercope", "Hypercope Corp." } , - { 0x1366, "Teijin", "Teijin Seiki Co. Ltd." } , - { 0x1367, "", "Hitachi Zosen Corporation" } , - { 0x1368, "", "Skyware Corporation" } , - { 0x1369, "Digigram", "Digigram" } , - { 0x136B, "", "Kawasaki Steel Corporation" } , - { 0x136C, "", "Adtek System Science Co Ltd" } , - { 0x1375, "", "Boeing - Sunnyvale" } , - { 0x137A, "MOTU", "Mark Of The Unicorn Inc" } , - { 0x137B, "", "PPT Vision" } , - { 0x137C, "", "Iwatsu Electric Co Ltd" } , - { 0x137D, "", "Dynachip Corporation" } , - { 0x137E, "PTSC", "Patriot Scientific Corp." } , - { 0x1380, "SANRITZ", "Sanritz Automation Co LTC" } , - { 0x1381, "", "Brains Co. Ltd" } , - { 0x1382, "Marian", "Marian - Electronic & Software" } , - { 0x1384, "", "Stellar Semiconductor Inc" } , - { 0x1385, "Netgear", "Netgear" } , - { 0x1387, "Digital Signal Processing", "Curtiss-Wright Controls Embedded Computing" } , - { 0x1388, "", "Hitachi Information Technology Co Ltd" } , - { 0x1389, "Applicom", "Applicom International" } , - { 0x138B, "", "Tokimec Inc" } , - { 0x138E, "", "Basler GMBH" } , - { 0x138F, "", "Patapsco Designs Inc" } , - { 0x1390, "CDI", "Concept Development Inc." } , - { 0x1393, "", "Moxa Technologies Co Ltd" } , - { 0x1394, "Level One", "Level One Communications" } , - { 0x1395, "", "Ambicom Inc" } , - { 0x1396, "", "Cipher Systems Inc" } , - { 0x1397, "Cologne", "Cologne Chip Designs GmbH" } , - { 0x1398, "", "Clarion Co. Ltd" } , - { 0x139A, "", "Alacritech Inc" } , - { 0x139D, "", "Xstreams PLC/ EPL Limited" } , - { 0x139E, "", "Echostar Data Networks" } , - { 0x13A0, "", "Crystal Group Inc" } , - { 0x13A1, "", "Kawasaki Heavy Industries Ltd" } , - { 0x13A3, "HI-FN", "HI-FN Inc." } , - { 0x13A4, "", "Rascom Inc" } , - { 0x13A7, "", "amc330" } , - { 0x13A8, "XR", "Exar Corp." } , - { 0x13A9, "", "Siemens Medical Solutions" } , - { 0x13AA, "", "Nortel Networks - BWA Division" } , - { 0x13AF, "", "T.Sqware" } , - { 0x13B1, "", "Tamura Corporation" } , - { 0x13B4, "", "Wellbean Co Inc" } , - { 0x13B5, "", "ARM Ltd" } , - { 0x13B6, "pci\ven_13b6", "DLoG GMBH" } , - { 0x13B8, "", "Nokia Telecommunications OY" } , - { 0x13BD, "SHARP", "Sharp Corporation" } , - { 0x13BF, "", "Sharewave Inc" } , - { 0x13C0, "Microgate", "Microgate Corp." } , - { 0x13C1, "3ware", "3ware Inc." } , - { 0x13C2, "", "Technotrend Systemtechnik GMBH" } , - { 0x13C3, "", "Janz Computer AG" } , - { 0x13C7, "", "Blue Chip Technology Ltd" } , - { 0x13CC, "", "Metheus Corporation" } , - { 0x13CF, "", "Studio Audio & Video Ltd" } , - { 0x13D0, "A", "B2C2 Inc" } , - { 0x13D1, "AboCom", "AboCom Systems, Inc" } , - { 0x13D4, "", "Graphics Microsystems Inc" } , - { 0x13D6, "", "K.I. Technology Co Ltd" } , - { 0x13D7, "tos6205", "Toshiba Engineering Corporation" } , - { 0x13D8, "", "Phobos Corporation" } , - { 0x13D9, "", "Apex Inc" } , - { 0x13DC, "", "Netboost Corporation" } , - { 0x13DE, "", "ABB Robotics Products AB" } , - { 0x13DF, "E-Tech", "E-Tech Inc." } , - { 0x13E0, "GVC", "GVC Corporation" } , - { 0x13E3, "", "Nest Inc" } , - { 0x13E4, "", "Calculex Inc" } , - { 0x13E5, "", "Telesoft Design Ltd" } , - { 0x13E9, "", "Intraserver Technology Inc" } , - { 0x13EA, "", "Dallas Semiconductor" } , - { 0x13F0, "", "IC Plus Corporation" } , - { 0x13F1, "", "OCE - Industries S.A." } , - { 0x13F4, "", "Troika Networks Inc" } , - { 0x13F6, "C-Media", "C-Media Electronics Inc." } , - { 0x13F9, "", "NTT Advanced Technology Corp." } , - { 0x13FA, "Pentland", "Pentland Systems Ltd." } , - { 0x13FB, "", "Aydin Corp" } , - { 0x13FD, "", "Micro Science Inc" } , - { 0x13FE, "Advantech", "Advantech Co., Ltd." } , - { 0x13FF, "", "Silicon Spice Inc." } , - { 0x1400, "ArtX", "ArtX Inc" } , - { 0x1402, "Meilhaus Electronic", "Meilhaus Electronic GmbH Germany" } , - { 0x1404, "", "Fundamental Software Inc" } , - { 0x1406, "Oc", "Oce Print Logics Technologies S.A." } , - { 0x1407, "LAVA", "Lava Computer MFG Inc." } , - { 0x1408, "", "Aloka Co. Ltd" } , - { 0x1409, "SUNIX", "SUNIX Co., Ltd." } , - { 0x140A, "", "DSP Research Inc" } , - { 0x140B, "", "Ramix Inc" } , - { 0x140D, "", "Matsushita Electric Works Ltd" } , - { 0x140F, "", "Salient Systems Corp" } , - { 0x1412, "IC Ensemble", "IC Ensemble, Inc." } , - { 0x1413, "", "Addonics" } , - { 0x1415, "Oxford", "Oxford Semiconductor Ltd" } , - { 0x1418, "", "Kyushu Electronics Systems Inc" } , - { 0x1419, "", "Excel Switching Corp" } , - { 0x141B, "Gerd Mokwinski", "Zoom Telephonics Inc" } , - { 0x141E, "", "Fanuc Co. Ltd" } , - { 0x141F, "", "Visiontech Ltd" } , - { 0x1420, "", "Psion Dacom PLC" } , - { 0x1425, "", "ASIC Designers Inc" } , - { 0x1428, "", "Edec Co Ltd" } , - { 0x1429, "", "Unex Technology Corp." } , - { 0x142A, "", "Kingmax Technology Inc" } , - { 0x142B, "", "Radiolan" } , - { 0x142C, "", "Minton Optic Industry Co Ltd" } , - { 0x142D, "", "Pixstream Inc" } , - { 0x1430, "", "ITT Aerospace/Communications Division" } , - { 0x1433, "", "Eltec Elektronik AG" } , - { 0x1435, "RTD", "RTD Embedded Technologies, Inc." } , - { 0x1436, "", "CIS Technology Inc" } , - { 0x1437, "", "Nissin Inc Co" } , - { 0x1438, "", "Atmel-Dream" } , - { 0x143F, "", "Lightwell Co Ltd - Zax Division" } , - { 0x1441, "", "Agie SA." } , - { 0x1443, "Unibrain", "Unibrain S.A." } , - { 0x1445, "", "Logical Co Ltd" } , - { 0x1446, "", "Graphin Co. Ltd" } , - { 0x1447, "", "Aim GMBH" } , - { 0x1448, "Alesis", "Alesis Studio" } , - { 0x144A, "ADLINK", "ADLINK Technology Inc" } , - { 0x144B, "Loronix", "Loronix Information Systems, Inc." } , - { 0x144D, "", "sanyo" } , - { 0x1450, "", "Octave Communications Ind." } , - { 0x1451, "", "SP3D Chip Design GMBH" } , - { 0x1453, "", "Mycom Inc" } , - { 0x1458, "Giga-Byte", "Giga-Byte Technologies" } , - { 0x145C, "", "Cryptek" } , - { 0x145F, "Baldor", "Baldor Electric Company" } , - { 0x1460, "", "Dynarc Inc" } , - { 0x1462, "MSI", "Micro-Star International Co Ltd" } , - { 0x1463, "", "Fast Corporation" } , - { 0x1464, "ICS", "Interactive Circuits & Systems Ltd" } , - { 0x1468, "", "Ambit Microsystems Corp." } , - { 0x1469, "", "Cleveland Motion Controls" } , - { 0x146C, "", "Ruby Tech Corp." } , - { 0x146D, "", "Tachyon Inc." } , - { 0x146E, "", "WMS Gaming" } , - { 0x1471, "", "Integrated Telecom Express Inc" } , - { 0x1473, "", "Zapex Technologies Inc" } , - { 0x1474, "", "Doug Carson & Associates" } , - { 0x1477, "", "Net Insight" } , - { 0x1478, "", "Diatrend Corporation" } , - { 0x147B, "", "Abit Computer Corp." } , - { 0x147F, "", "Nihon Unisys Ltd." } , - { 0x1482, "", "Isytec - Integrierte Systemtechnik Gmbh" } , - { 0x1483, "", "Labway Coporation" } , - { 0x1485, "", "Erma - Electronic GMBH" } , - { 0x1489, "", "KYE Systems Corporation" } , - { 0x148A, "", "Opto 22" } , - { 0x148B, "", "Innomedialogic Inc." } , - { 0x148C, "CP (PowerColor)", "C.P. Technology Co. Ltd" } , - { 0x148D, "Digicom", "Digicom Systems Inc." } , - { 0x148E, "", "OSI Plus Corporation" } , - { 0x148F, "", "Plant Equipment Inc." } , - { 0x1490, "", "TC Labs Pty Ltd." } , - { 0x1493, "", "Maker Communications" } , - { 0x1495, "", "Tokai Communications Industry Co. Ltd" } , - { 0x1496, "", "Joytech Computer Co. Ltd." } , - { 0x1497, "SMA", "SMA Technologie AG" } , - { 0x1498, "Tews", "Tews Technologies" } , - { 0x1499, "", "Micro-Technology Co Ltd" } , - { 0x149A, "Andor Tech", "Andor Technology Ltd" } , - { 0x149B, "", "Seiko Instruments Inc" } , - { 0x149E, "", "Mapletree Networks Inc." } , - { 0x149F, "", "Lectron Co Ltd" } , - { 0x14A0, "", "Softing GMBH" } , - { 0x14A2, "", "Millennium Engineering Inc" } , - { 0x14A4, "sebastien", "GVC/BCM Advanced Research" } , - { 0x14A9, "Hivertec Inc.", "Hivertec Inc." } , - { 0x14AB, "", "Mentor Graphics Corp." } , - { 0x14B1, "", "Nextcom K.K." } , - { 0x14B3, "Xpeed", "Xpeed Inc." } , - { 0x14B4, "", "Philips Business Electronics B.V." } , - { 0x14B5, "Creamware", "Creamware GmbH" } , - { 0x14B6, "", "Quantum Data Corp." } , - { 0x14B7, "Proxim", "Proxim Inc." } , - { 0x14B9, "Aironet", "Aironet Wireless Communication" } , - { 0x14BA, "", "Internix Inc." } , - { 0x14BB, "", "Semtech Corporation" } , - { 0x14BE, "", "L3 Communications" } , - { 0x14C0, "Compal", "Compal Electronics, Inc." } , - { 0x14C1, "", "Myricom Inc." } , - { 0x14C2, "", "DTK Computer" } , - { 0x14C4, "", "Iwasaki Information Systems Co Ltd" } , - { 0x14C5, "", "ABB Automation Products AB" } , - { 0x14C6, "", "Data Race Inc" } , - { 0x14C7, "Modtech", "Modular Technology Ltd." } , - { 0x14C8, "Turbocomm", "Turbocomm Tech Inc" } , - { 0x14C9, "", "Odin Telesystems Inc" } , - { 0x14CB, "", "Billionton Systems Inc./Cadmus Micro Inc" } , - { 0x14CD, "", "Universal Scientific Ind." } , - { 0x14CF, "Tekmicro", "TEK Microsystems Inc." } , - { 0x14D4, "PANACOM", "Panacom Technology Corporation" } , - { 0x14D5, "", "Nitsuko Corporation" } , - { 0x14D6, "", "Accusys Inc" } , - { 0x14D7, "", "Hirakawa Hewtech Corp" } , - { 0x14D8, "", "Hopf Elektronik GMBH" } , - { 0x14D9, "", "Alpha Processor Inc" } , - { 0x14DB, "Avlab", "Avlab Technology Inc." } , - { 0x14DC, "Amplicon", "Amplicon Liveline Limited" } , - { 0x14DD, "", "Imodl Inc." } , - { 0x14DE, "", "Applied Integration Corporation" } , - { 0x14E3, "", "Amtelco" } , - { 0x14E4, "Broadcom", "Broadcom Corporation" } , - { 0x14EA, "Planex", "Planex Communications, Inc." } , - { 0x14EB, "", "Seiko Epson Corporation" } , - { 0x14EC, "", "Acqiris" } , - { 0x14ED, "", "Datakinetics Ltd" } , - { 0x14EF, "", "Carry Computer Eng. Co Ltd" } , - { 0x14F1, "Conexant", "Conexant" } , - { 0x14F2, "Mobility", "Mobility Electronics, Inc." } , - { 0x14F4, "", "Tokyo Electronic Industry Co. Ltd." } , - { 0x14F5, "", "Sopac Ltd" } , - { 0x14F6, "", "Coyote Technologies LLC" } , - { 0x14F7, "", "Wolf Technology Inc" } , - { 0x14F8, "", "Audiocodes Inc" } , - { 0x14F9, "", "AG Communications" } , - { 0x14FB, "", "Transas Marine (UK) Ltd" } , - { 0x14FC, "", "Quadrics Ltd" } , - { 0x14FD, "Silex", "Silex Technology Inc." } , - { 0x14FE, "", "Archtek Telecom Corp." } , - { 0x14FF, "", "Twinhead International Corp." } , - { 0x1501, "", "Banksoft Canada Ltd" } , - { 0x1502, "", "Mitsubishi Electric Logistics Support Co" } , - { 0x1503, "", "Kawasaki LSI USA Inc" } , - { 0x1504, "", "Kaiser Electronics" } , - { 0x1506, "", "Chameleon Systems Inc" } , - { 0x1507, "Htec", "Htec Ltd." } , - { 0x1509, "FIC", "First International Computer Inc" } , - { 0x150B, "", "Yamashita Systems Corp" } , - { 0x150C, "", "Kyopal Co Ltd" } , - { 0x150D, "", "Warpspped Inc" } , - { 0x150E, "", "C-Port Corporation" } , - { 0x150F, "", "Intec GMBH" } , - { 0x1510, "", "Behavior Tech Computer Corp" } , - { 0x1511, "", "Centillium Technology Corp" } , - { 0x1512, "Rosen", "Rosun Technologies Inc" } , - { 0x1513, "", "Raychem" } , - { 0x1514, "", "TFL LAN Inc" } , - { 0x1515, "", "ICS Advent" } , - { 0x1516, "", "Myson Technology Inc" } , - { 0x1517, "", "Echotek Corporation" } , - { 0x1518, "", "Kontron Modular Computers GmbH (PEP Modular Computers GMBH)" } , - { 0x1519, "", "Telefon Aktiebolaget LM Ericsson" } , - { 0x151A, "Globetek", "Globetek Inc." } , - { 0x151B, "wesam", "Combox Ltd" } , - { 0x151C, "", "Digital Audio Labs Inc" } , - { 0x151D, "", "Fujitsu Computer Products Of America" } , - { 0x151E, "", "Matrix Corp." } , - { 0x151F, "", "Topic Semiconductor Corp" } , - { 0x1520, "", "Chaplet System Inc" } , - { 0x1521, "", "Bell Corporation" } , - { 0x1522, "Mainpine", "Mainpine Limited" } , - { 0x1523, "", "Music Semiconductors" } , - { 0x1524, "mayer", "ENE Technology Inc" } , - { 0x1525, "", "Impact Technologies" } , - { 0x1526, "", "ISS Inc" } , - { 0x1527, "", "Solectron" } , - { 0x1528, "", "Acksys" } , - { 0x1529, "", "American Microsystems Inc" } , - { 0x152A, "", "Quickturn Design Systems" } , - { 0x152B, "", "Flytech Technology Co Ltd" } , - { 0x152C, "", "Macraigor Systems LLC" } , - { 0x152D, "", "Quanta Computer Inc" } , - { 0x152E, "", "Melec Inc" } , - { 0x152F, "", "Philips - Crypto" } , - { 0x1532, "", "Echelon Corporation" } , - { 0x1533, "", "Baltimore" } , - { 0x1534, "", "Road Corporation" } , - { 0x1535, "", "Evergreen Technologies Inc" } , - { 0x1537, "", "Datalex Communcations" } , - { 0x1538, "Aralion", "Aralion Inc." } , - { 0x1539, "", "Atelier Informatiques et Electronique Et" } , - { 0x153A, "", "ONO Sokki" } , - { 0x153B, "cami", "Terratec Electronic GMBH" } , - { 0x153C, "", "Antal Electronic" } , - { 0x153D, "", "Filanet Corporation" } , - { 0x153E, "Techwell", "Techwell Inc" } , - { 0x153F, "MIPS", "MIPS Technologies, Inc" } , - { 0x1540, "", "Provideo Multimedia Co Ltd" } , - { 0x1541, "", "Telocity Inc." } , - { 0x1542, "", "Vivid Technology Inc" } , - { 0x1543, "", "Silicon Laboratories" } , - { 0x1544, "DCM", "DCM Technologies Ltd." } , - { 0x1545, "Visiontek", "VisionTek" } , - { 0x1546, "", "IOI Technology Corp." } , - { 0x1547, "", "Mitutoyo Corporation" } , - { 0x1548, "", "Jet Propulsion Laboratory" } , - { 0x1549, "ISS", "Interconnect Systems Solutions" } , - { 0x154A, "", "Max Technologies Inc." } , - { 0x154B, "", "Computex Co Ltd" } , - { 0x154C, "", "Visual Technology Inc." } , - { 0x154D, "", "PAN International Industrial Corp" } , - { 0x154E, "", "Servotest Ltd" } , - { 0x154F, "", "Stratabeam Technology" } , - { 0x1550, "", "Open Network Co Ltd" } , - { 0x1551, "", "Smart Electronic Development GMBH" } , - { 0x1553, "", "Chicony Electronics Co Ltd" } , - { 0x1554, "PMC", "Prolink Microsystems Corp." } , - { 0x1555, "Gesytec", "Gesytec GmbH" } , - { 0x1556, "", "PLD Applications" } , - { 0x1557, "", "Mediastar Co. Ltd" } , - { 0x1558, "", "Clevo/Kapok Computer" } , - { 0x1559, "", "SI Logic Ltd" } , - { 0x155A, "", "Innomedia Inc" } , - { 0x155B, "", "Protac International Corp" } , - { 0x155C, "", "s" } , - { 0x155D, "", "MAC System Co Ltd" } , - { 0x155E, "KR", "KUKA Roboter GmbH" } , - { 0x155F, "", "Perle Systems Limited" } , - { 0x1560, "", "Terayon Communications Systems" } , - { 0x1561, "", "Viewgraphics Inc" } , - { 0x1562, "", "Symbol Technologies, Inc." } , - { 0x1563, "", "A-Trend Technology Co Ltd" } , - { 0x1564, "", "Yamakatsu Electronics Industry Co Ltd" } , - { 0x1565, "xyz", "Biostar Microtech Intl Corp" } , - { 0x1566, "", "Ardent Technologies Inc" } , - { 0x1567, "", "Jungsoft" } , - { 0x1568, "", "DDK Electronics Inc" } , - { 0x1569, "AleksSPb", "Palit Microsystems Inc" } , - { 0x156A, "Avtec", "Avtec Systems Inc" } , - { 0x156B, "", "S2io Inc" } , - { 0x156C, "", "Vidac Electronics GMBH" } , - { 0x156D, "", "Alpha-Top Corp" } , - { 0x156E, "", "Alfa Inc." } , - { 0x156F, "", "M-Systems Flash Disk Pioneers Ltd" } , - { 0x1570, "", "Lecroy Corporation" } , - { 0x1571, "", "Contemporary Controls" } , - { 0x1572, "", "Otis Elevator Company" } , - { 0x1573, "", "Lattice - Vantis" } , - { 0x1574, "", "Fairchild Semiconductor" } , - { 0x1575, "", "Voltaire Advanced Data Security Ltd" } , - { 0x1576, "", "Viewcast Com" } , - { 0x1578, "", "Hitt" } , - { 0x1579, "", "Dual Technology Corporation" } , - { 0x157A, "", "Japan Elecronics Ind. Inc" } , - { 0x157B, "", "Star Multimedia Corp." } , - { 0x157C, "Eurosoft", "Eurosoft (UK)" } , - { 0x157D, "", "Gemflex Networks" } , - { 0x157E, "", "Transition Networks" } , - { 0x157F, "", "PX Instruments Technology Ltd" } , - { 0x1580, "", "Primex Aerospace Co." } , - { 0x1581, "", "SEH Computertechnik GMBH" } , - { 0x1582, "", "Cytec Corporation" } , - { 0x1583, "", "Inet Technologies Inc" } , - { 0x1584, "", "Uniwill Computer Corp." } , - { 0x1585, "", "Marconi Commerce Systems SRL" } , - { 0x1586, "", "Lancast Inc" } , - { 0x1587, "", "Konica Corporation" } , - { 0x1588, "Solidum", "Solidum Systems Corp" } , - { 0x1589, "", "Atlantek Microsystems Pty Ltd" } , - { 0x158A, "", "Digalog Systems Inc" } , - { 0x158B, "", "Allied Data Technologies" } , - { 0x158C, "", "Hitachi Semiconductor & Devices Sales Co" } , - { 0x158D, "", "Point Multimedia Systems" } , - { 0x158E, "", "Lara Technology Inc" } , - { 0x158F, "", "Ditect Coop" } , - { 0x1590, "", "3pardata Inc." } , - { 0x1591, "", "ARN" } , - { 0x1592, "Syba", "Syba Tech Ltd." } , - { 0x1593, "", "Bops Inc" } , - { 0x1594, "", "Netgame Ltd" } , - { 0x1595, "", "Diva Systems Corp." } , - { 0x1596, "", "Folsom Research Inc" } , - { 0x1597, "", "Memec Design Services" } , - { 0x1598, "", "Granite Microsystems" } , - { 0x1599, "", "Delta Electronics Inc" } , - { 0x159A, "", "General Instrument" } , - { 0x159B, "", "Faraday Technology Corp" } , - { 0x159C, "", "Stratus Computer Systems" } , - { 0x159D, "", "Ningbo Harrison Electronics Co Ltd" } , - { 0x159E, "", "A-Max Technology Co Ltd" } , - { 0x159F, "", "Galea Network Security" } , - { 0x15A0, "", "Compumaster SRL" } , - { 0x15A1, "", "Geocast Network Systems Inc" } , - { 0x15A2, "", "Catalyst Enterprises Inc" } , - { 0x15A3, "", "Italtel" } , - { 0x15A4, "", "X-Net OY" } , - { 0x15A5, "", "Toyota MACS Inc" } , - { 0x15A6, "", "Sunlight Ultrasound Technologies Ltd" } , - { 0x15A7, "", "SSE Telecom Inc" } , - { 0x15A8, "", "Shanghai Communications Technologies Cen" } , - { 0x15AA, "", "Moreton Bay" } , - { 0x15AB, "", "Bluesteel Networks Inc" } , - { 0x15AC, "", "North Atlantic Instruments" } , - { 0x15AD, "VMware", "VMware Inc." } , - { 0x15AE, "", "Amersham Pharmacia Biotech" } , - { 0x15B0, "", "Zoltrix International Limited" } , - { 0x15B1, "", "Source Technology Inc" } , - { 0x15B2, "", "Mosaid Technologies Inc." } , - { 0x15B3, "", "Mellanox Technology" } , - { 0x15B4, "", "CCI/Triad" } , - { 0x15B5, "", "Cimetrics Inc" } , - { 0x15B6, "", "Texas Memory Systems Inc" } , - { 0x15B7, "", "Sandisk Corp." } , - { 0x15B8, "", "Addi-Data GMBH" } , - { 0x15B9, "", "Maestro Digital Communications" } , - { 0x15BA, "", "Impacct Technology Corp" } , - { 0x15BB, "", "Portwell Inc" } , - { 0x15BC, "Agilent", "Agilent Technologies" } , - { 0x15BD, "", "DFI Inc." } , - { 0x15BE, "", "Sola Electronics" } , - { 0x15BF, "", "High Tech Computer Corp (HTC)" } , - { 0x15C0, "BVM", "BVM Limited" } , - { 0x15C1, "", "Quantel" } , - { 0x15C2, "", "Newer Technology Inc" } , - { 0x15C3, "", "Taiwan Mycomp Co Ltd" } , - { 0x15C4, "", "EVSX Inc" } , - { 0x15C5, "", "Procomp Informatics Ltd" } , - { 0x15C6, "", "Technical University Of Budapest" } , - { 0x15C7, "", "Tateyama System Laboratory Co Ltd" } , - { 0x15C8, "", "Penta Media Co. Ltd" } , - { 0x15C9, "", "Serome Technology Inc" } , - { 0x15CA, "", "Bitboys OY" } , - { 0x15CB, "", "AG Electronics Ltd" } , - { 0x15CC, "", "Hotrail Inc." } , - { 0x15CD, "", "Dreamtech Co Ltd" } , - { 0x15CE, "", "Genrad Inc." } , - { 0x15CF, "", "Hilscher GMBH" } , - { 0x15D1, "Infineon", "Infineon Technologies AG" } , - { 0x15D2, "", "FIC (First International Computer Inc)" } , - { 0x15D3, "", "NDS Technologies Israel Ltd" } , - { 0x15D4, "", "Iwill Corporation" } , - { 0x15D5, "", "Tatung Co." } , - { 0x15D6, "", "Entridia Corporation" } , - { 0x15D7, "", "Rockwell-Collins Inc" } , - { 0x15D8, "", "Cybernetics Technology Co Ltd" } , - { 0x15D9, "", "Super Micro Computer Inc" } , - { 0x15DA, "", "Cyberfirm Inc." } , - { 0x15DB, "", "Applied Computing Systems Inc." } , - { 0x15DC, "Litronic", "Litronic Inc." } , - { 0x15DD, "jjk", "Sigmatel Inc." } , - { 0x15DE, "", "Malleable Technologies Inc" } , - { 0x15E0, "", "Cacheflow Inc" } , - { 0x15E1, "VTG", "Voice Technologies Group" } , - { 0x15E2, "", "Quicknet Technologies Inc" } , - { 0x15E3, "", "Networth Technologies Inc" } , - { 0x15E4, "", "VSN Systemen BV" } , - { 0x15E5, "", "Valley Technologies Inc" } , - { 0x15E6, "", "Agere Inc." } , - { 0x15E7, "", "GET Engineering Corp." } , - { 0x15E8, "", "National Datacomm Corp." } , - { 0x15E9, "", "Pacific Digital Corp." } , - { 0x15EA, "", "Tokyo Denshi Sekei K.K." } , - { 0x15EB, "", "Drsearch GMBH" } , - { 0x15EC, "", "Beckhoff GMBH" } , - { 0x15ED, "", "Macrolink Inc" } , - { 0x15EE, "", "IN Win Development Inc." } , - { 0x15EF, "", "Intelligent Paradigm Inc" } , - { 0x15F0, "", "B-Tree Systems Inc" } , - { 0x15F1, "", "Times N Systems Inc" } , - { 0x15F2, "", "Diagnostic Instruments Inc" } , - { 0x15F3, "", "Digitmedia Corp." } , - { 0x15F4, "", "Valuesoft" } , - { 0x15F5, "", "Power Micro Research" } , - { 0x15F6, "", "Extreme Packet Device Inc" } , - { 0x15F7, "", "Banctec" } , - { 0x15F8, "", "Koga Electronics Co" } , - { 0x15F9, "", "Zenith Electronics Co" } , - { 0x15FA, "Axzam", "Axzam Corporation" } , - { 0x15FB, "", "Zilog Inc." } , - { 0x15FC, "", "Techsan Electronics Co Ltd" } , - { 0x15FD, "", "N-Cubed.Net" } , - { 0x15FE, "", "Kinpo Electronics Inc" } , - { 0x15FF, "", "Fastpoint Technologies Inc." } , - { 0x1600, "", "Northrop Grumman - Canada Ltd" } , - { 0x1601, "", "Tenta Technology" } , - { 0x1602, "", "Prosys-TEC Inc." } , - { 0x1603, "", "Nokia Wireless Business Communications" } , - { 0x1604, "", "Central System Research Co Ltd" } , - { 0x1605, "", "Pairgain Technologies" } , - { 0x1606, "", "Europop AG" } , - { 0x1607, "", "Lava Semiconductor Manufacturing Inc." } , - { 0x1608, "", "Automated Wagering International" } , - { 0x1609, "", "Sciemetric Instruments Inc" } , - { 0x160A, "", "Kollmorgen Servotronix" } , - { 0x160B, "", "Onkyo Corp." } , - { 0x160C, "", "Oregon Micro Systems Inc." } , - { 0x160D, "", "Aaeon Electronics Inc" } , - { 0x160E, "", "CML Emergency Services" } , - { 0x160F, "", "ITEC Co Ltd" } , - { 0x1610, "", "Tottori Sanyo Electric Co Ltd" } , - { 0x1611, "", "Bel Fuse Inc." } , - { 0x1612, "", "Telesynergy Research Inc." } , - { 0x1613, "", "System Craft Inc." } , - { 0x1614, "", "Jace Tech Inc." } , - { 0x1615, "", "Equus Computer Systems Inc" } , - { 0x1616, "", "Iotech Inc." } , - { 0x1617, "", "Rapidstream Inc" } , - { 0x1618, "", "Esec SA" } , - { 0x1619, "FarSite", "FarSite Communications Limited" } , - { 0x161B, "", "Mobilian Israel Ltd" } , - { 0x161C, "", "Berkshire Products" } , - { 0x161D, "", "Gatec" } , - { 0x161E, "", "Kyoei Sangyo Co Ltd" } , - { 0x161F, "Arima", "Arima Computer Corporation" } , - { 0x1620, "", "Sigmacom Co Ltd" } , - { 0x1621, "", "Lynx Studio Technology Inc" } , - { 0x1622, "NHC", "Nokia Home Communications" } , - { 0x1623, "", "KRF Tech Ltd" } , - { 0x1624, "", "CE Infosys GMBH" } , - { 0x1625, "", "Warp Nine Engineering" } , - { 0x1626, "", "TDK Semiconductor Corp." } , - { 0x1627, "", "BCom Electronics Inc" } , - { 0x1629, "", "Kongsberg Spacetec a.s." } , - { 0x162A, "", "Sejin Computerland Co Ltd" } , - { 0x162B, "", "Shanghai Bell Company Limited" } , - { 0x162C, "", "C&H Technologies Inc" } , - { 0x162D, "", "Reprosoft Co Ltd" } , - { 0x162E, "", "Margi Systems Inc" } , - { 0x162F, "", "Rohde & Schwarz GMBH & Co KG" } , - { 0x1630, "", "Sky Computers Inc" } , - { 0x1631, "", "NEC Computer International" } , - { 0x1632, "", "Verisys Inc" } , - { 0x1633, "", "Adac Corporation" } , - { 0x1634, "", "Visionglobal Network Corp." } , - { 0x1635, "", "Decros" } , - { 0x1636, "", "Jean Company Ltd" } , - { 0x1637, "", "NSI" } , - { 0x1638, " Eumitcom Technology Inc", "Eumitcom Technology Inc" } , - { 0x163A, "", "Air Prime Inc" } , - { 0x163B, "", "Glotrex Co Ltd" } , - { 0x163C, "", "intel" } , - { 0x163D, "", "Heidelberg Digital LLC" } , - { 0x163E, "владими&", "3dpower" } , - { 0x163F, "", "Renishaw PLC" } , - { 0x1640, "", "Intelliworxx Inc" } , - { 0x1641, "", "MKNet Corporation" } , - { 0x1642, "", "Bitland" } , - { 0x1643, "", "Hajime Industries Ltd" } , - { 0x1644, "", "Western Avionics Ltd" } , - { 0x1645, "", "Quick-Serv. Computer Co. Ltd" } , - { 0x1646, "", "Nippon Systemware Co Ltd" } , - { 0x1647, "", "Hertz Systemtechnik GMBH" } , - { 0x1648, "", "MeltDown Systems LLC" } , - { 0x1649, "", "Jupiter Systems" } , - { 0x164A, "", "Aiwa Co. Ltd" } , - { 0x164C, "", "Department Of Defense" } , - { 0x164D, "", "Ishoni Networks" } , - { 0x164E, "", "Micrel Inc." } , - { 0x164F, "DataVoice", "Datavoice (Pty) Ltd." } , - { 0x1650, "", "Admore Technology Inc." } , - { 0x1651, "", "Chaparral Network Storage" } , - { 0x1652, "", "Spectrum Digital Inc." } , - { 0x1653, "Naturetech", "Nature Worldwide Technology Corp" } , - { 0x1654, "", "Sonicwall Inc" } , - { 0x1655, "", "Dazzle Multimedia Inc." } , - { 0x1656, "", "Insyde Software Corp" } , - { 0x1657, "", "Brocade Communications Systems" } , - { 0x1658, "", "Med Associates Inc." } , - { 0x1659, "", "Shiba Denshi Systems Inc." } , - { 0x165A, "", "Epix Inc." } , - { 0x165B, "", "Real-Time Digital Inc." } , - { 0x165C, "", "Kondo Kagaku" } , - { 0x165D, "", "Hsing Tech. Enterprise Co. Ltd." } , - { 0x165E, "", "Hyunju Computer Co. Ltd." } , - { 0x165F, "Comart", "Comartsystem Korea" } , - { 0x1660, "", "Network Security Technologies Inc. (Net" } , - { 0x1661, "", "Worldspace Corp." } , - { 0x1662, "", "Int Labs" } , - { 0x1663, "", "Elmec Inc. Ltd." } , - { 0x1664, "", "Fastfame Technology Co. Ltd." } , - { 0x1665, "", "Edax Inc." } , - { 0x1666, "", "Norpak Corporation" } , - { 0x1667, "", "CoSystems Inc." } , - { 0x1668, "Actiontec", "Actiontec Electronics Inc." } , - { 0x166A, "", "Komatsu Ltd." } , - { 0x166B, "", "Supernet Inc." } , - { 0x166C, "", "Shade Ltd." } , - { 0x166D, "", "Sibyte Inc." } , - { 0x166E, "", "Schneider Automation Inc." } , - { 0x166F, "", "Televox Software Inc." } , - { 0x1670, "", "Rearden Steel" } , - { 0x1671, "", "Atan Technology Inc." } , - { 0x1672, "", "Unitec Co. Ltd." } , - { 0x1673, "", "pctel" } , - { 0x1675, "", "Square Wave Technology" } , - { 0x1676, "Gateway", "Emachines Inc." } , - { 0x1677, "", "Bernecker + Rainer" } , - { 0x1678, "", "INH Semiconductor" } , - { 0x1679, "", "Tokyo Electron Device Ltd." } , - { 0x167F, "iba", "iba AG" } , - { 0x1680, "Dunti", "Dunti Corp." } , - { 0x1681, "Hercules", "Hercules" } , - { 0x1682, "PINE", "PINE Technology, Ltd." } , - { 0x1688, "CastleNet", "CastleNet Technology Inc." } , - { 0x168A, "USA", "Utimaco Safeware AG" } , - { 0x168B, "", "Circut Assembly Corp." } , - { 0x168C, "Atheros", "Atheros Communications Inc." } , - { 0x168D, "NMI", "NMI Electronics Ltd." } , - { 0x168E, "Hyundai MultiCAV", "Hyundai MultiCAV Computer Co. Ltd." } , - { 0x168F, "qsb", "KDS Innotech Corp." } , - { 0x1690, "NetContinuum", "NetContinuum, Inc." } , - { 0x1693, "FERMA", "FERMA" } , - { 0x1695, "EPoX", "EPoX Computer Co., Ltd." } , - { 0x16AE, "SFNT", "SafeNet Inc." } , - { 0x16B3, "", "CNF Mobile Solutions" } , - { 0x16B8, "Sonnet Technologies", "Sonnet Technologies, Inc." } , - { 0x16CA, "Cenatek", "Cenatek Inc." } , - { 0x16CB, "Minolta", "Minolta Co. Ltd." } , - { 0x16CC, "Inari", "Inari Inc." } , - { 0x16D0, "", "Systemax" } , - { 0x16E0, "3MTS", "Third Millenium Test Solutions, Inc." } , - { 0x16E5, "", "Intellon Corporation" } , - { 0x16EC, "USR", "U.S. Robotics" } , - { 0x16F0, "", "TLA Inc." } , - { 0x16F1, "Adicti", "Adicti Corp." } , - { 0x16F3, "Jetway", "Jetway Information Co., Ltd" } , - { 0x16F6, "VideoTele.com", "VideoTele.com Inc." } , - { 0x1700, "Antara", "Antara LLC" } , - { 0x1701, "", "Interactive Computer Products Inc." } , - { 0x1702, "IMC", "Internet Machines Corp." } , - { 0x1703, "Desana", "Desana Systems" } , - { 0x1704, "Clearwater", "Clearwater Networks" } , - { 0x1705, "Digital First", "Digital First" } , - { 0x1706, "PBC", "Pacific Broadband Communications" } , - { 0x1707, "Cogency", "Cogency Semiconductor Inc." } , - { 0x1708, "Harris", "Harris Corp." } , - { 0x1709, "Zarlink", "Zarlink Semiconductor" } , - { 0x170A, "Alpine", "Alpine Electronics Inc." } , - { 0x170B, "NetOctave", "NetOctave Inc." } , - { 0x170C, "YottaYotta", "YottaYotta Inc." } , - { 0x170D, "SMI", "SensoMotoric Instruments GmbH" } , - { 0x170E, "San Valley", "San Valley Systems, Inc." } , - { 0x170F, "Cyberdyne", "Cyberdyne Inc." } , - { 0x1710, "Pelago", "Pelago Nutworks" } , - { 0x1711, "NetScreen", "MyName Technologies, Inc." } , - { 0x1712, "NICE", "NICE Systems Inc." } , - { 0x1713, "TOPCON", "TOPCON Corp." } , - { 0x1725, "Vitesse", "Vitesse Semiconductor" } , - { 0x1734, "Fujitsu-Siemens", "Fujitsu-Siemens Computers GmbH" } , - { 0x1737, "LinkSys", "LinkSys" } , - { 0x173B, "Altima", "Altima Communications Inc." } , - { 0x1743, "Peppercon", "Peppercon AG" } , - { 0x174B, "PC Partner (Sapphire)", "PC Partner Limited" } , - { 0x1752, "AMW Europe GmbH", "Global Brands Manufacture Ltd." } , - { 0x1753, "TeraRecon", "TeraRecon, Inc." } , - { 0x1755, "Alchemy", "Alchemy Semiconductor Inc." } , - { 0x176A, "GDC", "General Dynamics Canada" } , - { 0x1789, "Ennyah", "Ennyah Technologies Corp" } , - { 0x1793, "Unitech", "Unitech Electronics Co., Ltd" } , - { 0x17A7, "Start Network", "Start Network Technology Co., Ltd." } , - { 0x17AA, "lenovo", "Legend Ltd. (Beijing)" } , - { 0x17AB, "", "Phillips Components" } , - { 0x17AF, "Hightech", "Hightech Information Systems, Ltd." } , - { 0x17BE, "Philips", "Philips Semiconductors" } , - { 0x17C0, "Wistron", "Wistron Corp." } , - { 0x17C4, "", "Movita" } , - { 0x17CC, "NetChip", "NetChip" } , - { 0x17D5, "Neterion", "Neterion Inc." } , - { 0x17E9, "", "DH electronics GmbH" } , - { 0x17EE, "Connect3D", "Connect Components, Ltd." } , - { 0x1813, "Ambient", "phillip rees" } , - { 0x1814, "Ralink Technology", "Ralink Technology, Corp" } , - { 0x1815, "devolo", "devolo AG" } , - { 0x1820, "InfiniCon", "InfiniCon Systems, Inc." } , - { 0x1824, "Avocent", "Avocent" } , - { 0x1860, "Primagraphics", "Primagraphics Ltd." } , - { 0x186C, "Humusoft", "Humusoft S.R.O" } , - { 0x1887, "Elan", "Elan Digital Systems Ltd" } , - { 0x1888, "", "Varisys Limited" } , - { 0x188D, "Millogic", "Millogic Ltd." } , - { 0x1890, "", "Egenera, Inc." } , - { 0x18BC, "", "Info-Tek Corp." } , - { 0x18C9, "ARVOO", "ARVOO Engineering BV" } , - { 0x18CA, "XGI", "XGI Technology Inc" } , - { 0x18F1, "Spc", "Spectrum Systementwicklung Microelectronic GmbH" } , - { 0x18F4, "Napatech", "Napatech A/S" } , - { 0x18F7, "Commtech", "Commtech, Inc." } , - { 0x18FB, "", "Resilience Corporation" } , - { 0x1905, "WIS Computers", "WIS Technology, Inc." } , - { 0x1910, "Seaway Networks", "Seaway Networks" } , - { 0x1971, "", "AGEIA Technologies, Inc." } , - { 0x19A8, "DAQDATA", "DAQDATA GmbH" } , - { 0x19AC, "Kasten Chase", "Kasten Chase Applied Research" } , - { 0x19E2, "Vector", "Vector Informatik GmbH" } , - { 0x1A08, "", "Linux Networx" } , - { 0x1A42, "", "Imaginant" } , - { 0x1B13, "Jaton Corp", "Jaton Corporation USA" } , - { 0x1DE1, "Tekram", "Tekram" } , - { 0x1FCF, "Miranda", "Miranda Technologies Ltd." } , - { 0x2001, "", "Temporal Research Ltd" } , - { 0x2646, "Kingston", "Kingston Technology Co." } , - { 0x270F, "ChainTech", "ChainTech Computer Co. Ltd." } , - { 0x2EC1, "", "Zenic Inc" } , - { 0x3388, "Hint", "Hint Corp." } , - { 0x3411, "", "Quantum Designs (H.K.) Inc." } , - { 0x3513, "ARCOM", "ARCOM Control Systems Ltd." } , - { 0x38EF, "", "4links" } , - { 0x3D3D, "3DLabs", "3Dlabs, Inc. Ltd" } , - { 0x4005, "Avance", "Avance Logic Inc." } , - { 0x4144, "Alpha Data", "Alpha Data" } , - { 0x416C, "", "Aladdin Knowledge Systems" } , - { 0x4680, "UMAX Comp", "UMAX Computer Corp." } , - { 0x4843, "Hercules", "Hercules Computer Technology" } , - { 0x4943, "", "Growth Networks" } , - { 0x4954, "Integral", "Integral Technologies" } , - { 0x4978, "Axil", "Axil Computer Inc." } , - { 0x4C48, "Lung Hwa", "Lung Hwa Electronics" } , - { 0x4C53, "SBS", "SBS-OR Industrial Computers" } , - { 0x4CA1, "", "Seanix Technology Inc" } , - { 0x4D51, "Mediaq", "Mediaq Inc." } , - { 0x4D54, "", "Microtechnica Co Ltd" } , - { 0x4DDC, "ILC", "ILC Data Device Corp." } , - { 0x5053, "TBS/Voyetra", "TBS/Voyetra Technologies" } , - { 0x5136, "", "S S Technologies" } , - { 0x5143, "Qualcomm", "Qualcomm Inc." } , - { 0x5333, "S3 86c765", "S3 Graphics Co., Ltd" } , - { 0x544C, "", "Teralogic Inc" } , - { 0x5555, "Genroco", "Genroco Inc." } , - { 0x6409, "", "Logitec Corp." } , - { 0x6666, "Decision", "Decision Computer International Co." } , - { 0x7604, "O.N.", "O.N. Electric Co. Ltd." } , - { 0x8086, "Intel", "Intel Corporation" } , - { 0x80EE, "VirtualBox", "VirtualBox" } , - { 0x8866, "T-Square", "T-Square Design Inc." } , - { 0x8888, "Sil Magic", "Silicon Magic" } , - { 0x8E0E, "Computone", "Computone Corporation" } , - { 0x9004, "Adaptec", "Adaptec Inc" } , - { 0x9005, "Adaptec", "Adaptec Inc" } , - { 0x919A, "", "Gigapixel Corp" } , - { 0x9412, "Holtek", "Holtek" } , - { 0x9699, "", "Omni Media Technology Inc." } , - { 0x9902, "StarGen", "StarGen, Inc." } , - { 0xA0A0, "Aopen", "Aopen Inc." } , - { 0xA0F1, "", "Unisys Corporation" } , - { 0xA200, "NEC", "NEC Corp." } , - { 0xA259, "", "Hewlett Packard" } , - { 0xA304, "Sony", "Sony" } , - { 0xA727, "", "3com Corporation" } , - { 0xAA42, "Scitex", "Scitex Digital Video" } , - { 0xAC1E, "", "Digital Receiver Technology Inc" } , - { 0xB1B3, "Shiva", "Shiva Europe Ltd." } , - { 0xB894, "", "Brown & Sharpe Mfg. Co." } , - { 0xBEEF, "Mindstream Computing", "Mindstream Computing" } , - { 0xC001, "TSI", "TSI Telsys" } , - { 0xC0A9, "Micron/Crucial", "Micron/Crucial Technology" } , - { 0xC0DE, "", "Motorola" } , - { 0xC0FE, "Mot Engrg", "Motion Engineering Inc." } , - { 0xC622, "", "Hudson Soft Co Ltd" } , - { 0xCA50, "Varian", "Varian, Inc" } , - { 0xCAFE, "", "Chrysalis-ITS" } , - { 0xCCCC, "", "Catapult Communications" } , - { 0xD4D4, "Processing", "Curtiss-Wright Controls Embedded Computing" } , - { 0xDC93, "", "Dawicontrol" } , - { 0xDEAD, "Indigita", "Indigita Corporation" } , - { 0xDEAF, "", "Middle Digital, Inc" } , - { 0xE159, "Tiger Jet", "Tiger Jet Network Inc" } , - { 0xE4BF, "", "EKF Elektronik GMBH" } , - { 0xEA01, "", "Eagle Technology" } , - { 0xEABB, "Aashima", "Aashima Technology B.V." } , - { 0xEACE, "Endace", "Endace Measurement Systems Ltd." } , - { 0xECC0, "Echo", "Echo Digital Audio Corporation" } , - { 0xEDD8, "ARK Logic", "ARK Logic, Inc" } , - { 0xF5F5, "", "F5 Networks Inc." } , - { 0xFA57, "Interagon", "Interagon AS" } , -} ; - - -// Use this value for loop control during searching: -#define PCI_VENTABLE_LEN (sizeof(PciVenTable)/sizeof(PCI_VENTABLE)) - -typedef struct _PCI_DEVTABLE -{ - unsigned short VenId ; - unsigned short DevId ; - const char * Chip ; - const char * ChipDesc ; -} PCI_DEVTABLE, *PPCI_DEVTABLE ; - -PCI_DEVTABLE PciDevTable [] = -{ - { 0x165C, 0x0002, "FT232BL", "FT232BL" } , - { 0x16AE, 0x1141, "SafeXcel-1141", "???" } , - { 0x11DB, 0x1234, "", "Dreamcast Broadband Adapter" } , - { 0x11DE, 0x6057, "ZR36067", "AV PCI Controller" } , - { 0x11DE, 0x6067, "zr36067pqc", "zoran" } , - { 0x11DE, 0x6120, "ZR36120PQC", "MPEG VideoBVPSXI Capture Card" } , - { 0x11DE, 0x6057, "ZR36057PQC", "ZORAN PCI Bridge (interface for transferring video across the PCI bus)" } , - { 0x11DE, 0x9876, "", "" } , - { 0x11EC, 0x2064, "", "" } , - { 0x11F0, 0x4231, "", "" } , - { 0x11F0, 0x4232, "FASTline UTP Quattro", "" } , - { 0x11F0, 0x4233, "FASTline FO", "" } , - { 0x11F0, 0x4234, "FASTline UTP", "" } , - { 0x11F0, 0x4235, "FASTline-II UTP", "" } , - { 0x11F0, 0x4236, "FASTline-II FO", "" } , - { 0x11F0, 0x4731, "GIGAline", "Gigabit Ethernet Adapter" } , - { 0x11F4, 0x2915, "2915", "" } , - { 0x11F6, 0x0112, "ATT2MD11", "ReadyLink ENET100-VG4" } , - { 0x11F6, 0x0113, "", "FreedomLine 100" } , - { 0x11F6, 0x1401, "832AE28030680", "ReadyLink RL2000" } , - { 0x11F6, 0x2011, "TXA9882", "ReadyLink RL100ATX/PCI Fast Ethernet Adapter" } , - { 0x11F6, 0x2201, "TXA9883", "ReadyLink 100TX (Winbond W89C840)" } , - { 0x11F6, 0x9881, "TXA9881?", "ReadyLink RL100TX Fast Ethernet Adapter" } , - { 0x11F8, 0x7364, "PM7364", "FREEDM-32 Frame Engine & Datalink Mgr" } , - { 0x11F8, 0x7366, "PM7364", "FREEDM-8 Frame Engine & Datalink Manager" } , - { 0x11F8, 0x7367, "PM7367", "FREEDM-32P32 Frame Engine & Datalink Mgr" } , - { 0x11F8, 0x7375, "PM7375", "LASAR-155 ATM SAR" } , - { 0x11F8, 0x7380, "PM7380", "FREEDM-32P672 Frm Engine & Datalink Mgr" } , - { 0x11F8, 0x7382, "PM7382", "FREEDM-32P256 Frm Engine & Datalink Mgr" } , - { 0x11F8, 0x7384, "PM7384", "FREEDM-84P672 Frm Engine & Datalink Mgr" } , - { 0x11F8, 0x8000, "PM8000 SPC", "6G SAS/SATA Controller" } , - { 0x11F8, 0x8010, "PM8010 SRC", "6G SAS/SATA RAID Controller" } , - { 0x11FE, 0x0001, "RocketPort", "" } , - { 0x11FE, 0x0002, "RocketPort", "" } , - { 0x11FE, 0x0003, "RocketPort", "" } , - { 0x11FE, 0x0004, "RocketPort", "" } , - { 0x11FE, 0x0005, "RocketPort", "" } , - { 0x11FE, 0x0006, "RocketPort", "" } , - { 0x11FE, 0x0007, "RocketPort", "" } , - { 0x11FE, 0x0008, "RocketPort", "" } , - { 0x11FE, 0x0009, "RocketPort", "" } , - { 0x11FE, 0x000A, "RocketPort", "" } , - { 0x11FE, 0x000B, "RocketPort", "" } , - { 0x11FE, 0x000C, "RocketPort", "" } , - { 0x11FE, 0x000D, "RocketPort", "" } , - { 0x11FE, 0x8015, "RocketPort", "4-port UART 16954" } , - { 0x1202, 0x0001, "NAIATMPCI", "PCI ATM Adapter" } , - { 0x1208, 0x4853, "", "HS-Link Device" } , - { 0x1365, 0x9050, "HYSDN", "" } , - { 0x1209, 0x0100, "PCI 9054", "PLX PCI BRIDGE" } , - { 0x120E, 0x0100, "Cyclom-Y", "Multiport Serial Card" } , - { 0x120E, 0x0101, "Cyclom-Y", "Multiport Serial Card" } , - { 0x120E, 0x0102, "Cyclom-4Y", "Multiport Serial Card" } , - { 0x120E, 0x0103, "Cyclom-4Y", "Multiport Serial Card" } , - { 0x120E, 0x0104, "Cyclom-8Y", "Multiport Serial Card" } , - { 0x120E, 0x0105, "Cyclom-8Y", "Multiport Serial Card" } , - { 0x120E, 0x0200, "Cyclom-Z", "Intelligent Multiport Serial" } , - { 0x120E, 0x0201, "Cyclom-Z", "Intelligent Serial Card" } , - { 0x120E, 0x0300, "PC300 RX 2", "" } , - { 0x120E, 0x0301, "PC300 RX 1", "" } , - { 0x120E, 0x0302, "PC300 TE 2", "" } , - { 0x120E, 0x0303, "PC300 TE 1", "" } , - { 0x120F, 0x0001, "Roadrunner", "" } , - { 0x1216, 0x0003, "?", "PTM400 PCI Taxi Module" } , - { 0x1217, 0x00f7, "0x00f71217", "1394 Open Host Controller Interface" } , - { 0x1217, 0x6729, "OZ6729", "PCI to PCMCIA Bridge" } , - { 0x1217, 0x673A, "OZ6730", "PCI to PCMCIA Bridge" } , - { 0x1217, 0x6832, "OZ6832/3", "CardBus Controller" } , - { 0x1217, 0x6836, "OZ6836/6860", "CardBus Controller" } , - { 0x1217, 0x6872, "OZ6812", "CardBus Controller" } , - { 0x1217, 0x6925, "OZ6922", "CardBus Controller" } , - { 0x1217, 0x6933, "OZ6933", "CardBus Controller" } , - { 0x1217, 0x6972, "OZ6912", "CardBus Controller" } , - { 0x1217, 0x7110, "OZ711Mx", "MemoryCardBus Accelerator" } , - { 0x1217, 0x7113, "0Z711EC1", "SmartCardBus Contoller" } , - { 0x1217, 0x7114, "OZ711M1", "CardBus Controller" } , - { 0x1217, 0x7120, "Unknown device", "O2Micro Integrated MMC/SD controller" } , - { 0x1217, 0x7130, "OZ711M3", "Integrated MMC/SD/MS/xD/SM Controller" } , - { 0x1217, 0x7134, "OZ711MP1/MS1", "MemoryCardBus Controller 6-in-1" } , - { 0x1217, 0x7222, "unknow", "pci to pcmcia bridge" } , - { 0x1217, 0x7223, "OZ711M3/MC3", "MemoryCardBus Controller" } , - { 0x121A, 0x0001, "Voodoo", "Voodoo 3D Acceleration Chip" } , - { 0x121A, 0x0002, "Voodoo2", "Voodoo 2 3D Accelerator" } , - { 0x121A, 0x0003, "Voodoo Banshee", "Voodoo Banshee" } , - { 0x121A, 0x0005, "Voodoo3", "All Voodoo3 chips, 3000" } , - { 0x121A, 0x0007, "Voodoo4", "" } , - { 0x121A, 0x0009, "Voodoo5", "" } , - { 0x121A, 0x0010, "Rampage", "Rev.A AGPx4, 0.25�, 200/2x200 core/RAM" } , - { 0x121A, 0x0057, "Voodoo 3/3000", "Avenger" } , - { 0x1220, 0x1220, "9622qac", "AMCC 5933 TMS320C80 DSP/Imaging Board" } , - { 0x1220, 0x4242, " ", "controller audio multimediale" } , - { 0x1223, 0x0001, "KatanaQp", "Real-Time Processing Blade in a standard single-slot AdvancedTCA� formfactor" } , - { 0x1223, 0x0002, "KosaiPM", "Intel� Pentium-M� based AMC Module" } , - { 0x1223, 0x003, "Katana3752", "Advanced Tri-Processor Blade" } , - { 0x1223, 0x004, "Katana3750", "Advanced Tri-Processor Blade" } , - { 0x1223, 0x0044, "Memory controller", "Memory controller" } , - { 0x1223, 0x005, "Katana752i", "Real-time Processing Blade" } , - { 0x1223, 0x006, "Katana750i", "Real-time Processing Blade" } , - { 0x1223, 0x007, "CC1000dm", "Processor PMC Carrier Card" } , - { 0x1223, 0x008, "Pm3Gv", "Up to 8 E1/T1/J1 interfaces for PMC-compatible baseboards" } , - { 0x1223, 0x009, "Pm3GE1T1", "Third Generation E1 and T1/J1 interfaces for PMC-compatible baseboards" } , - { 0x1223, 0x010, "SpiderwareSG", "SIGTRAN Signalling Gateway Blade" } , - { 0x1223, 0x011, "SpiderwareSS7", "64 SS7 signaling channels on a single blade" } , - { 0x1223, 0x012, "SpiderSS7", "Portable, STREAMS-Based Implementation of the ITU SS7 Protocol Stack" } , - { 0x1223, 0x013, "Spider FRAME RELAY", "STREAMS-Based Frame Relay Implementation" } , - { 0x1223, 0x014, "Spider STREAMS", "Implementation of the UNIX STREAMS Environment" } , - { 0x1223, 0x015, "Spider DSF", "Transparent STREAMS Interface for High Speed LAN or Shared Memory Systems" } , - { 0x1224, 0x1000, "CL560?", "Plum Audio, Video and VTR Controller" } , - { 0x122D, 0x1206, "ICH2", "Asus" } , - { 0x122D, 0x4201, "MR2800W", "AMR 56K modem" } , - { 0x122D, 0x50DC, "PCI168/3328", "Audio" } , - { 0x122D, 0x80DA, "3328", "Audio" } , - { 0x122F, 0x37AF, "0x9030", "Reflectometer using PLX 9030" } , - { 0x1668, 0x0100, "0304", "PCI to PCI Bridge" } , - { 0x1236, 0x0000, "RealMagic64/GX", "SD6425" } , - { 0x1236, 0x0531, "MX98715/25", "Single Chip Fast Ethernet NIC Controller" } , - { 0x1236, 0x3d01, "?", "RealMagic/2D" } , - { 0x1236, 0x6401, "REALmagic64/GX", "GUI" } , - { 0x1236, 0x9708, "realmagic64/gx", "sd6425" } , - { 0x123D, 0x0010, "PCI-DV", "PCI-DV Digital Video Interface" } , - { 0x123F, 0x00E4, "cl 480", "MPEG" } , - { 0x123F, 0x6120, "12.03", "DVD device" } , - { 0x123F, 0x8120, "176", "i845E" } , - { 0x123F, 0x8888, "12.03", "cPEG C 3.0 DVD/MPEG2 Decoder" } , - { 0x1241, 0x1603, "1", "keyboard" } , - { 0x1244, 0x0700, "B1", "ISDN controller" } , - { 0x1244, 0x0800, "C4", "ISDN Controller" } , - { 0x1244, 0x0A00, "A1", "ISDN Controller" } , - { 0x1244, 0x0E00, "", "Fritz!PCI 2.0 ISDN Controller" } , - { 0x1244, 0x1100, "C2", "ISDN Controller" } , - { 0x1244, 0x1200, "T1", "ISDN Controller" } , - { 0x1244, 0x2700, "E13 32A5KYW / 2CAKRCT", "DSP TNETD5100GHK / TNETD5015" } , - { 0x124A, 0x10BD, "82566DM-2", "Intel Gigabit network connection" } , - { 0x124C, 0x0220, ".", "." } , - { 0x124D, 0x0000, "EasyConnect 8/32", "" } , - { 0x124D, 0x0002, "EasyConnect 8/64", "" } , - { 0x124D, 0x0003, "EasyIO PCI", "" } , - { 0x124F, 0x0041, "IFT-2000", "PCI RAID Controller" } , - { 0x1250, 0x1978, "", "" } , - { 0x1250, 0x2898, "", "" } , - { 0x1255, 0x1110, "MPEG Forge", "" } , - { 0x1255, 0x1210, "MPEG Fusion", "" } , - { 0x1255, 0x2110, "VideoPlex-pci", "VideoPlex pci bpc1825 rev a" } , - { 0x1255, 0x2120, "VideoPlex plus", "VideoPlex BPC 1851 A" } , - { 0x1255, 0x2130, "VideoQuest", "" } , - { 0x1256, 0x4201, "PCI-2240i", "EIDE Adapter" } , - { 0x1256, 0x4401, "PCI-2220i", "Dale EIDE Adapter" } , - { 0x1256, 0x5201, "PCI-2000", "IntelliCache SCSI Adapter" } , - { 0x1258, 0x1988, "", "" } , - { 0x1259, 0x2503, "Realtek 8139b", "" } , - { 0x1259, 0x2560, "", "AT-2560 Fast Ethernet Adapter (i82557B)" } , - { 0x1259, 0xc107, "Realtek 8169S", "" } , - { 0x125B, 0x0B95, "AX88772", "USB2.0 to 10/100M Fast Ethernet Controller" } , - { 0x125B, 0x1400, "AX88140A", "ASIX AX88140 Based PCI Fast Ethernet Adapter" } , - { 0x125B, 0x1720, "AX88172", "USB2 to Fast Ethernet Adapter" } , - { 0x125D, 0x0000, "ESS336H", "PCI Fax Modem (early model)" } , - { 0x125D, 0x1961, "Multimedia Device", "ESS Solo-1 Soundcard" } , - { 0x125D, 0x1968, "ES2839", "Maestro-2 PCI audio accelerator" } , - { 0x125D, 0x1969, "ES72222", "Solo-1 PCI AudioDrive family" } , - { 0x125D, 0x1978, "ES1978", "ESS Maestro-2E PCI Audiodrive" } , - { 0x125D, 0x1988, "ES1989", "ESS Allegro PCI Audio (WDM)" } , - { 0x125D, 0x1989, "ES1989", "ESS Maestro 3 PCI Audio (WDM)" } , - { 0x125D, 0x1990, "ES2898S", "" } , - { 0x125D, 0x1992, "", "" } , - { 0x125D, 0x1998, "Maestro 3i", "Maestro 3i" } , - { 0x125D, 0x199B, "ES1938/41/46 solo audio", "Maestro-3.COMM PCI Voice+audio" } , - { 0x125D, 0x2808, "ES336H", "PCI Fax Modem (later model)" } , - { 0x125D, 0x2828, "ES2828S", "TeleDrive" } , - { 0x125D, 0x2838, "ES56H-PI", "Data Fax Modem" } , - { 0x125D, 0x2839, "2838", "Superlink Modem/V.92 chipset 56K" } , - { 0x125D, 0x2898, "2898", "TelDrive ES56T-PI family V.90 PCI modem" } , - { 0x125F, 0x2084, "AMCC S5933", "AMCC Bridge + 2 x Super I/O (National PC97338)" } , - { 0x1260, 0x3872, "PRISM 3", "LAN-Express IEEE 802.11b PCI Adapter" } , - { 0x1260, 0x3873, "ISL3874A", "PRISMII.5 IEE802.11B Wireless LAN" } , - { 0x1260, 0x3886, "Unknown", "Creatix CTX405 WLAN Controller" } , - { 0x1260, 0x3890, "ISL3890", "PRISM GT 802.11g 54Mbps Wireless Controller" } , - { 0x1260, 0x8130, "HMP8130", "NTSC/PAL Video Decoder" } , - { 0x1260, 0x8131, "HMP8131", "NTSC/PAL Video Decoder" } , - { 0x1266, 0x0001, "", "NE10/100 Adapter (i82557B)" } , - { 0x1266, 0x1910, "", "NE2000Plus (RT8029) Ethernet Adapter" } , - { 0x1267, 0x1016, "", "NICCY PCI card" } , - { 0x1267, 0x4243, "", "Satellite receiver board / MPEG2 decoder" } , - { 0x1267, 0x5352, "PCR2101", "" } , - { 0x1267, 0x5A4B, "telsatturbo", "" } , - { 0x1382, 0x0001, "unknown", "Sek'D ARC88 professional soundcard" } , - { 0x1382, 0x2009, "PLX TECHNOLOGY \n PCI9052 \n 0435 \n BX9497.1 MALA", "SEK'D Prodif 96 Pro - professional audio card" } , - { 0x1382, 0x2048, "2048", "Prodif Plus sound card" } , - { 0x1382, 0x2088, "Marc 8 Midi", "8-in, 8-out sound card" } , - { 0x1268, 0x0204, "Unknown", "Tektronix IO Processor / Tektronix PCI Acquisition Interface Rev 204" } , - { 0x126C, 0x1F1F, "", "e-mobility 802.11b Wireless LAN PCI Card" } , - { 0x126F, 0x0710, "SM710", "LynxEM" } , - { 0x126F, 0x0712, "SM712", "LynxEM+" } , - { 0x126F, 0x0720, "SM720 / SM722", "Lynx3DM" } , - { 0x126F, 0x0810, "SM810", "LynxE" } , - { 0x126F, 0x0811, "SM811", "LynxE" } , - { 0x126F, 0x0820, "SM820", "Lynx3D" } , - { 0x126F, 0x0910, "SM910", "SILICON MOTION" } , - { 0x1273, 0x0002, "DirecPC", "t9p17af-01" } , - { 0x1274, 0X1005, "", "" } , - { 0x1274, 0x1274, "5880x", "multimedia audio device" } , - { 0x1274, 0x1371, "ES 1371", "AudioPCI" } , - { 0x1274, 0x1373, "ES1373", "Sound Blaster Audio(PCI)" } , - { 0x1274, 0x5000, "ES1371", "AudioPCI" } , - { 0x1274, 0x5880, "5880x", "AudioPci" } , - { 0x1274, 0x9876, "", "" } , - { 0x1278, 0x0701, "TPE3/TM3", "PowerPC Node" } , - { 0x1279, 0x0060, "TM8000", "Efficeon Virtual Northbridge" } , - { 0x1279, 0x0061, "TMTM8000", "Efficeon AGP Bridge" } , - { 0x1279, 0x0295, "", "Virtual Northbridge" } , - { 0x1279, 0x0395, "LongRun", "Northbridge" } , - { 0x1279, 0x0396, "", "SDRAM Controller" } , - { 0x1279, 0x0397, "", "BIOS scratchpad" } , - { 0x1282, 0x9009, "DM9009", "Ethernet Adapter" } , - { 0x1282, 0x9100, "", "" } , - { 0x1282, 0x9102, "DM9102/A/AF", "10/100 Mbps Fast Ethernet Controller" } , - { 0x1283, 0x0801, "IT8152F/G", "Audio Digital Controller" } , - { 0x1283, 0x673A, "IT8330G", "IDE Controller" } , - { 0x1283, 0x8152, "IT8152F/G", "Advanced RISC-to-PCI Companion Chip" } , - { 0x1283, 0x8172, "IT8172G", "Ultra RISC (MIPS, SH4) Companion Chip" } , - { 0x1283, 0x8211, "IT8211F", "ATA/ATAPI Controller" } , - { 0x1283, 0x8212, "IT8212F", "ATA 133 IDE RAID Controller" } , - { 0x1283, 0x8213, "IT8213F", "IDE Controller" } , - { 0x1283, 0x8330, "IT8330G", "Host Bridge" } , - { 0x1283, 0x8872, "IT8871/72", "PCI-ISA I/O chip with SMB & Parallel Port" } , - { 0x1283, 0x8875, "IT8875F", "PCI Parallel Port" } , - { 0x1283, 0x8888, "IT8888F", "PCI to ISA Bridge" } , - { 0x1283, 0x8889, "IT8889F", "sound" } , - { 0x1283, 0x9876, "IT8875F", "PCI I/O CARD" } , - { 0x1283, 0xE886, "IT8330G", "PCI to ISA Bridge" } , - { 0x1285, 0x0100, "ES1849", "Maestro-1 AudioDrive" } , - { 0x1287, 0x001E, "LS220D", "DVD Decoder" } , - { 0x1287, 0x001F, "LS220C", "DVD Decoder" } , - { 0x1287, 0x0020, "LS242", "MPEG/DVD video decoder" } , - { 0x1289, 0x1006, "", "" } , - { 0x128A, 0xF001, "Ethernet 10/100", "AsanteFAST 10/100 PCI Ethernet Adapter" } , - { 0x128D, 0x0021, "", "ATM Adapter" } , - { 0x13FE, 0x1240, "PCI-1710", "4-Axis Stepping/Servo Motor Card" } , - { 0x13FE, 0x1680, "PCI-1680U-A", "2-port CAN UniversalPCI Communication Card with Isolation" } , - { 0x13FE, 0x1713, "PCI-1713", "32-channel Isolated Analog Input Card" } , - { 0x13FE, 0x1724, "PCI-1724", "14-bit, 32-channel Isolated Analog Output Card" } , - { 0x13FE, 0x1760, "", "" } , - { 0x129A, 0x0415, "PBT-415", "PCI 66MHz Analyzer and 33MHz Exerciser" } , - { 0x129A, 0x0515, "PBT-515", "PCI 66MHz Analyzer and Exerciser" } , - { 0x129A, 0x0615, "PBT-615", "PCI 66MHz and PCI-X 100MHz Bus Analyzer and Exerciser" } , - { 0x129A, 0x0715, "Vanguard PCI/PMC/cPCI", "PCI 66MHz and PCI-X 133MHz Bus Analyzer and Exerciser" } , - { 0x129A, 0xDD10, "DPIO", "Digital Parallel Input Output Device 32bit, 33MHz PCI bus" } , - { 0x129A, 0xDD11, "DPIO2", "Digital Parallel Input Output Device 64bit, 33MHz PCI bus" } , - { 0x129A, 0xDD12, "DPIO2-66", "Digital Parallel Input Output Device 64bit, 66MHz PCI bus" } , - { 0x12A0, 0x0008, "1784-PKTX", "Allen-Bradley 1784-PKTX" } , - { 0x12A3, 0xECB8, "1646T00", "V.92 Lucent Modem" } , - { 0x12AA, 0x5568, "Wan405", "WANic 400 series X.21 controller" } , - { 0x12AA, 0x556C, "", "NAI HSSI Sniffer PCI Adapter" } , - { 0x12AB, 0x3000, "JRS-3DS100", "PCI" } , - { 0x12AD, 0x0010, "1", "HERMES-S0" } , - { 0x12AD, 0x0020, "1", "HERMES-PRI" } , - { 0x12AD, 0x0080, "1", "HERMES-PRI/PCIX" } , - { 0x12AE, 0x0001, "3C986", "ACEnic 1000 BASE-SX Ethernet adapter" } , - { 0x12AE, 0x0002, "3C986-T", "Copper Gigabit Ethernet Adapter" } , - { 0x12BA, 0x0032, "Hammerhead-Lite-PCI", "DSP Prototyping & Development Card" } , - { 0x12C1, 0x9080, "Sync4hs/CCP/PCI/MP", "Communications Processor" } , - { 0x13A3, 0x0005, "7751", "Security Processor" } , - { 0x13A3, 0x0006, "6500", "Public Key Processor" } , - { 0x13A3, 0x0007, "7811", "Security Processor" } , - { 0x13A3, 0x0012, "7951", "Security Processor" } , - { 0x13A3, 0x0014, "7814/7851/7854", "Security Processor" } , - { 0x13A3, 0x0015, "8065", "Security Processor" } , - { 0x13A3, 0x0017, "8165", "Security Processor" } , - { 0x13A3, 0x0018, "8154", "Security Processor" } , - { 0x13A3, 0x001d, "7956", "Cryptographic Processor" } , - { 0x13A3, 0x0020, "7954/7955", "Cryptographic Processor" } , - { 0x13A3, 0x0016, "8065", "Security Processor" } , - { 0x12C3, 0x0058, "HT80232", "LAN Adapter (NE2000-compatible)" } , - { 0x12C3, 0x5598, "HT80229", "Ethernet Adapter (NE2000-compatible)" } , - { 0x12C4, 0x0001, "", "" } , - { 0x12C4, 0x0002, "", "" } , - { 0x12C4, 0x0003, "", "" } , - { 0x12C4, 0x0004, "", "" } , - { 0x12C4, 0x0005, "Blue Heat-8 RS232", "BlueHeat 8 Port RS232 Serial Board" } , - { 0x12C4, 0x0006, "", "" } , - { 0x12C4, 0x0007, "", "" } , - { 0x12C4, 0x0008, "", "" } , - { 0x12C4, 0x0009, "", "" } , - { 0x12C4, 0x000A, "", "" } , - { 0x12C4, 0x000B, "", "" } , - { 0x12C4, 0x000C, "", "" } , - { 0x12C4, 0x000D, "", "" } , - { 0x12C4, 0x000E, "", "" } , - { 0x12C4, 0x000F, "", "" } , - { 0x12C4, 0x0300, "", "" } , - { 0x12C4, 0x0301, "", "" } , - { 0x12C4, 0x0302, "", "" } , - { 0x12C4, 0x0303, "", "" } , - { 0x12C4, 0x0304, "", "" } , - { 0x12C4, 0x0305, "", "" } , - { 0x12C4, 0x0306, "", "" } , - { 0x12C4, 0x0307, "", "" } , - { 0x12C4, 0x0308, "", "" } , - { 0x12C4, 0x0309, "", "" } , - { 0x12C4, 0x030A, "", "" } , - { 0x12C4, 0x030B, "", "" } , - { 0x12C5, 0x007F, "ISE", "PEI Imaging Subsystem Engine" } , - { 0x12C5, 0x0081, "PCIVST", "PCI Thresholding Engine" } , - { 0x12C5, 0x0085, "", "Video Simulator/Sender" } , - { 0x12C5, 0x0086, "THR2", "Multi-scale Thresholder" } , - { 0x12C7, 0x0546, "kssjsjj", "D120JCT-LS Card" } , - { 0x12C7, 0x0561, "", "BRI/2 Type Card (Voice Driver)" } , - { 0x12C7, 0x0647, "", "D/240JCT-T1 Card" } , - { 0x12C7, 0x0648, "", "D/300JCT-E1 Card" } , - { 0x12C7, 0x0649, "", "D/300JCT-E1 Card" } , - { 0x12C7, 0x0651, "", "MSI PCI Card" } , - { 0x12C7, 0x0673, "", "BRI/160-PCI Card" } , - { 0x12C7, 0x0674, "", "BRI/120-PCI Card" } , - { 0x12C7, 0x0675, "", "BRI/80-PCI Card" } , - { 0x12C7, 0x0676, "", "D/41JCT Card" } , - { 0x12C7, 0x0685, "", "D/480JCT-2T1 Card" } , - { 0x12C7, 0x0687, "", "D/600JCT-2E1 (75 Ohm) Card" } , - { 0x12C7, 0x0689, "D/600JCT-2E1", "Dialogic 2E1 - JCT series" } , - { 0x12C7, 0x0707, "", "D/320JCT (Resource Only) Card" } , - { 0x12C7, 0x0708, "", "D/160JCT (Resource Only) Card" } , - { 0x12CB, 0x0027, "StudioCard", "" } , - { 0x12CB, 0x002D, "BX-12", "" } , - { 0x12CB, 0x002E, "SC-2000", "" } , - { 0x12CB, 0x002F, "LX-44", "" } , - { 0x12CB, 0x0030, "SC-22", "" } , - { 0x12CB, 0x0031, "BX-44", "" } , - { 0x12CB, 0x0032, "LX-24M", "20-bit 2-in, 4-out audio card w/MPEG-2" } , - { 0x12CB, 0x0033, "LX-22M", "" } , - { 0x12CB, 0x0034, "BX-8", "" } , - { 0x12CB, 0x0035, "BX-12e", "" } , - { 0x12D4, 0x0301, "EP1S", "SS7 Telecommunications Interface Adapter" } , - { 0x12D5, 0x1000, "MAP-CA", "Broadband Signal Processor" } , - { 0x12D5, 0x1002, "MAP-1000", "Digital Signal Processor" } , - { 0x1755, 0x0000, "Au1500", "Au1500 Processor" } , - { 0x12D8, 0x71E2, "PI7C7300", "3 Port PCI to PCI bridge" } , - { 0x12D8, 0x8150, "PI7C8150", "2-Port PCI to PCI Bridge" } , - { 0x12D8, 0x8152, "PI7C8152", "2-Port PCI-To-PCI Bridge" } , - { 0x12D8, 0xe130, "PI7C9X130", "PCI-X Bridge" } , - { 0x12DB, 0x0003, "", "FoxFire II" } , - { 0x12DE, 0x0200, "", "Cryptoswift 200" } , - { 0x12DF, 0x2102, "Infineon PEB 20534", "Communications Controller" } , - { 0x12DF, 0x8236, "Unknown", "PCI Controller" } , - { 0x12E0, 0x0010, "ST16C654", "Quad UART" } , - { 0x12E0, 0x0020, "ST16C654", "Quad UART" } , - { 0x12E0, 0x0030, "ST16C654", "Quad UART" } , - { 0x12E4, 0x1000, "TR1000 PRI", "PRI Controller" } , - { 0x12E4, 0x1140, "", "ISDN Controller" } , - { 0x12E4, 0xB005, "TR1000 BRI", "BRI Controller" } , - { 0x12E4, 0xB006, "TR1000 BRI", "BRI Controller" } , - { 0x12EB, 0x0001, "AU8820", "Vortex 1 Digital Audio Processor" } , - { 0x12EB, 0x0002, "AU8830A2", "Vortex 2 Audio Processor" } , - { 0x12EB, 0x0003, "312EB&REV3", "Aureal Soundcard" } , - { 0x12EC, 0x8139, "0xxxx", "0xxxx" } , - { 0x12F2, 0x1002, "215RAAGCGA11F", "Grapics Radeon X850" } , - { 0x12F2, 0x3059, "VT8237", "AC97 Enhanced Audio Controller - the 8251 controller is different" } , - { 0x12F8, 0x0002, "VideoMaker", "s3 trio" } , - { 0x1DE1, 0x0391, "TRM-S1040", "SCSI ASIC" } , - { 0x1DE1, 0x2020, "DC-390", "SCSI Controller" } , - { 0x1DE1, 0x690C, "DC-690C", "IDE Cache Controller" } , - { 0x1DE1, 0xDC29, "DC290M", "Bus Master IDE PCI 2 controllers" } , - { 0x3D3D, 0x0001, "GLint 300SX", "3D Accelerator" } , - { 0x3D3D, 0x0002, "GLint 500TX", "Sapphire 3D Accelerator" } , - { 0x3D3D, 0x0003, "GLint", "Delta Geometry processor" } , - { 0x3D3D, 0x0004, "3C0SX", "2D+3D Accelerator" } , - { 0x3D3D, 0x0005, "Permedia", "2D+3D Accelerator" } , - { 0x3D3D, 0x0006, "GLint MX", "3D Accelerator" } , - { 0x3D3D, 0x0007, "3D Extreme", "Permedia II 2D+3D Accelerator" } , - { 0x3D3D, 0x0008, "GLint Gamma G1", "" } , - { 0x3D3D, 0x0009, "Permedia2v", "2d+3d chipset, integrated ramdac" } , - { 0x3D3D, 0x000A, "Permedia 3", "" } , - { 0x3D3D, 0x000C, "Permedia 3", "" } , - { 0x3D3D, 0x000D, "GLINT R4", "3D Accelerator" } , - { 0x3D3D, 0x000E, "GLINT Gamma G2", "" } , - { 0x3D3D, 0x0030, "0x030000", "3Dlabs Wildcat Realizm 800" } , - { 0x3D3D, 0x0100, "Permedia II", "2D+3D Accelerator" } , - { 0x3D3D, 0x1004, "Permedia", "3D+3D Accelerator" } , - { 0x3D3D, 0x3D04, "Permedia", "2D+3D Accelerator" } , - { 0x3D3D, 0xFFFF, "GLint VGA", "" } , - { 0x4005, 0x0300, "3220", "PCI Audio Device" } , - { 0x4005, 0x0308, "3220", "PCI Audio Device + modem" } , - { 0x4005, 0x0309, "ALS300+", "PCI Input Controller" } , - { 0x4005, 0x1064, "ALG2064", "GUI Accelerator" } , - { 0x4005, 0x2064, "", "GUI Accelerator" } , - { 0x4005, 0x2128, "ALG2364A", "GUI Accelerator" } , - { 0x4005, 0x2301, "ALG2301", "GUI Accelerator" } , - { 0x4005, 0x2302, "ALG2302", "GUI Accelerator" } , - { 0x4005, 0x2303, "AVG2302", "GUI Accelerator" } , - { 0x4005, 0x2364, "ALG2364", "GUI Accelerator" } , - { 0x4005, 0x2464, "ALG2464", "GUI Accelerator" } , - { 0x4005, 0x2501, "ALG2564A/25128A", "GUI Accelerator" } , - { 0x4005, 0x4000, "ALS4000", "Audio Chipset" } , - { 0x5333, 0x0551, "86C551", "Plato/PX" } , - { 0x5333, 0x5333, "S3 86c765", "via" } , - { 0x5333, 0x5631, "86C325", "Virge 3D " } , - { 0x5333, 0x8800, "86C866", "Vision 866 GUI Accelerator" } , - { 0x5333, 0x8801, "86C964", "Vision 964 GUI Accelerator" } , - { 0x5333, 0x8810, "86C732-P", "S3 TRIO32 IACB2 86C732-P" } , - { 0x5333, 0x8811, "8622mcq04", "Trio 64/64V" } , - { 0x5333, 0x8812, "86CM65?", "Aurora 64V+" } , - { 0x5333, 0x8813, "86C764", "Trio 32/64 GUI Accelerator v3" } , - { 0x5333, 0x8814, "86C767", "Trio 64UV+" } , - { 0x5333, 0x8815, "86CM66", "Aurora128" } , - { 0x5333, 0x883D, "86C988", "ViRGE/VX 3D GUI Accelerator" } , - { 0x5333, 0x8870, "Fire GL", "" } , - { 0x5333, 0x8880, "86C868", "Vision 868 GUI Accelerator VRAM rev. 0" } , - { 0x5333, 0x8881, "86C868", "Vision 868 GUI Accelerator VRAM rev. 1" } , - { 0x5333, 0x8882, "86C868", "Vision 868 GUI Accelerator VRAM rev. 2" } , - { 0x5333, 0x8883, "86C868", "Vision 868 GUI Accelerator VRAM rev. 3" } , - { 0x5333, 0x88B0, "86C928", "Vision 928 GUI Accelerator VRAM rev. 0" } , - { 0x5333, 0x88B1, "86C928", "Vision 928 GUI Accelerator VRAM rev. 1" } , - { 0x5333, 0x88B2, "86C928", "Vision 928 GUI Accelerator VRAM rev. 2" } , - { 0x5333, 0x88B3, "86C928", "Vision 928 GUI Accelerator VRAM rev. 3" } , - { 0x5333, 0x88C0, "86C864", "Vision 864 GUI Accelerator DRAM rev. 0" } , - { 0x5333, 0x88C1, "86C864", "Vision 864 GUI Accelerator DRAM rev. 1" } , - { 0x5333, 0x88C2, "86C864", "Vision 864 GUI Accelerator DRAM rev. 2" } , - { 0x5333, 0x88C3, "86C864", "Vision 864 GUI Accelerator DRAM rev. 3" } , - { 0x5333, 0x88D0, "86C964", "Vision 964 GUI Accelerator VRAM rev. 0" } , - { 0x5333, 0x88D1, "86C964", "Vision 964-P GUI Accelerator VRAM rev. 1" } , - { 0x5333, 0x88D2, "86C964", "Vision 964-P GUI Accelerator DRAM rev 2" } , - { 0x5333, 0x88D3, "86C964", "Vision 964-P GUI Accelerator VRAM rev. 3" } , - { 0x5333, 0x88F0, "86C968", "Vision 968 GUI Accelerator VRAM rev. 0" } , - { 0x5333, 0x88F1, "86C968", "Vision 968 GUI Accelerator VRAM rev. 1" } , - { 0x5333, 0x88F2, "86C968", "Vision 968 GUI Accelerator VRAM rev. 2" } , - { 0x5333, 0x88F3, "86C968", "Vision 968 GUI Accelerator VRAM rev. 3" } , - { 0x5333, 0x8900, "86C775", "Trio64V2/DX" } , - { 0x5333, 0x8901, "pci\ven_5333dev_8C2E&SUBSYS_00011179&REV_05\4&74C6", "S3 trio64uv+ for windows xp" } , - { 0x5333, 0x8902, "86C551", "SMA Family" } , - { 0x5333, 0x8903, "", "TrioV Family" } , - { 0x5333, 0x8904, "86C365/366", "Trio3D QFP/BGA" } , - { 0x5333, 0x8905, "86c765", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x8906, "86c765", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x8907, "86c765", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x8908, "9711 MCN74", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x8909, "7699688", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x890A, "0x00091011", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x890B, "9726 c19394.00", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x890C, "86C765", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x890D, "", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x890E, "9711 MCN74", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x890F, "86c765", "86C765 Trio64V+ compatible" } , - { 0x5333, 0x8A01, "86C375/86C385", "ViRGE /DX & /GX" } , - { 0x5333, 0x8A10, "86C357", "ViRGE /GX2" } , - { 0x5333, 0x8A11, "86C359", "ViRGE /GX2+ Macrovision" } , - { 0x5333, 0x8A12, "86C359", "ViRGE /GX2+" } , - { 0x5333, 0x8A13, "86C368", "Trio3D2x & Trio3D2x+ AGP / Trio3D2x & Trio3D2x+ 8MB" } , - { 0x5333, 0x8A20, "86C391", "S3savage3D" } , - { 0x5333, 0x8A21, "86C390", "Savage3D/MV" } , - { 0x5333, 0x8A22, "86c398", "Savage 4" } , - { 0x5333, 0x8A23, "86C394-397", "Savage 4" } , - { 0x5333, 0x8A25, "86C370", "Savage4" } , - { 0x5333, 0x8A26, "86C395B", "ProSavage" } , - { 0x5333, 0x8C00, "85C260", "ViRGE/M3 (ViRGE/MX)" } , - { 0x5333, 0x8C01, "86C260", "ViRGE/M5 (ViRGE/MX)" } , - { 0x5333, 0x8C02, "86C240", "ViRGE/MXC" } , - { 0x5333, 0x8C03, "86C280 db", "ViRGE /MX+mv" } , - { 0x5333, 0x8C10, "86C270/274/290/294", "Savage MX/IX/MX+MV/IX+MV" } , - { 0x5333, 0x8C12, "86C270/274/290/294", "Savage MX/IX/MX+MV/IX+MV" } , - { 0x5333, 0x8C13, "82C294", "SAVAGE IX" } , - { 0x5333, 0x8C22, "86C508", "SuperSavage 128/MX" } , - { 0x5333, 0x8C2A, "86C544", "SuperSavage 128/IX" } , - { 0x5333, 0x8C2B, "86C553", "SuperSavage 128/IX DDR" } , - { 0x5333, 0x8C2C, "86C564", "SuperSavage/IX" } , - { 0x5333, 0x8C2D, "86C573", "SuperSavage/IX DDR" } , - { 0x5333, 0x8C2E, "86C584", "SuperSavage/IXC SDRAM" } , - { 0x5333, 0x8C2F, "86C594", "SuperSavage/IXC DDR" } , - { 0x5333, 0x8D01, "86C380/381", "Twister/Twister T" } , - { 0x5333, 0x8D02, "86c387", "Twister K" } , - { 0x5333, 0x8D04, "86C410", "ProSavage DDR" } , - { 0x5333, 0x8E00, "86C777/787", "DeltaChrome S8/F1" } , - { 0x5333, 0x8E01, "86C732", "DeltaChromeX9m" } , - { 0x5333, 0x9102, "86c410", "Inno Savage 2000" } , - { 0x5333, 0xCA00, "86C617", "SonicVibes PCI Audio Accelerator" } , - { 0x165F, 0x2000, "XILINX SPARTAN", "16 Channel Audio Capture Card" } , - { 0x8086, 0x0008, "", "Extended Express System Support Ctrlr" } , - { 0x8086, 0x283E, "AA", "Intel(R) ICH8 Family SMBus Controller" } , - { 0x8086, 0x0309, "80303", "I/O Processor PCI-to-PCI Bridge Unit" } , - { 0x8086, 0x030D, "80312", "I/O Companion Unit PCI-to-PCI Bridge" } , - { 0x8086, 0x0318, "80219", "General Purpose PCI Processor Address Translation Unit" } , - { 0x8086, 0x0319, "80219", "General Purpose PCI Processor Address Translation Unit" } , - { 0x8086, 0x0326, "670xPXH", "I/OxAPIC Interrupt Controller" } , - { 0x8086, 0x0327, "6700PXH", "I/OxAPIC Interrupt Controller B" } , - { 0x8086, 0x0329, "6700PXH", "PCI Express-to-PCI Express Bridge A" } , - { 0x8086, 0x032A, "6700PXH", "PCI Express-to-PCI Express Bridge B" } , - { 0x8086, 0x032C, "6702PXH", "PCI Express-to-PCI Express Bridge" } , - { 0x8086, 0x0330, "80332", "A-Segment Bridge" } , - { 0x8086, 0x0331, "80332", "A-Segment IOAPIC" } , - { 0x8086, 0x0332, "80332", "B-Segment Bridge" } , - { 0x8086, 0x0333, "80332", "B-Segment IOAPIC" } , - { 0x8086, 0x0334, "80332", "Address Translation Unit" } , - { 0x8086, 0x0335, "80331", "PCI-X Bridge" } , - { 0x8086, 0x0336, "80331", "Address Translation Unit (ATU)" } , - { 0x8086, 0x0340, "41210", "Serial to Parallel PCI Bridge A" } , - { 0x8086, 0x0341, "41210", "Serial to Parallel PCI Bridge B" } , - { 0x8086, 0x0370, "80333", "Segment-A PCI Express-to-PCI Express Bridge" } , - { 0x8086, 0x0371, "80333", "A-Bus IOAPIC" } , - { 0x8086, 0x0372, "80333", "Segment-B PCI Express-to-PCI Express Bridge" } , - { 0x8086, 0x0373, "80333", "B-Bus IOAPIC" } , - { 0x8086, 0x0374, "80333", "Address Translation Unit" } , - { 0x8086, 0x0482, "82375MB", "PCI-EISA Bridge (PCEB)" } , - { 0x8086, 0x0483, "82424TX/ZX", "CPU (i486) Bridge (Saturn)" } , - { 0x8086, 0x0484, "82378ZB/IB", "SIO ISA Bridge" } , - { 0x8086, 0x0486, "82425EX", "" } , - { 0x8086, 0x04A3, "82434bX/zX", "Mercury/Neptune Cache/DRAM Controller" } , - { 0x8086, 0x0500, "E8870", "Processor Bus Controller" } , - { 0x8086, 0x0501, "E8870", "Memory Controller" } , - { 0x8086, 0x0502, "E8870", "Scalability Port 0" } , - { 0x8086, 0x0503, "E8870", "Scalability Port 1 / Glob. Perf. Monitor" } , - { 0x8086, 0x0510, "E8870IO", "Hub Interface Port 0 (8-bit compatible)" } , - { 0x8086, 0x0511, "E8870IO", "Hub Interface Port 1" } , - { 0x8086, 0x0512, "E8870IO", "Hub Interface Port 2" } , - { 0x8086, 0x0513, "E8870IO", "Hub Interface Port 3" } , - { 0x8086, 0x0514, "E8870IO", "Hub Interface Port 4" } , - { 0x8086, 0x0515, "E8870IO", "Server I/O Hub (SIOH)" } , - { 0x8086, 0x0516, "E8870IO", "Reliabilty, Availability, Serviceability" } , - { 0x8086, 0x0530, "E8870SP", "Scalability Port 0" } , - { 0x8086, 0x0531, "E8870SP", "Scalability Port 1" } , - { 0x8086, 0x0532, "E8870SP", "Scalability Port 2" } , - { 0x8086, 0x0533, "E8870SP", "Scalability Port 3" } , - { 0x8086, 0x0534, "E8870SP", "Scalability Port 4" } , - { 0x8086, 0x0535, "E8870SP", "Scalability Port 5" } , - { 0x8086, 0x0536, "E8870SP", "Scalability Port Switch Global Registers" } , - { 0x8086, 0x0537, "E8870SP", "Interleave Configuration Registers" } , - { 0x8086, 0x0600, "01af8086", "Storage RAID Controller" } , - { 0x8086, 0x0960, "80960RP", "i960 RP Microprocessor/Bridge" } , - { 0x8086, 0x0962, "80960RM/RN", "i960RM/RN Microprocessor/Bridge" } , - { 0x8086, 0x0964, "80960RP", "i960 RP Microprocessor Bridge" } , - { 0x8086, 0x1000, "82542", "Gigabit Ethernet Controller" } , - { 0x8086, 0x1001, "2572", "10/100/1000 Ethernet Controller (Fiber)" } , - { 0x8086, 0x1002, "", "Pro 100 LAN+Modem 56 CardBus II" } , - { 0x8086, 0x1004, "82543GC", "Gigabit Ethernet Controller (Copper)" } , - { 0x8086, 0x1008, "82544EI/GC", "Gigabit Ethernet Controller (Copper)" } , - { 0x8086, 0x1009, "82544EI", "Gigabit Ethernet Controller (Fiber)" } , - { 0x8086, 0x100C, "82543EI/GC", "Gigabit Ethernet Controller (Copper)" } , - { 0x8086, 0x100D, "82544GC", "Gigabit Ethernet Controller (LOM)" } , - { 0x8086, 0x100E, "82540EM", "Gigabit Ethernet Controller" } , - { 0x8086, 0x100F, "82545EM", "Gigabit Ethernet Controller (copper)" } , - { 0x8086, 0x1010, "82546EB", "Dual Port Gigabit Ethernet Controller (Copper)" } , - { 0x8086, 0x1011, "82545EM", "Gigabit Ethernet Controller (Fiber)" } , - { 0x8086, 0x1012, "82546EB", "Dual Port Gigabit Ethernet Controller (Fiber)" } , - { 0x8086, 0x1013, "82541EI", "Gigabit Ethernet Controller (Copper)" } , - { 0x8086, 0x1014, "82541ER", "Gigabit Ethernet Controller" } , - { 0x8086, 0x1015, "82540EM", "Gigabit Ethernet Controller (LOM)" } , - { 0x8086, 0x1016, "82540EP", "Gigabit Ethernet Controller (LOM)" } , - { 0x8086, 0x1017, "82540EP", "Gigabit Ethernet Controller (LOM)" } , - { 0x8086, 0x1018, "82541EI", "PRO/1000 MT Mobile connection" } , - { 0x8086, 0x1019, "82547EI", "Gigabit Ethernet Controller (LOM)" } , - { 0x8086, 0x101A, "82547EI", "Gigabit Ethernet Controller (LOM)" } , - { 0x8086, 0x101d, "82546EB", "Dual Port Gigabit Ethernet Controller" } , - { 0x8086, 0x101E, "82540EP", "Gigabit Ethernet Controller (Mobile)" } , - { 0x8086, 0x1026, "82545ep", "Gigabit Ethernet Controller" } , - { 0x8086, 0x1027, "82545GM", "Gigabit Ethernet Controller (Fiber)" } , - { 0x8086, 0x1028, "82545GM", "Gigabit Ethernet Controller" } , - { 0x8086, 0x1029, "82559", "Fast Ethernet PCI/CardBus Controller" } , - { 0x8086, 0x1030, "825593", "PCI Networking device" } , - { 0x8086, 0x1031, "82801CAM", "PRO/100 VE Network Connection" } , - { 0x8086, 0x1032, "82801CAM", "PRO/100 VE Network Connection" } , - { 0x8086, 0x1033, "82801CAM", "PRO/100 VM Network Connection" } , - { 0x8086, 0x1034, "82801CAM", "PRO/100 VM Network Connection" } , - { 0x8086, 0x1035, "82562EH", "Phoneline Network Connection" } , - { 0x8086, 0x1036, "82562EH", "Phoneline Network Connection" } , - { 0x8086, 0x1037, "82801CAM", "LAN Controller" } , - { 0x8086, 0x1038, "82801CAM", "PRO/100 VM/KM Network Connection" } , - { 0x8086, 0x1039, "10011734", "LAN Controller with 82562ET/EZ PHY" } , - { 0x8086, 0x103A, "82801DB", "LAN Controller with 82562ET/EZ (CNR) PHY" } , - { 0x8086, 0x103B, "82801DB", "LAN Controller with 82562EM/EX PHY" } , - { 0x8086, 0x103C, "82801DB", "LAN Controller with 82562EM/EX (CNR) PHY" } , - { 0x8086, 0x103D, "82801DB", "PRO/100 VE Network Connection" } , - { 0x8086, 0x103E, "82801DB", "PRO/100 VM Network Connection" } , - { 0x8086, 0x1040, "536EP", "V.92 PCI (DSP) Data Fax Modem" } , - { 0x8086, 0x1042, "", "PRO/Wireless 2011 LAN PCI Card" } , - { 0x8086, 0x1043, "82801", "Intel(R) PRO/Wireless 2100 LAN Card Driver" } , - { 0x8086, 0x1048, "82597EX", "10 Gigabit Ethernet Controller" } , - { 0x8086, 0x1049, "82566MM NIC", "Gigabit Network Connection Interface Controller" } , - { 0x8086, 0x104A, "82566DM", "Gigabit Ethernet" } , - { 0x8086, 0x104B, "82566DC", "Gigabit Ethernet" } , - { 0x8086, 0x1050, "82801EB/ER", "PRO/100 VE Network Connection" } , - { 0x8086, 0x1051, "82801EB/ER", "PRO/100 VE Network Connection" } , - { 0x8086, 0x1052, "82801EB/ER", "PRO/100 VM Network Connection" } , - { 0x8086, 0x1053, "82801EB/ER", "PRO/100 VM Network Connection" } , - { 0x8086, 0x1054, "82801EB/ER", "PRO/100 VE Network Connection (mobile)" } , - { 0x8086, 0x1055, "82801EB/ER", "PRO/100 VM Network Connection (mobile)" } , - { 0x8086, 0x1059, "82551QM", "Fast Ethernet PCI/CardBus Controller" } , - { 0x8086, 0x105E, "n1e5132", "HP NC360T PCIe DP Gigabit Server Adapter" } , - { 0x8086, 0x1064, "Intel Pro VE", "82562EZ PLC" } , - { 0x8086, 0x1065, "82801FB/FR/FW/FRW", "LAN Controller" } , - { 0x8086, 0x1068, "82562", "1068h 82562ET/EZ/GT/GZ PRO/100 VE Ethernet Controller" } , - { 0x8086, 0x1075, "82547EI", "Gigabit Ethernet Controller" } , - { 0x8086, 0x1076, "82541EI", "Gigabit Ethernet Controller" } , - { 0x8086, 0x1077, "82547EI", "Gigabit Ethernet Controller (Mobile)" } , - { 0x8086, 0x1078, "82541ER", "Gigabit Ethernet Controller" } , - { 0x8086, 0x1079, "82546EB", "Dual Port Gigabit Ethernet Controller" } , - { 0x8086, 0x107A, "82546EB", "Dual Port Gigabit Ethernet Controller (Fiber)" } , - { 0x8086, 0x107B, "82546EB", "Dual Port Gigabit Ethernet Controller (Copper)" } , - { 0x8086, 0x107C, "82541PI", "Gigabit Ethernet Controller (Copper) rev 5" } , - { 0x8086, 0x1080, "0321CGEA04", "FA82537EP - Intel 537EP V.92 (PCI) modem" } , - { 0x8086, 0x108B, "PC82573V", "Intel network controller (PCIE Gigabit Ethernet)" } , - { 0x8086, 0x108c, "82573E", "Intel Corporation 82573E Gigabit Ethernet Controller (Copper)" } , - { 0x8086, 0x108E, "ICH7R", "Intel(R) Active Management Technology - KCS" } , - { 0x8086, 0x108F, "ICH7R", "Intel(R) Active Management Technology - SOL" } , - { 0x8086, 0x1092, "27DA", "PRO/100 VE Network Controller" } , - { 0x8086, 0x1094, "Onboard - Intel PRO 100/VE nic", "get PRO2KXP.exe from Intel" } , - { 0x8086, 0x1096, "Intel PRO/1000 EB", "Intel PRO/1000 EB" } , - { 0x8086, 0x109A, "82573L", "Intel PRO/1000 PL Network Adaptor" } , - { 0x8086, 0x10b9, "82572GI", "Intel PRO/1000 PT Desktop" } , - { 0x8086, 0x10BD, "82566DM", "Intel 82566DM Gigabit Ethernet Adapter" } , - { 0x8086, 0x10C0, "8082", "Intel(R) 82562V-2 10/100 Network Connection" } , - { 0x8086, 0x10DE, "83567LM-3 ", "Intel Gigabit network connection" } , - { 0x8086, 0x10F5, "82567LM", "Intel� 82567LM-2 Gigabit Network Connection" } , - { 0x8086, 0x1100, "82815/EP/P", "Host-Hub Interface Bridge / DRAM Ctrlr" } , - { 0x8086, 0x1101, "82815/EP/P", "AGP Bridge" } , - { 0x8086, 0x1102, "82815", "Internal Graphics Device" } , - { 0x8086, 0x1110, "82815", "Host-Hub Interface Bridge / DRAM Ctrlr" } , - { 0x8086, 0x1112, "82815", "Internal Graphics Device" } , - { 0x8086, 0x1120, "82815", "Host-Hub Interface Bridge / DRAM Ctrlr" } , - { 0x8086, 0x1121, "82815", "AGP Bridge" } , - { 0x8086, 0x1130, "82815/82815EM/EP", "Host-Hub Interface Bridge / DRAM Ctrlr" } , - { 0x8086, 0x1131, "82815/82815EM/EP", "AGP Bridge" } , - { 0x8086, 0x1132, "65416", "Internal Graphics Device [810/815 chipset AGP]" } , - { 0x8086, 0x1161, "82806AA", "I/O APIC Device" } , - { 0x8086, 0x1162, "BECC", "XScale 80200 Companion Chip (FPGA)" } , - { 0x8086, 0x1179, "82546EB", "Dual Port Gigabit Ethernet Controller" } , - { 0x8086, 0x1200, "IXP1200", "Network Processor" } , - { 0x8086, 0x1209, "8255xER/IT", "Fast Ethernet Controller" } , - { 0x8086, 0x1221, "82092AA", "PCMCIA Bridge" } , - { 0x8086, 0x1222, "82092AA", "IDE Ctrlr" } , - { 0x8086, 0x1223, "SAA 7116 H", "Video Controller" } , - { 0x8086, 0x1225, "82452KX/GX", "Orion Extended Express CPU to PCI Bridge" } , - { 0x8086, 0x1226, "82596", "EtherExpress PRO/10" } , - { 0x8086, 0x1227, "82801db ich4", "LAN Controller with 82562EM/EX PHY PCI" } , - { 0x8086, 0x1228, "EE PRO/100 Smart", "Intelligent 10/100 Fast Ethernet Adapter" } , - { 0x8086, 0x1229, "82557/8/9/0/1", "Fast Ethernet LAN Controller" } , - { 0x8086, 0x122D, "82437FX", "System Controller (TSC)" } , - { 0x8086, 0x122E, "82371FB", "PCI to ISA Bridge (Triton)" } , - { 0x8086, 0x1230, "FW82371AB", "IDE Interface (Triton)" } , - { 0x8086, 0x1231, "16345", "DSVD Modem" } , - { 0x8086, 0x1234, "82371MX", "PCI to ISA Bridge" } , - { 0x8086, 0x1235, "82439TX", "Mobile System Controller (MTSC)" } , - { 0x8086, 0x1237, "82440LX/EX", "PCI & Memory" } , - { 0x8086, 0x1239, "82371FB", "IDE Interface (Triton)" } , - { 0x8086, 0x123B, "82380PB", "PCI to PCI Docking Bridge" } , - { 0x8086, 0x123C, "82380AB", "Mobile PCI-to-ISA Bridge (MISA)" } , - { 0x8086, 0x123D, "683053", "Programmable Interrupt Device" } , - { 0x8086, 0x123E, "82466GX", "Integrated Hot-Plug Controller (IHPC)" } , - { 0x8086, 0x123F, "82466GX", "Integrated Hot-Plug Controller (IHPC)" } , - { 0x8086, 0x1240, "82752", "AGP Graphics Accelerator" } , - { 0x8086, 0x124B, "4227", "Mobile PCI-to-PCI Bridge (MPCI2)" } , - { 0x8086, 0x1250, "82430HX", "System Controller (TXC)" } , - { 0x8086, 0x12D8, "92XX", "SIGMATEL STAC 92XX C-Major HD Audio" } , - { 0x8086, 0x1360, "82806AA", "Hub Interface to PCI Bridge" } , - { 0x8086, 0x1361, "82806AA", "Advanced Interrupt Controller" } , - { 0x8086, 0x1460, "82870P2", "Hub Interface-to-PCI Bridge" } , - { 0x8086, 0x1461, "14611014", "I/OxAPIC Interrupt Controller" } , - { 0x8086, 0x1462, "82870P2", "Hot Plug Controller" } , - { 0x8086, 0x1960, "80960RP", "i960RP Microprocessor" } , - { 0x8086, 0x1962, "???", "Promise SuperTrak SX6000 IDE RAID Controller" } , - { 0x8086, 0x1A12, "???", "Eicon DIVA Server Voice PRI 2.0 (PCI)" } , - { 0x8086, 0x1A13, "???", "Eicon DIVA Server Voice PRI 2.0 (PCI)" } , - { 0x8086, 0x1A20, "82840", "" } , - { 0x8086, 0x1A21, "82840", "Host-Hub Interface A Bridge / DRAM Ctrlr" } , - { 0x8086, 0x1A22, "82840", "Host to I/O Hub Bridge (Quad PCI)" } , - { 0x8086, 0x1A23, "82840", "AGP Bridge" } , - { 0x8086, 0x1A24, "82840", "Hub Interface B Bridge" } , - { 0x8086, 0x1A30, "82845G[GL/GV/GE/PE]", "Host-Hub Interface Bridge" } , - { 0x8086, 0x1A31, "82845[MP/MZ]", "AGP Bridge" } , - { 0x8086, 0x1A38, "5000P", "5000 Series Chipset DMA Engine" } , - { 0x8086, 0x2125, "82801AA", "AC97 Audio Controller. website to download - http://www.intel.com/design/chipsets/manuals/29802801.p" } , - { 0x8086, 0x2410, "82801AA", "LPC Interface" } , - { 0x8086, 0x2411, "82801AA", "IDE Controller (UltraATA/66)" } , - { 0x8086, 0x2412, "82801AA", "USB Controller" } , - { 0x8086, 0x2413, "82801AA", "SMBus Controller" } , - { 0x8086, 0x2415, "Intel 82801DBM SM/BUS Controller 24C3", "Aureal (AD1881 SOUNDMAX) Placa Mãe Asaki P3-141" } , - { 0x8086, 0x2416, "82801fb", "AC'97 Modem Controller" } , - { 0x8086, 0x2418, "82801AA", "Hub Interface-to-PCI Bridge" } , - { 0x8086, 0x2420, "82801AB", "LPC Interface" } , - { 0x8086, 0x2421, "82801AB", "IDE Controller (UltraATA/33)" } , - { 0x8086, 0x2422, "82801AB", "USB Controller" } , - { 0x8086, 0x2423, "82801AB", "SMBus Controller" } , - { 0x8086, 0x2425, "82845G", "Video controler" } , - { 0x8086, 0x2426, "82801AB", "AC97 Modem Controller" } , - { 0x8086, 0x2428, "82801AB", "Hub Interface-to-PCI Bridge" } , - { 0x8086, 0x2431, "82810", "pci bus" } , - { 0x8086, 0x2440, "82801BA", "LPC Interface Bridge, ICH2" } , - { 0x8086, 0x2441, "82801BA", "IDE Controller (UltraATA/66)" } , - { 0x8086, 0x2442, "82801BA/BAM", "USB Controller, USB-A" } , - { 0x8086, 0x2443, "0055110A", "SMBus Controller" } , - { 0x8086, 0x2444, "82801BA/BAM", "USB Controller, USB-B" } , - { 0x8086, 0x2445, "Intel i945G/GZ", "AC97 Audio Controller" } , - { 0x8086, 0x2446, "82801BA/BAM", "AC97 Modem Controller" } , - { 0x8086, 0x2448, "82801BAM/CAM/DBM", "Hub Interface to PCI Bridge" } , - { 0x8086, 0x2449, "82559ER", "82559ER Integrated 10Base-T/100Base-TX Ethernet Controller" } , - { 0x8086, 0x244A, "82801BAM", "IDE Controller" } , - { 0x8086, 0x244B, "82801BA", "IDE Controller" } , - { 0x8086, 0x244C, "82801BAM", "LPC Interface Bridge" } , - { 0x8086, 0x244E, "82801DB", "Hub Interface to PCI Bridge" } , - { 0x8086, 0x2450, "82801E", "LPC Interface Bridge" } , - { 0x8086, 0x2452, "82801E", "USB Controller" } , - { 0x8086, 0x2453, "82801E", "SMBus Controller" } , - { 0x8086, 0x2459, "82801E", "LAN0 Controller" } , - { 0x8086, 0x245B, "82801E", "IDE Controller" } , - { 0x8086, 0x245D, "82801E", "LAN1 Controller" } , - { 0x8086, 0x245E, "82801E", "Hub Interface to PCI Bridge" } , - { 0x8086, 0x2480, "82801CA", "LPC Interface Bridge" } , - { 0x8086, 0x2481, "82801CA", "IDE Controller (UltraATA/66)" } , - { 0x8086, 0x2482, "82801CA/CAM", "USB Controller" } , - { 0x8086, 0x2483, "82801CA/CAM", "SMBus Controller" } , - { 0x8086, 0x2484, "82801CA/CAM", "USB Controller" } , - { 0x8086, 0x2485, "82801CA/CAM", "AC97 Audio Controller" } , - { 0x8086, 0x2486, "82801CA/CAM", "AC 97 Modem Controller" } , - { 0x8086, 0x2487, "82801CA/CAM", "USB Controller" } , - { 0x8086, 0x248A, "82801CAM", "UltraATA IDE Controller" } , - { 0x8086, 0x248B, "82801CA", "UltraATA/100 IDE Controller" } , - { 0x8086, 0x248C, "82801CAM", "LPC Interface or ISA bridge: see Notes" } , - { 0x8086, 0x248D, "82801??", "USB 2.0 EHCI Contoroller" } , - { 0x8086, 0x24C0, "82801DB/DBL", "LPC Interface Bridge" } , - { 0x8086, 0x24C2, "82801DB/DBL/DBM", "USB UHCI Controller #1" } , - { 0x8086, 0x24C3, "82801DB/DBL/DBM", "modem" } , - { 0x8086, 0x24C4, "82801DB/DBL/DBM", "USB UHCI Controller" } , - { 0x8086, 0x24C5, "Realtek ALC268 & ALC650", "RealTek" } , - { 0x8086, 0x24C5, "Subsys_01601028", "Soundmax Integrated Digital Audio" } , - { 0x8086, 0x24C6, "82801", "AC97 Modem Controller" } , - { 0x8086, 0x24C7, "82801DB/DBL/DBM", "USB UHCI Controller #3" } , - { 0x8086, 0x24CA, "82801DBM", "IDE Controller (UltraATA/100)" } , - { 0x8086, 0x24CB, "82801DB/DBL", "IDE Controller (UltraATA/100)" } , - { 0x8086, 0x24CC, "82801DBM", "LPC Interface Bridge" } , - { 0x8086, 0x24CD, "82801DB/DBL/DBM", "USB EHCI Controller" } , - { 0x8086, 0x24D0, "82801EB/ER", "LPC Interface Bridge" } , - { 0x8086, 0x24D1, "82801EB/ER", "SATA Controller" } , - { 0x8086, 0x24D2, "82801EB/ER", "USB UHCI Controller #1" } , - { 0x8086, 0x24D3, "82801EB/ER", "SMBus Controller" } , - { 0x8086, 0x24D4, "82801EB/ER", "USB UHCI Controller #2" } , - { 0x8086, 0x24D5, "815B104D", "multimedia audio device (codec AC97) SoundMAX or VIA" } , - { 0x8086, 0x24D6, "82801EB/ER", "AC'97 Modem Controller" } , - { 0x8086, 0x24D7, "82801EB/ER", "USB UHCI Controller #3" } , - { 0x8086, 0x24DB, "82801EB/ER", "EIDE Controller" } , - { 0x8086, 0x24DC, "82801EB", "LPC Interface Controller" } , - { 0x8086, 0x24DD, "82801EB/ER", "USB EHCI Controller" } , - { 0x8086, 0x24DE, "82801EB/ER", "USB UHCI Controller #4" } , - { 0x8086, 0x24DF, "82801ER", "SATA Controller (RAID)" } , - { 0x8086, 0x2500, "82820", "Host-Hub Interface Bridge / DRAM Ctrlr" } , - { 0x8086, 0x2501, "82820", "Host Bridge (MCH)" } , - { 0x8086, 0x2502, "82820", "" } , - { 0x8086, 0x2503, "82820", "" } , - { 0x8086, 0x2504, "82820", "" } , - { 0x8086, 0x250B, "82820", "Host Bridge (MCH)" } , - { 0x8086, 0x250F, "82820", "AGP Bridge" } , - { 0x8086, 0x2520, "82805AA", "Memory Translator Hub (MTH)" } , - { 0x8086, 0x2521, "82804AA", "Memory Repeater Hub for SDRAM (MRH-S)" } , - { 0x8086, 0x2530, "82850/E", "Host-Hub Interface Bridge(A2 step)" } , - { 0x8086, 0x2531, "82860", "Host-Hub Interface_A Bridge (DP mode)" } , - { 0x8086, 0x2532, "82850/850E/860", "AGP Bridge" } , - { 0x8086, 0x2533, "82860", "Hub Interface_B Bridge" } , - { 0x8086, 0x2534, "82860", "Hub Interface_C Bridge" } , - { 0x8086, 0x2535, "82860", "PCI Bridge" } , - { 0x8086, 0x2536, "82860", "PCI Bridge" } , - { 0x8086, 0x2539, "82860", "(Quad Processor mode)" } , - { 0x8086, 0x2540, "E7500", "Host-HI Bridge & DRAM Controller" } , - { 0x8086, 0x2541, "E7500/E7501", "DRAM Controller Error Reporting" } , - { 0x8086, 0x2543, "E7500/E7501", "HI_B Virtual PCI-to-PCI Bridge" } , - { 0x8086, 0x2544, "E7500/E7501", "HI_B PCI-to-PCI Bridge Error Reporting" } , - { 0x8086, 0x2545, "E7500/E7501", "HI_C Virtual PCI-to-PCI Bridge" } , - { 0x8086, 0x2546, "E7500/E7501", "HI_C PCI-to-PCI Bridge Error Reporting" } , - { 0x8086, 0x2547, "E7500/E7501", "HI_D Virtual PCI-to-PCI Bridge" } , - { 0x8086, 0x2548, "E7500/E7501", "HI_D PCI-to-PCI Bridge Error Reporting" } , - { 0x8086, 0x254C, "E7501", "Host Controller" } , - { 0x8086, 0x2550, "E7505", "Host Controller" } , - { 0x8086, 0x2551, "25511014", "Host RAS Controller" } , - { 0x8086, 0x2552, "E7205/E7505", "PCI-to-AGP Bridge" } , - { 0x8086, 0x2553, "E7505", "Hub Interface_B PCI-to-PCI Bridge" } , - { 0x8086, 0x2554, "E7505", "Hub I/F_B PCI-to-PCI Bridge Error Report" } , - { 0x8086, 0x255d, "E7205", "Host Controller" } , - { 0x8086, 0x2560, "82845G/GL/GV/GE/PE", "DRAM Controller / Host-Hub I/F Bridge" } , - { 0x8086, 0x2561, "82845G/GL/GV/GE/PE", "Host-to-AGP Bridge" } , - { 0x8086, 0x2562, "82845G", "Integrated Graphics Device" } , - { 0x8086, 0x2570, "82865G/PE/P, 82848P", "DRAM Controller / Host-Hub Interface" } , - { 0x8086, 0x2571, "82865G/PE/P, 82848P", "PCI-to-AGP Bridge" } , - { 0x8086, 0x2572, "82865G", "Integrated Graphics Device" } , - { 0x8086, 0x2573, "82865G/PE/P, 82848P", "PCI-to-CSA Bridge" } , - { 0x8086, 0x2576, "82865G/PE/P, 82848P", "Overflow Configuration" } , - { 0x8086, 0x2578, "82875P/E7210", "DRAM Controller / Host-Hub Interface" } , - { 0x8086, 0x2579, "82875P", "PCI-to-AGP Bridge" } , - { 0x8086, 0x257A, "", "" } , - { 0x8086, 0x257B, "82875P/E7210", "PCI to CSA Bridge" } , - { 0x8086, 0x257E, "82875P/E7210", "Overflow Configuration" } , - { 0x8086, 0x2580, "915G/P/GV", "Host Bridge / DRAM Controller" } , - { 0x8086, 0x2581, "915G/P/GV, 925X/XE?", "Host-PCI Express Bridge" } , - { 0x8086, 0x2582, "0181102", "82915g/gv/910gl Express Chipset Family" } , - { 0x8086, 0x2584, "82925X/XE", "Host Bridge / DRAM Controller" } , - { 0x8086, 0x2588, "E7221", "Host Bridge/DRAM Controller" } , - { 0x8086, 0x2589, "E7221", "PCI Express Bridge" } , - { 0x8086, 0x258A, "E7221", "Internal Graphics" } , - { 0x8086, 0x2590, "915GM", "Mobile Intel(R) 915GM/PM/GMS/910GML Express Processor to DRAM Controller" } , - { 0x8086, 0x2592, "Intel 82852/82855 Graphic controller family", "you can be found in www.intelcom" } , - { 0x8086, 0x25A1, "6300ESB", "LPC Interface Bridge" } , - { 0x8086, 0x25A2, "6300ESB", "IDE Controller" } , - { 0x8086, 0x25A3, "6300ESB", "SATA Controller" } , - { 0x8086, 0x25A4, "6300ESB", "SMBus Controller" } , - { 0x8086, 0x25A6, "6300ESB", "AC'97 Audio Controller" } , - { 0x8086, 0x25A7, "6300ESB", "AC'97 Modem Controller" } , - { 0x8086, 0x25A9, "6300ESB", "USB 1.1 UHCI Controller #1" } , - { 0x8086, 0x25AA, "6300ESB", "USB 1.1 UHCI Controller #2" } , - { 0x8086, 0x25AB, "6300ESB", "Watchdog Timer" } , - { 0x8086, 0x25AC, "6300ESB", "APIC1" } , - { 0x8086, 0x25AD, "6300ESB", "USB 2.0 EHCI Controller" } , - { 0x8086, 0x25AE, "6300ESB", "Hub Interface to PCI-X Bridge" } , - { 0x8086, 0x25B0, "6300ESB", "Serial ATA Controller (RAID mode)" } , - { 0x8086, 0x2600, "E8500", "Hub Interface 1.5" } , - { 0x8086, 0x2601, "E8500", "PCI Express Port D" } , - { 0x8086, 0x2602, "E8500", "PCI Express Port C0" } , - { 0x8086, 0x2603, "E8500", "PCI Express Port C1" } , - { 0x8086, 0x2604, "E8500", "PCI Express Port B0" } , - { 0x8086, 0x2605, "E8500", "PCI Express Port B1" } , - { 0x8086, 0x2606, "E8500", "PCI Express Port A0" } , - { 0x8086, 0x2607, "E8500", "PCI Express Port A1" } , - { 0x8086, 0x2640, "82801FB/FR", "LPC Interface Bridge" } , - { 0x8086, 0x2641, "82801FBM", "LPC Interface Bridge (ICH6-M)" } , - { 0x8086, 0x2651, "82801Fb", "SATA Controller" } , - { 0x8086, 0x2652, "82801FR", "SATA RAID Controller" } , - { 0x8086, 0x2652, "82801FR/FRW", "SATA Controller" } , - { 0x8086, 0x2652, "82801FR/FRW", "SATA Raid Controller" } , - { 0x8086, 0x2652, "82801FR/FRW", "AHCI Controller" } , - { 0x8086, 0x2653, "82801FBM", "SATA AHCI Controller" } , - { 0x8086, 0x2653, "82801FBM", "SATA IDE Controller" } , - { 0x8086, 0x2653, "82801FBM", "AHCI Controller" } , - { 0x8086, 0x2658, "82801FB/FR/FW/FRW", "USB UHCI Controller #1" } , - { 0x8086, 0x2659, "82801FB/FR/FW/FRW", "USB UHCI Controller #2" } , - { 0x8086, 0x265A, "82801FB/FR/FW/FRW", "USB UHCI Controller #3" } , - { 0x8086, 0x265B, "82801FB/FR/FW/FRW", "USB UHCI Controller #4" } , - { 0x8086, 0x265C, "82801FB/FR/FW/FRW", "USB 2.0 EHCI Controller" } , - { 0x8086, 0x2660, "82801FB/FR/FW/FRW", "PCI Express Port 1" } , - { 0x8086, 0x2662, "82801FB/FR/FW/FRW", "PCI Express Port 2" } , - { 0x8086, 0x2664, "82801FB", "PCI Express Port 3" } , - { 0x8086, 0x2666, "82801FB/FR/FW/FRW", "PCI Express Port 4" } , - { 0x8086, 0x2668, "11583659", "82801FB (ICH6) High Definition Audio Controller" } , - { 0x8086, 0x2669, "2028026", "jkn " } , - { 0x8086, 0x266A, "82801BA/CA", "SMBus Controller" } , - { 0x8086, 0x266C, "82801FB/FR/FW/FRW", "LAN Controller" } , - { 0x8086, 0x266D, "82801I", "INTEL 82801FB ICH6-AC'97 AUDIO CONTROLLER" } , - { 0x8086, 0x266E, "Intel Corporation 82830M/MG SDRAM Controller / Ho", "AC '97 Audio Controller/ Sigmatel (SoundMAX Integrated Digital Audio)" } , - { 0x8086, 0x266F, "82801FB/FBM/FW/FR/FRW", "PATA100 Controller - 266F" } , - { 0x8086, 0x2681, "62089A2", "LSI LOGIC, 62089A2, LSISAS1068 B0, T 0620, WE 119200.1" } , - { 0x8086, 0x2770, "82945G/GZ/P/PL", "Host Bridge/DRAM Controller" } , - { 0x8086, 0x2771, "82945G/GZ/P/PL", "Host to PCI Express Bridge" } , - { 0x8086, 0x2772, "82945G/GZ", "Integrated Graphics Device" } , - { 0x8086, 0x277C, "82975X", "Intel 975X Express Chipset" } , - { 0x8086, 0x2780, "82915G", "Graphics device" } , - { 0x8086, 0x2782, "82915G", "Graphics device: 82915G/GV/910GL Express Chipset Family" } , - { 0x8086, 0x2792, "Mobile 82915GLx/x/x", "Mobile Intel(R) 915GM/GMS/, 910GML Express Chipset Family" } , - { 0x8086, 0x27A0, "874079", "i945GM Express Chipset" } , - { 0x8086, 0x27A2, "82940GML", "Mobile Intel(R) 945 Express Chipset Family" } , - { 0x8086, 0x27A6, "945GM", "Intel 945GM/950" } , - { 0x8086, 0x27B8, "945GL", "Intel 82801GB/GR (ICH7 Family) LPC Interface Controller - 27B8" } , - { 0x8086, 0x27c0, "82801GB/GR/GH", "82801 GB Serial ATA Storage Controllers" } , - { 0x8086, 0x27C1, "82801GB/GR/GH", "AHCI Controller" } , - { 0x8086, 0x27c3, "82801GR/GH", "Raid Controller" } , - { 0x8086, 0x27c4, "82801GBM/GHM", "SATA IDE Controller" } , - { 0x8086, 0x27C5, "82801GBM/GHM", "AHCI Controller" } , - { 0x8086, 0x27C6, "82801GHM", "Raid Controller" } , - { 0x8086, 0x27c8, "-", "USB UHCI Controller" } , - { 0x8086, 0x27c9, "-", "USB UHCI Controller" } , - { 0x8086, 0x27CA, "-", "USB UHCI Controller" } , - { 0x8086, 0x27CB, "", "USB UHCI Controller" } , - { 0x8086, 0x27d8, "26331019", "INTEL" } , - { 0x8086, 0x27D8, "945GME", "Intel core2duo" } , - { 0x8086, 0x27d8, "", "Microsoft UAA Bus HD Audio" } , - { 0x8086, 0x27DA, "1B761019", "SMBus Controller XP driver" } , - { 0x8086, 0x27DC, "Intel PRO/100", "Intel(R) PRO/100 VE Network Connection" } , - { 0x8086, 0x27df, "82801GB/GBM/GR/GH/GHM", "PATA100" } , - { 0x8086, 0x2820, "82801HB/HR/HH/HO", "SATA IDE Controller:4 port" } , - { 0x8086, 0x2821, "82821HR/HH/HO", "AHCI Controller" } , - { 0x8086, 0x2822, "82801HR/HH/HO&82801IR/IH/IO(AIE=0)/ICH10R", "Raid Controller" } , - { 0x8086, 0x2824, "82801HB", "ICH8 AHCI Controller" } , - { 0x8086, 0x2825, "82801HB/HR/HH/HO", "SATA IDE Controller:2 port" } , - { 0x8086, 0x2828, "82801HBM/HEM", "SATA IDE Controller" } , - { 0x8086, 0x2829, "82801HBM/HEM", "AHCI Controller" } , - { 0x8086, 0x282A, "ICH8ME/9ME", "Raid Controller" } , - { 0x8086, 0x283A, "81EC1043 (?)", "ICH8 Enhanced USB2 Enhanced Host Controller" } , - { 0x8086, 0x284B, "82801H", "Intel audio controller embedded with the 82801H chipset ( ICH8 chipset )" } , - { 0x8086, 0x2850, "82801HBM/HEM", "PATA Controller" } , - { 0x8086, 0x2920, "82801(IB)/IR/IH/IO", "SATA IDE Controller:4 port" } , - { 0x8086, 0x2921, "82801IR/IH/IO", "SATA IDE Controller:2 port1" } , - { 0x8086, 0x2922, "82801IR/IH/IO", "AHCI Controller" } , - { 0x8086, 0x2923, "82801IB", "ICH9 AHCI Controller" } , - { 0x8086, 0x2925, "82801IR/IH/IO(AIE=1)", "Raid Controller" } , - { 0x8086, 0x2926, "82801IR/IH/IO", "SATA IDE Controller:2 port2" } , - { 0x8086, 0x2928, "?(ICH9M Family)", "SATA IDE Controller:2port1" } , - { 0x8086, 0x2929, "ICH9M/ME", "ICH9M/ME AHCI Controller" } , - { 0x8086, 0x292D, "?(ICH9M Family)", "SATA IDE Controller:2port2" } , - { 0x8086, 0x292E, "?(ICH9M Family)", "SATA IDE Controller:1port2" } , - { 0x8086, 0x2930, "?", "ICH9 Family SMBus Controller" } , - { 0x8086, 0x293E, "486486", "82801IB/IR/IH (ICH9 Family) HD Audio Controller" } , - { 0x8086, 0x294C, "82566DC-2", "Intel(R) 82566DC-2 Gigabit Network Connection" } , - { 0x8086, 0x2972, "82946GZ ", "Onboard Video Device for 82946GZ chips" } , - { 0x8086, 0x2987, "Q965/Q963", "Intel PCI Serial Port" } , - { 0x8086, 0x2992, "", "Intel(R) Express Chipset video" } , - { 0x8086, 0x2993, "", "Intel(R) Express Chipset (Dell Version)" } , - { 0x8086, 0x2994, "0x8086", "Intel(R) Management Engine Interface" } , - { 0x8086, 0x2997, "Q965/Q963", "Intel PCI Serial Port" } , - { 0x8086, 0x29a0, "?(82P965)", "Intel P965/G965 Processor to I/O Controller" } , - { 0x8086, 0x29a1, "?(82Q965, 82G965, 82P965)", "Intel P965/G965 PCI Express Root Port" } , - { 0x8086, 0x29A4, "n/a", "The Intel Management Engine provides thermal management for Intel Desktop Boards." } , - { 0x8086, 0x29B2, "Q35", "Intel(R) Q35 Express Chipset Family" } , - { 0x8086, 0x29B3, "Q35", "Intel" } , - { 0x8086, 0x29B4, "Q35-Chipset", "Intel(R) Management Engine Interface (HECI)" } , - { 0x8086, 0x29B7, "Q35-Chipset", "Serial Over LAN" } , - { 0x8086, 0x29C2, "82G33", "Intel(R) G33 chipset GMA3100 video" } , - { 0x8086, 0x29D4, "82801", "Intel Management Interface" } , - { 0x8086, 0x2A02, "02091028", "Intel GM965, Intel X3100" } , - { 0x8086, 0x2A03, "82Q965", "Intel GM" } , - { 0x8086, 0x2A04, "Q965/Q96", "Intel PCI communication controller" } , - { 0x8086, 0x2A07, "Q965/Q963", "Intel PCI Serial Port" } , - { 0x8086, 0x2A08, "Q965 Chipset", "Intel(R) Extended Thermal Model MCH" } , - { 0x8086, 0x2A44, "unknown", "unknown" } , - { 0x8086, 0x2a47, "20EC17AA", "Active Management Technology - SOL" } , - { 0x8086, 0x2f00, "815B104D", "multimedia audio device (codec AC97) SoundMAX or VIA" } , - { 0x8086, 0x3092, "SRCU32", "I2O 1.5 RAID Controller" } , - { 0x8086, 0x3200, "31244", "PCI-X to Serial ATA Controller" } , - { 0x8086, 0x3340, "82855PM", "Host-Hub Interface Bridge" } , - { 0x8086, 0x3341, "82855PM", "AGP Bridge" } , - { 0x8086, 0x3342, "82855PM", "Power Management" } , - { 0x8086, 0x348D, "82541EI", "Gigabit Ethernet Controller" } , - { 0x8086, 0x3575, "82830[MP]", "Host-Hub I/F Bridge / SDRAM Controller" } , - { 0x8086, 0x3576, "82830M/MP", "Host-AGP Bridge" } , - { 0x8086, 0x3577, "82830M/MG", "Integrated Graphics Device" } , - { 0x8086, 0x3578, "82830[MP]", "CPU to I/O Bridge" } , - { 0x8086, 0x3579, "82835", "SDRAM Controller / Host-hub Interface" } , - { 0x8086, 0x357B, "82835", "Integrated Graphics Device" } , - { 0x8086, 0x3580, "852GM/GMV", "Host-Hub Interface Bridge" } , - { 0x8086, 0x3581, "82852GME/PM", "Virtual PCI to AGP Bridge" } , - { 0x8086, 0x3582, "852GM/GMV", "Integrated Graphics Device" } , - { 0x8086, 0x3584, "852GM/GMV", "System Memory Controller" } , - { 0x8086, 0x3585, "852GM", "Configuration Process" } , - { 0x8086, 0x3590, "E7520", "Memory Controller Hub" } , - { 0x8086, 0x3591, "E7520", "Memory Controller Hub" } , - { 0x8086, 0x3592, "E7320", "Memory Controller Hub" } , - { 0x8086, 0x3593, "E7525", "MCH Error Reporting Registers" } , - { 0x8086, 0x3594, "E7520", "DMA Controller Registers" } , - { 0x8086, 0x3595, "E7525", "PCI Express Port A" } , - { 0x8086, 0x3596, "E7525", "PCI Express Port B" } , - { 0x8086, 0x3597, "E7525", "PCI Express Port B" } , - { 0x8086, 0x3598, "E7520", "PCI Express Port B1" } , - { 0x8086, 0x3599, "E7520", "PCI Express Port C" } , - { 0x8086, 0x359A, "E7520", "PCI Express Port C1" } , - { 0x8086, 0x359B, "E7525", "Extended Configuration Registers" } , - { 0x8086, 0x359E, "E7525", "MCH Control Registers" } , - { 0x8086, 0x360B, "", "who knows&erka" } , - { 0x8086, 0x3A00, "ICH10 Family", "SATA2(4Port1)" } , - { 0x8086, 0x3A02, "ICH10R", "ICH10R AHCI" } , - { 0x8086, 0x3A03, "ICH10", "ICH10 AHCI" } , - { 0x8086, 0x3A06, "ICH10 Family", "SATA2(2Port1)" } , - { 0x8086, 0x3A20, "ICH10 Family", " SATA2(4Port2)" } , - { 0x8086, 0x3A22, "ICH10R", "AHCI Controller" } , - { 0x8086, 0x3A23, "ICH10", "ICH10 AHCI" } , - { 0x8086, 0x3A26, "ICH10 Family", "SATA2(2Port2)" } , - { 0x8086, 0x3A30, "50011458", "SMB controller " } , - { 0x8086, 0x4000, "Creatix", "V.90 HaM Modem" } , - { 0x8086, 0x4220, "MPCI3B", " driverIntel PRO/Wireless 2200BG" } , - { 0x8086, 0x4222, "10418086", "Intel 3945ABG Wireless LAN controller" } , - { 0x8086, 0x4223, "2915ABG", "Intel (R) PRO/Wireless 2200BG Network Connection, (R) PRO/Wireless 2915ABG Network Connection" } , - { 0x8086, 0x4224, "Intel Pro Wireless 2915ABG", "802.11a/b/g WLan adapter" } , - { 0x8086, 0x4227, "3945ABG", "Intel(R) PRO/Wireless 3945ABG" } , - { 0x8086, 0x4229, "Intel 4965AGN", "Intel Wireless WiFi Link 4965AGN(supporting 802.11a/b/g/Draft-N)" } , - { 0x8086, 0x422D, "Intel 4965AGN", "Intel Wireless WiFi Link 4965AGN" } , - { 0x8086, 0x4230, "Intel 4965AGN", "Intel Wireless WiFi Link 4965AGN" } , - { 0x8086, 0x4232, "Intel WiFi Link 5100", "Carte Intel WiFi Link 5100 AGN" } , - { 0x8086, 0x4233, "Intel 4965AGN", "Intel Wireless WiFi Link 4965AGN" } , - { 0x8086, 0x4235, "5300AGN", "Intel WiFi Link 5300 AGN" } , - { 0x8086, 0x4237, "5100 AGN", "Intel (R) WiFi Link 5100 AGN" } , - { 0x8086, 0x444E, "TurboMemory", "Intel TurboMemory" } , - { 0x8086, 0x5001, "PRO/DSL 2100", "Modem - PPP" } , - { 0x8086, 0x5005, "PRO/DSL 2200", "Modem - PPPoA" } , - { 0x8086, 0x5029, "?(EP80579)", "AHCI Controller" } , - { 0x8086, 0x5200, "NH82801GR", "PCI to PCI Bridge" } , - { 0x8086, 0x5201, "", "Network Controller" } , - { 0x8086, 0x5309, "80303", "I/O Processor Address Translation Unit" } , - { 0x8086, 0x530D, "80312", "I/O Companion Unit Address Translation" } , - { 0x8086, 0x6960, "", "EHCI 960 emulator" } , - { 0x8086, 0x7000, "82371SB", "PIIX3 PCI-to-ISA Bridge (Triton II)" } , - { 0x8086, 0x7010, "82371SB", "PIIX3 IDE Interface (Triton II)" } , - { 0x8086, 0x7020, "82371SB", "PIIX3 USB Host Controller (Triton II)" } , - { 0x8086, 0x7030, "82437VX", "System Controller" } , - { 0x8086, 0x7051, "PB 642365-003", "Intel Business Video Conferencing Card" } , - { 0x8086, 0x7100, "82439TX", "System Controller (MTXC), part of 430TX chipset" } , - { 0x8086, 0x7110, "82371AB/EB/MB", "PIIX4/4E/4M ISBridgeA " } , - { 0x8086, 0x7111, "82371AB/EB/MB", "PIIX4/4E/4M IDE Controller" } , - { 0x8086, 0x7112, "82371AB/EB/MB", "PIIX4/4E/4M USB Interface" } , - { 0x8086, 0x7113, "82371AB/EB/MB", "PIIX4/4E/4M Power Management Controller" } , - { 0x8086, 0x7120, "82810", "Host-Hub Interface Bridge / DRAM Ctrlr" } , - { 0x8086, 0x7121, "82810", "Graphics Controller" } , - { 0x8086, 0x7122, "82810-DC100", "Host-Hub Interface Bridge / DRAM Ctrlr" } , - { 0x8086, 0x7123, "82810-DC100", "Intel� 82810 Graphics Controller" } , - { 0x8086, 0x7124, "82810E", "Host-Hub Interface Bridge / DRAM Ctrlr" } , - { 0x8086, 0x7125, "82810E", "Intel Direct AGP 810 Chipset" } , - { 0x8086, 0x7126, "82810-DC133", "Host Bridge and Memory Controller Hub" } , - { 0x8086, 0x7127, "82810-DC133", "Graphics Device (FSB 133 MHz)" } , - { 0x8086, 0x7128, "82810-M DC-100", "Host Bridge and Memory Controller Hub" } , - { 0x8086, 0x712A, "82810-M DC-133", "Host Bridge and Memory Controller Hub" } , - { 0x8086, 0x7180, "rmc", "Host/PCI bridge in 440LX/EX AGP chipset" } , - { 0x8086, 0x7181, "82443 ex/lx", "AGP device in 440LX/EX AGP chipset" } , - { 0x8086, 0x7182, "440LX/EX", "intel" } , - { 0x8086, 0x7190, "82443BX/ZX", "440BX/ZX AGPset Host Bridge" } , - { 0x8086, 0x7191, "82443BX/ZX", "440BX/ZX AGPset PCI-to-PCI bridge" } , - { 0x8086, 0x7192, "82443BX/ZX", "440BX/ZX chipset Host-to-PCI Bridge" } , - { 0x8086, 0x7194, "82443MX", "AC'97 Audio device" } , - { 0x8086, 0x7195, "82443MX", "AC97 Audio Controller" } , - { 0x8086, 0x7196, "82440 - 443MX", "AC97 Modem Controller (Winmodem)" } , - { 0x8086, 0x7198, "82443MX", "PCI to ISA Bridge" } , - { 0x8086, 0x7199, "82443MX", "EIDE Controller" } , - { 0x8086, 0x719A, "82443MX", "USB Universal Host Controller" } , - { 0x8086, 0x719B, "82443MX", "Power Management Controller" } , - { 0x8086, 0x71A0, "82443GX", "Host-to-PCI Bridge" } , - { 0x8086, 0x71A1, "intel 82801 IB ICH9 - high definition audio", "Intel" } , - { 0x8086, 0x71A2, "82443GX", "Host-to-PCI Bridge" } , - { 0x8086, 0x7221, "82810", "graphics device" } , - { 0x8086, 0x7600, "82372FB/82468GX", "LPC/FWH Interface" } , - { 0x8086, 0x7601, "82372FB/82468GX", "EIDE Controller" } , - { 0x8086, 0x7602, "82372FB/82468GX", "USB Host Controller" } , - { 0x8086, 0x7603, "82372FB/82468GX", "SM Bus Controller" } , - { 0x8086, 0x7605, "82372FB", "IEEE1394 OpenHCI Host Controller" } , - { 0x8086, 0x7800, "82740", "AGP Graphics Accelerator" } , -// { 0x8086, 0x8086, "park55", "lsdurjlk" } , -// { 0x8086, 0x8086, "", "" } , - { 0x8086, 0x8086, "(0x2994)", "Intel(R) Management Engine Interface" } , - { 0x8086, 0x811A, "Atom SCH", "Atom SCH PATA" } , - { 0x8086, 0x84C4, "82454KX/GX", "450KX/GX PCI Bridge (Orion)" } , - { 0x8086, 0x84C5, "82453KX/GX", "450KX/GX Memory Controller (Orion)" } , - { 0x8086, 0x84CA, "82451NX", "450NX PCIset Memory & I/O Controller" } , - { 0x8086, 0x84CB, "82454NX/82467GX", "PCI Expander Bridge" } , - { 0x8086, 0x84E0, "82461GX", "System Address controller" } , - { 0x8086, 0x84E1, "82462GX", "System Data Controller" } , - { 0x8086, 0x84E2, "82465GX", "Graphics Expander Bridge" } , - { 0x8086, 0x84E3, "82463GX", "Memory Address Controller" } , - { 0x8086, 0x84E4, "82464GX", "Memory Data Controller" } , - { 0x8086, 0x84E6, "82466GX", "Wide and fast PCI eXpander Bridge" } , - { 0x8086, 0x84EA, "82460GX", "AGP Bridge (GXB function 1)" } , - { 0x8086, 0x85A1, "6300ESB", "LPC Bridge" } , - { 0x8086, 0x85A2, "6300ESB", "IDE Controller" } , - { 0x8086, 0x85A3, "6300ESB", "Serial ATA Controller" } , - { 0x8086, 0x85A4, "6300ESB", "SMBus Controller" } , - { 0x8086, 0x85A6, "6300ESB", "AC'97 Audio Controller" } , - { 0x8086, 0x85A7, "6300ESB", "AC'97 Modem Controller" } , - { 0x8086, 0x85A9, "6300ESB", "USB 1.1 UHCI Controller #1" } , - { 0x8086, 0x85AA, "6300ESB", "USB 1.1 UHCI Controller #2" } , - { 0x8086, 0x9620, "", "I2O RAID PCI to PCI Bridge" } , - { 0x8086, 0x9621, "SRCU21", "I2O 1.5 RAID Controller" } , - { 0x8086, 0x9622, "SRCUxx", "I2O 1.5 RAID Controller" } , - { 0x8086, 0x9641, "SRCU31", "I2O 1.5 RAID Controller" } , - { 0x8086, 0x96A1, "SRCU31L", "I2O 1.5 RAID Controller" } , - { 0x8086, 0x9874, "AC97", "AUDIO CONTROLLER" } , - { 0x8086, 0x9876, "i845", "intel brokdale" } , - { 0x8086, 0xB152, "S21152BB", "PCI to PCI Bridge" } , - { 0x8086, 0xB154, "S21154AE/BE", "PCI to PCI Bridge" } , - { 0x8086, 0xB555, "21555", "Non-Transparent PCI-to-PCI Bridge" } , - { 0x8086, 8671, "", "" } , - { 0x80EE, 0xBEEF, "BGA", "Bochs/Qemu Graphics Adapter (VirtualBox)" } , - { 0x80EE, 0xCAFE, "VMMDEV", "Guest Additions device" } , - { 0x9004, 0x0078, "aic-7880p", "AHA-2940UW/CN" } , - { 0x9004, 0x1078, "AIC-7810C", "RAID Coprocessor" } , - { 0x9004, 0x1135, "0x0035", "Texas Instruments" } , - { 0x9004, 0x1160, "AIC-1160", "Fibre Channel Adapter" } , - { 0x9004, 0x2178, "AIC-7821", "SCSI Controller" } , - { 0x9004, 0x3860, "", "AIC-2930U Ultra SCSI Ctrlr" } , - { 0x9004, 0x3B78, "AHA-4944W/4944UW", "QuadChannel Fast-Wide/Ultra-Wide Diff. SCSI Ctrlr" } , - { 0x9004, 0x5075, "AIC-755x", "SCSI Ctrlr" } , - { 0x9004, 0x5078, "AIC-7850P", "Fast/Wide SCSI Controller" } , - { 0x9004, 0x5175, "AIC-755x", "SCSI Ctrlr" } , - { 0x9004, 0x5178, "AIC-7850", "FAST-SCSI Ctrlr" } , - { 0x9004, 0x5275, "AIC-755x", "SCSI Ctrlr" } , - { 0x9004, 0x5278, "AIC-7850", "Fast SCSI Ctrlr" } , - { 0x9004, 0x5375, "AIC-755x", "SCSI Ctrlr" } , - { 0x9004, 0x5378, "AIC-7850", "Fast SCSI Ctrlr" } , - { 0x9004, 0x5475, "AIC-755x", "SCSI Ctrlr" } , - { 0x9004, 0x5478, "AIC-7850", "Fast SCSI Ctrlr" } , - { 0x9004, 0x5575, "AVA-2930", "SCSI Ctrlr" } , - { 0x9004, 0x5578, "AIC-7855", "Fast SCSI Ctrlr" } , - { 0x9004, 0x5675, "AIC-755x", "SCSI Ctrlr" } , - { 0x9004, 0x5678, "AIC-7856", "Fast SCSI Ctrlr" } , - { 0x9004, 0x5775, "AIC-755x", "SCSI Ctrlr" } , - { 0x9004, 0x5778, "AIC-7850", "Fast SCSI Ctrlr" } , - { 0x9004, 0x5800, "AIC-5800", "PCI-to-1394 Ctrlr" } , - { 0x9004, 0x5900, "ANA-5910/30/40", "ATM155 & 25 LAN Controller" } , - { 0x9004, 0x5905, "ANA-5910A/30A/40A", "ATM Adpater" } , - { 0x9004, 0x6038, "AHA-2930C", "Ultra SCSI Adpater (VAR)" } , - { 0x9004, 0x6075, "AIC-7560?", "CardBus Ultra SCSI Controller" } , - { 0x9004, 0x6078, "AIC-7860", "PCI SCSI Controller" } , - { 0x9004, 0x6178, "AIC-7861", "PCI SCSI Controller" } , - { 0x9004, 0x6278, "AIC-7860", "SCSI Ctrlr" } , - { 0x9004, 0x6378, "AIC-7860", "SCSI Ctrlr" } , - { 0x9004, 0x6478, "AIC-786x", "SCSI Ctrlr" } , - { 0x9004, 0x6578, "AIC-786x", "SCSI Ctrlr" } , - { 0x9004, 0x6678, "AIC-786x", "SCSI Ctrlr" } , - { 0x9004, 0x6778, "AIC-786x", "SCSI Ctrlr" } , - { 0x9004, 0x6915, "ANA620xx/69011A", "Fast Ethernet" } , - { 0x9004, 0x7078, "AIC-7870", "Fast and Wide SCSI Ctrlr" } , - { 0x9004, 0x7178, "AHA-2940/2940W", "Fast/Fast-Wide SCSI Ctrlr" } , - { 0x9004, 0x7278, "AHA-3940/3940W", "Multichannel Fast/Fast-Wide SCSI Ctrlr" } , - { 0x9004, 0x7378, "AHA-3985", "4-chan RAID SCSI Ctrlr" } , - { 0x9004, 0x7478, "AHA-2944", "SCSI Ctrlr" } , - { 0x9004, 0x7578, "AHA-3944/3944W", "Multichannel Fast/Fast-Wide Diff. SCSI Ctrlr" } , - { 0x9004, 0x7678, "AHA-4944W/4944UW", "QuadChannel Fast-Wide/Ultra-Wide Diff. SCSI Ctrlr" } , - { 0x9004, 0x7778, "AIC-787x", "SCSI Ctrlr" } , - { 0x9004, 0x7810, "aic 7810", "Memory control IC" } , - { 0x9004, 0x7815, "AIC-7515", "RAID + Memory Controller IC" } , - { 0x9004, 0x7850, "aic-7850", "Fast/Wide SCSI-2 Controller" } , - { 0x9004, 0x7855, "AHA-2930", "Single channel SCSI Host Adapter" } , - { 0x9004, 0x7860, "AIC-7860", "PCI SCSI Controller" } , - { 0x9004, 0x7870, "AIC-7870", "Fast/Wide SCSI-2 Controller" } , - { 0x9004, 0x7871, "aha 2940", "SCSI" } , - { 0x9004, 0x7872, "aha 3940", "Multiple SCSI channels" } , - { 0x9004, 0x7873, "aha 3985", "Multiple SCSI channels" } , - { 0x9004, 0x7874, "aha 2944", "Differential SCSI" } , - { 0x9004, 0x7880, "aic7880p", "Fast 20 SCSI" } , - { 0x9004, 0x7890, "AIC-7890", "SCSI controller" } , - { 0x9004, 0x7891, "AIC-789x", "SCSI controller" } , - { 0x9004, 0x7892, "AIC-789x", "SCSI controller" } , - { 0x9004, 0x7893, "AIC-789x", "SCSI controller" } , - { 0x9004, 0x7894, "AIC-789x", "SCSI controller" } , - { 0x9004, 0x7895, "AIC-7895", "Ultra-Wide SCSI Ctrlr on AHA-2940 AHA-394x" } , - { 0x9004, 0x7896, "AIC-789x", "SCSI controller" } , - { 0x9004, 0x7897, "AIC-789x", "SCSI controller" } , - { 0x9004, 0x8078, "AIC-7880", "Ultra Wide SCSI" } , - { 0x9004, 0x8178, "AHA-2940U/2940UW", "Ultra/Ultra-Wide SCSI Ctrlr" } , - { 0x9004, 0x8278, "AHA-3940Uxx", "AHA-3940U/3940UW/3940UWD SCSI Ctrlr" } , - { 0x9004, 0x8378, "AIC-7883U", "SCSI Controller" } , - { 0x9004, 0x8478, "ADAPTEC 2940UW CN SCSI", "Ultra-Wide Diff. SCSI Ctrlr" } , - { 0x9004, 0x8578, "AHA-3944U/3944UWD", "Fast-Wide/Ultra-Wide Diff. SCSI Ctrlr" } , - { 0x9004, 0x8678, "AHA-4944UW", "QuadChannel Ultra-Wide Diff. SCSI Ctrlr" } , - { 0x9004, 0x8778, "AIC-788x", "Ultra-Wide SCSI Ctrlr" } , - { 0x9004, 0x8878, "AIC-7888?", "Ultra Wide SCSI Controller" } , - { 0x9004, 0x8B78, "ABA-1030", "AIC-7880P" } , - { 0x9004, 0xEC78, "AHA-4944W/4944UW", "QuadChannel Fast-Wide/Ultra-Wide Diff. SCSI Ctrlr" } , - { 0xD4D4, 0x010F, "PMC-211", "PMC-211" } , - { 0xD4D4, 0x0601, "", "PCI Mezzanine Card" } , - { 0xDEAF, 0x9050, "", "PC Weasel PCI VGA Device" } , - { 0xDEAF, 0x9051, "", "PC Weasel PCI Serial Comm. Device" } , - { 0xDEAF, 0x9052, "", "PC Weasel PCI" } , - { 0xE159, 0x0001, "Ambient MD3200 A", "Intel 537 Data Fax Voice v.92 Modem" } , - { 0xE159, 0x0002, "", "Sedlbauer Speed PCI" } , - { 0xE159, 0x0600, "Tiger 600", "PCI-to-PCI Bridge" } , - { 0xEDD8, 0xA091, "ARK1000PV", "Stingray GUI Accelerator" } , - { 0xEDD8, 0xA099, "ARK2000PV", "Stingray GUI Accelerator" } , - { 0xEDD8, 0xA0A1, "ARK2000MT", "Stingray 64" } , - { 0xEDD8, 0xA0A9, "ARK2000MI", "Quadro645 GUI Accelerator" } , - { 0xEDD8, 0xA0B1, "ARK2000MI+", "GUI Accelerator" } , - { 0x1519, 0x2004, "0x1", "PCI Interface bus" } , - { 0x151B, 0x9080, "me594v02100 combox", "combox cb 300a" } , - { 0x151F, 0x0001, "TOPIC FM-56PCI-TP", "TOPIC FM-56PCI-TP" } , - { 0x151F, 0x0568, "1.0.1.8", "56k Internal Data Fax Voice Modem" } , - { 0x1435, 0x0531, "DELETE", "DELETE" } , - { 0x1435, 0x6020, "SPM6020", "PCI-104 dspModule" } , - { 0x1435, 0x6030, "SPM6030", "PC/104-Plus dspModule" } , - { 0x1435, 0x6420, "SPM186420", "PC/104-Plus dspModule" } , - { 0x1435, 0x6430, "SPM176430", "PC/104-Plus dspModule" } , - { 0x1435, 0x7520, "DM7520", "PC/104-Plus dataModule" } , - { 0x1435, 0x7540, "SDM7540", "PC/104-Plus dataModule with SmartCal" } , - { 0x1523, 0x8, "MU9C8K64", "Content Addressable Memory" } , - { 0x1524, 0x0510, "1.4.5.0", "PCI Memory Card Reader Controller" } , - { 0x1524, 0x0530, "CB-712/714/810", "Memory Stick Card Reader" } , - { 0x1524, 0x0550, "CB-712/714/810", "Secure Digital Card Reader" } , - { 0x1524, 0x0610, "???", "PCI Smart Card Reader Controller" } , - { 0x1524, 0x1211, "CB-1211", "CardBus Controller" } , - { 0x1524, 0x1225, "CB-1225", "CardBus Controller" } , - { 0x1524, 0x1410, "CB-1420", "CardBus Controller" } , - { 0x1524, 0x1411, "CB-710/2/4/810", "Cardbus Controller" } , - { 0x1524, 0x1412, "CB-712/4", "Cardbus Controller" } , - { 0x1524, 0x1420, "CB-1420", "CardBus Controller" } , - { 0x1524, 0x1421, "CB-720/2/4", "CardBus Controller" } , - { 0x1524, 0x1422, "CB-722/4", "CardBus Controller" } , - { 0x1524, 0x510, "1.4.5.0", "PCI Memory Card Reader Controller" } , - { 0x1538, 0x0301, "?", "Tekram DC200 PATA100 RAID Controller" } , - { 0x153B, 0x1115, "ICE1712 Envy24", "IC Ensemble Inc ICE1712 Envy24 Multichannel Audio Controller" } , - { 0x153B, 0x1143, "SAA7134HL", "Philips Semiconductors SAA7134HL Multimedia Capture Device" } , - { 0x153B, 0x6003, "CS4614/22/24", "CrystalClear SoundFusion PCI Audio Accel" } , - { 0x153F, 0xdead, "xx12345", "Not a chip ..." } , - { 0x1540, 0x9524, "saa7134", "PAL/SECAM TV card w/ FM1216ME MK3 tuner (+FM radio)" } , - { 0x1693, 0x0212, "PLX PCI9054", "EPONINE ESR-PCI Board" } , - { 0x1693, 0x0213, "Motorola MPC8245", "EPONINE MTM120 PCI Board" } , - { 0x170B, 0x0100, "NSP2000-SSL", "Crypto Aceletator" } , - { 0x1743, 0x8139, "ROL/F-100", "Fast Ethernet Adapter with ROL" } , - { 0x1522, 0x0100, "PBridge+", "PCI Interface Chip" } , - { 0x1543, 0x3052, "30201543", "Modem Intel 537EP (Chipset KAIOMY)" } , - { 0x1543, 0x3155, "Unknown", "Modem Device on High Definition Audio Bus" } , - { 0x1555, 0x0002, "PLX PCI 9050", "Easylon PCI Bus Interface" } , - { 0x1549, 0x80FF, "PCI-ISA-001", "PCI/ISA Bus Bridge" } , - { 0x1558, 0x1558, "", "" } , - { 0x155E, 0x0020, "MFC3", "Multi Function Card Version 3" } , - { 0x1562, 0x0001, "LA-41x3", "Spectrum24 Wireless LAN PCI Card" } , - { 0x1562, 0x0002, "LA-5030", "Symbol Wireless Networker 802.11a/g CardBus" } , - { 0x1562, 0x0003, "LA-5033", "Symbol Wireless Networker 802.11a/g PCI" } , - { 0x156A, 0x5000, "NA", "Wideband Advanced Signal Processor" } , - { 0x156A, 0x5100, "NA", "High Data Rate Radio" } , - { 0x16CA, 0x0001, "Rocket Drive", "Solid State Disk" } , - { 0x1571, 0xA001, "CCSI PCI20", "ARCNET backplane" } , - { 0x1571, 0xA002, "CCSI PCI20-485D", "ARCnet" } , - { 0x1571, 0xA003, "CCSI PCI20-485X", "ARCnet" } , - { 0x1571, 0xA004, "CCSI PCI20-CXB", "ARCnet" } , - { 0x1571, 0xA005, "CCSI PCI20-CXS", "ARCnet" } , - { 0x1571, 0xA006, "CCSI PCI20-FOG-SMA", "ARCnet" } , - { 0x1571, 0xA007, "CCSI PCI20-FOG-ST", "ARCnet" } , - { 0x1571, 0xA008, "CCSI PCI20-TB5", "ARCnet" } , - { 0x1571, 0xA009, "CCSI PCI20-5-485", "5 Mbit ARCnet" } , - { 0x1571, 0xA00A, "CCSI PCI20-5-485D", "5 Mbit ARCnet" } , - { 0x1571, 0xA00B, "CCSI PCI20-5-485X", "5 Mbit ARCnet" } , - { 0x1571, 0xA00C, "CCSI PIC20-5-FOG-ST", "5 Mbit ARCnet" } , - { 0x1571, 0xA00D, "CCSI PCI20-5-FOG-SMA", "5 Mbit ARCnet" } , - { 0x1571, 0xA00E, "COM200C22", "ARCNET" } , - { 0x1571, 0xA201, "CCSI PCI22-485", "10 Mbit ARCnet" } , - { 0x1571, 0xA202, "CCSI PCI22-485D", "10 Mbit ARCnet" } , - { 0x1571, 0xA203, "CCSI PCI22-485X", "10 Mbit ARCnet" } , - { 0x1571, 0xA204, "CCSI PCI22-CHB", "10 Mbit ARCnet" } , - { 0x1571, 0xA205, "CCSI PCI22-FOG-ST", "10 Mbit ARCnet" } , - { 0x1571, 0xA206, "CCSI PCI22-THB", "10 Mbit ARCnet" } , - { 0x173B, 0x03E8, "AC1000", "Gigabit Ethernet Adapter" } , - { 0x173B, 0x03EA, "AC1002", "Gigabit Ethernet Adapter" } , - { 0x1584, 4003, "", "" } , - { 0x1586, 0x0803, "", "" } , - { 0x1588, 0x1100, "PAX.port 1100", "PAX.ware 1100 dual Gb classifier engine" } , - { 0x1588, 0x2000, "AMD '971", "SNP 8023 packet classifier - AMD component" } , - { 0x1588, 0x8023, "SNP8023", "PAX.ware 100 packet classifier" } , - { 0x158B, 0x0015, "HLF-VMPEU560-C", "Standar HSP Modem Series" } , - { 0x15A2, 0x0001, "TA700", "PCI Bus Analyzer/Exerciser" } , - { 0x17AF, 0x4150, "200", "HIS Excalibur Radeon 9600" } , - { 0x15B0, 0x0001, "FM-1789", "Pctel" } , - { 0x15B0, 0x2BD0, "2BD0", "soft56k voice,data,fax CARP" } , - { 0x15B3, 0x5274, "MT21108", "InfiniBridge" } , - { 0x15B3, 0x6278, "MT25208A0-FCC", "InfiniHost TM III Ex" } , - { 0x15B8, 0x3009, "xPCI-3504", "Analog output board" } , - { 0x15BC, 0x0101, "n2530a", "DX2+ FC-AL Adapter" } , - { 0x15BC, 0x0103, "QX4", "4 Port Fibre Channel Controller" } , - { 0x15BC, 0x2530, "???", "HP Communications Port" } , - { 0x15BC, 0x2531, "???", "HP Toptools Remote Control Adapter" } , - { 0x15BC, 0x2532, "???", "HP Toptools Remote Control Adapter" } , - { 0x15BC, 0x2929, "E2929A", "PCI/PCI-X Bus Analyzer" } , - { 0x1394, 0x0001, "LXT1001", "Gigabit Ethernet Adapter" } , - { 0x15D1, 0x0001, "TC11IB", "TriCore 32-bit Single-chip Microctrlr" } , - { 0x15D1, 0x0003, "PEB 20544 E v1.1", "6 Port Optimized Comm Ctrlr (SPOCC)" } , - { 0x15D1, 0x0004, "PEB 3454 E v1.1", "TE3-SPICCE 6 Port Integrated Comm Ctrlr" } , - { 0x15D7, 0x0056, "hcf cx11252-41z", "hcf 56" } , - { 0x15D8, 0x9001, "", "" } , - { 0x15DD, 0x7664, "vgn-ar71mr", "idt high audio" } , - { 0x15DD, 0x7680, "*", "SIGMATEL STAC 92XX C-Major HD Audio" } , - { 0x15E2, 0x0500, "", "Internet PhoneJack PCI Card" } , - { 0xEACE, 0x3100, "DAG 3.10", "OC-3/OC-12" } , - { 0xEACE, 0x3200, "DAG 3.2x", "OC-3/OC-12" } , - { 0xEACE, 0x320E, "DAG 3.2E", "Fast Ethernet" } , - { 0xEACE, 0x340E, "DAG 3.4E", "Fast Ethernet" } , - { 0xEACE, 0x341E, "DAG 3.41E", "Fast Ethernet" } , - { 0xEACE, 0x3500, "DAG 3.5", "OC-3/OC-12" } , - { 0xEACE, 0x351C, "DAG 3.5ECM", "Fast Ethernet" } , - { 0xEACE, 0x4100, "DAG 4.10", "OC-48" } , - { 0xEACE, 0x4110, "DAG 4.11", "OC-48" } , - { 0xEACE, 0x4200, "DAG 4.2", "OC-48" } , - { 0xEACE, 0x420E, "DAG 4.2E", "Dual Gigabit Ethernet" } , - { 0xEACE, 0x430e, "DAG 4.3E", "Dual Gigabit Ethernet" } , - { 0x15E6, 0x0002, "1646t00", "v.90 Lucent Modem" } , - { 0x15E8, 0x0130, "NCP130", "Wireless NIC" } , - { 0x15E8, 0x0131, "Prism II", "InstantWave HR PCI card" } , - { 0x15E9, 0x1841, "NetStaQ ADMA-100", "ATA controller" } , - { 0x15F1, 0x2F30, "CX11252-15", "Conexant HSFi" } , - { 0x15F2, 0x0001, "Spot RT", "Spot RT Interface Board" } , - { 0x15F2, 0x0002, "Spot RT #2", "Spot RT Interface Board" } , - { 0x15F2, 0x0003, "Spot Insight", "Spot Insight Interface Board" } , - { 0x1619, 0x0400, "FarSync T2P", "Two Port Intelligent Sync Comms Card" } , - { 0x1619, 0x0440, "FarSync T4P", "Four Port Intelligent Sync Comms Card" } , - { 0x1619, 0x0610, "FarSync T1U", "One Port Intelligent Sync Comms Card" } , - { 0x1619, 0x0620, "FarSync T2U", "Two Port Intelligent Sync Comms Card" } , - { 0x1619, 0x0640, "FarSync T4U", "Four Port Intelligent Sync Comms Card" } , - { 0x1619, 0x1610, "FarSync TE1", "One Port Intelligent Sync Comms Card" } , - { 0x1619, 0x1612, "FarSync TE1C", "Channelized Intelligent Sync Comms Card" } , - { 0x1619, 0x2610, "FarSync DSL-S1", "G.SHDSL Intelligent Sync Comms Card" } , - { 0x1619, 0x3640, "FarSync T4E", "Four Port Intelligent Sync Comms Card" } , - { 0x1619, 0x4620, "FarSync T2Ue (PCI Express)", "Two Port Intelligent Sync Comms Card" } , - { 0x1619, 0x4640, "FarSync T4Ue (PCI Express)", "Four Port Intelligent Sync Comms Card" } , - { 0x1621, 0x0020, "LynxTWO-A", "4 in/4 out Professional Digital Audio Card" } , - { 0x1621, 0x0021, "LynxTWO-B", "2 in/6 out Professional Digital Audio Card" } , - { 0x1621, 0x0022, "LynxTWO-C", "6 in/2 out Professional Digital Audio Card" } , - { 0x1621, 0x0023, "Lynx L22", "2 in/2 out Professional Digital Audio Card" } , - { 0x1621, 0x0024, "Lynx AES16", "16 in/16 out AES/EBU Audio Card" } , - { 0x1621, 0x0025, "Lynx AES16-SRC", "16 in/16 out AES/EBU Audio Card w/SRC" } , - { 0x1629, 0x1003, "", "Format Synchronizer v3.0" } , - { 0x1629, 0x2002, "", "Fast Universal Data Output" } , - { 0x162D, 0x0100, "", "Repeographics controller" } , - { 0x162D, 0x0101, "", "Reprographics Controller" } , - { 0x162D, 0x0102, "", "Reprographics Controller" } , - { 0x162D, 0x0103, "", "Reprographics Controller" } , - { 0x162F, 0x1111, "TS-PRL1", "General Purpose Relay Card" } , - { 0x162F, 0x1112, "TS-PMA", "Matrix Card" } , - { 0x1638, 0x1100, "WL11000P", " WL11000P" } , - { 0x163C, 0x3052, "R6793-11", "RS56/HSP-PCI" } , - { 0x163C, 0xFF02, "SL2800 PCI", "SMART LINK 56K VOICE V.92 MODEM" } , - { 0x1734, 0x007a, "Rage XL", "ATI Rage XL (rev 27)" } , - { 0x1734, 0x1011, "AIC-7902W", "Adaptec AIC-7902 Dual Channel U320 SCSI" } , - { 0x1734, 0x1012, "CSB6", "Serverworks Southbridge with RAID/IDE (rev a0), OHCI USB (rev 05), GCLE-2 Host Bridge" } , - { 0x1734, 0x1013, "BCM5703", "Broadcom Corp. NetXtreme Gigabyte Ethernet" } , - { 0x1734, 0x10b9, "0x00541000", "SAS 3000 series, 8-port with 1068 -StorPort" } , - { 0x164F, 0x0001, "PLX 9054", "PCI interface chip" } , - { 0x164F, 0x0002, "PLX 9054", "PCI interaface chip" } , - { 0x1813, 0x3059, "VT8237", "AC97 Enhanced Audio Controller - the 8251 controller is different" } , - { 0x1813, 0x4000, "MD5628D-L-A", "intel V.92 HaM Modem" } , - { 0x1813, 0x4100, "Ambient MD8820", "Intel HaM V.92 Modem" } , - { 0x17D5, 0x5831, "X1", "Xframe 10GbE PCI-X Adapter" } , - { 0x17D5, 0x5832, "X2", "Xframe II 10GbE PCI-X 2.0 Adapter" } , - { 0x17D5, 0x5833, "X3", "E3100 PCI-Express 10Gb Ethernet Interface" } , - { 0xFA57, 0x0001, "PMC", "Pattern Matching Chip" } , - { 0x18CA, 0x0040, "8085", "Volari Family" } , - { 0x18C9, 0x1011, "Leonardo CL", "Video processor" } , - { 0x18C9, 0x1012, "Leonardo CL-P", "Video processor" } , - { 0x18C9, 0x1013, "Leonardo CL-DB", "Video processor" } , - { 0x18C9, 0x1014, "Leonardo CL-P-DB", "Video processor" } , - { 0x18C9, 0x1015, "Leonardo CL-DVR", "Video processor" } , - { 0x18C9, 0x1016, "Leonardo CL-DVR-DB", "Video processor" } , - { 0x18C9, 0x2011, "Picasso 2SQ", "Framegrabber" } , - { 0x18C9, 0x2012, "Picasso 3C/3Cpro", "Framegrabber" } , - { 0x18C9, 0x2013, "Picasso LS", "Framegrabber" } , - { 0x18C9, 0x2014, "Picasso CL", "Framegrabber" } , - { 0x18C9, 0x2015, "Picasso FI", "Framegrabber" } , - { 0x18C9, 0x2016, "Picasso SDI", "Framegrabber" } , - { 0x18C9, 0x2017, "Picasso DUO", "Framegrabber" } , - { 0x18C9, 0x2021, "Colory", "Framegrabber" } , - { 0x18C9, 0x3011, "Valentino", "Video Output Board" } , - { 0x1910, 0x0001, "SW5000-NCA", "Seaway Network Content Accelerator" } , - { 0x1360, 0x0101, "PCI32", "DCF77 Radio Clock" } , - { 0x1360, 0x0102, "PCI509", "DCF77 Radio Clock" } , - { 0x1360, 0x0103, "PCI510", "DCF77 Radio Clock" } , - { 0x1360, 0x0104, "PCI511", "DCF77 Radio Clock" } , - { 0x1360, 0x0105, "PEX511", "DCF77 Receiver" } , - { 0x1360, 0x0201, "GPS167PCI", "GPS Receiver" } , - { 0x1360, 0x0202, "GPS168PCI", "GPS Receiver" } , - { 0x1360, 0x0203, "GPS169PCI", "GPS Receiver" } , - { 0x1360, 0x0204, "GPS170PCI", "GPS Receiver" } , - { 0x1360, 0x0205, "GPS170PEX", "GPS Receiver" } , - { 0x1360, 0x0301, "TCR510PCI", "IRIG Timecode Reader" } , - { 0x1360, 0x0302, "TCR167PCI", "IRIG Timecode Reader" } , - { 0x1360, 0x0303, "TCR511PCI", "IRIG Timecode Reader" } , - { 0x1360, 0x0304, "TCR511PEX", "IRIG Timecode Receiver" } , - { 0x1725, 0x7174, "VSC7174", "VSC7174 PCI/PCI-X SATA Controller" } , - { 0x1753, 0x1001, "VP500", "VolumePro 500" } , - { 0x1753, 0x1004, "VP1000", "VolumePro 1000" } , - { 0x17CC, 0x2280, "Net 2280", "USB 2.0 Device Controller" } , - { 0x14EA, 0xAB06, "FNW-3603-TX", "10/100 Fast Ethernet CardBus (RTL8139)" } , - { 0x12B9, 0x1006, "5610", "5610 56K FaxModem WinModem" } , - { 0x12B9, 0x1007, "AD1807JS", "US Robotics 56K DATA FAX WINMODEM" } , - { 0x12B9, 0x1008, "USR5610B", "USR5610B (0005610-02) 56K Performance Pro Modem (PCI Internal)" } , - { 0x12B9, 0x3F0, "3CP2977", "US Robotics 56K Fax PCI aka Model 0726, V.90 56K Internal Faxmodem" } , - { 0x1814, 0x0101, "2460 802.11b", "RT2460 802.11b Baseband/MAC integrated chip" } , - { 0x1814, 0x0201, "0x03011814", "Ralink Chipset 802.11b/g WLAN Card" } , - { 0x1814, 0x0201, "", "W-LAN 802.11b/g" } , - { 0x1814, 0x0201, "RT2560F", "RaLink" } , - { 0x1814, 0x0301, "b8341462", "Edimax 54 MBit WLan 802.11g rt 2500" } , - { 0x1814, 0x0302, "RT2525 2.4GHz transceiver + RT2560 MAC/BBP", "wireless a/b" } , - { 0x1814, 0x0781, "RT2860/RT2890", "Wireless" } , - { 0x1103, 0x0003, "HPT 343/345/363", "EIDE Controller" } , - { 0x1103, 0x0004, "HPT366/368/370/370A", "ATA Raid Controller" } , - { 0x1103, 0x0005, "HPT372/372N", "PATA133 Raid Controller" } , - { 0x1103, 0x0006, "HPT302", "ATA Raid Controller" } , - { 0x1103, 0x0007, "HPT371", "ATA133 Controller" } , - { 0x1103, 0x0008, "HPT-374", "ATA Raid Controller" } , - { 0x1103, 0x1720, "RR172x", "RR172x SATA Controller" } , - { 0x1103, 0x1740, "RR174x", "RR174x SATA Controller" } , - { 0x1103, 0x1742, "RR174x", "RR174x SATA Controller" } , - { 0x1103, 0x2210, "RR2210", "RR2210 SATA Controller" } , - { 0x1103, 0x2300, "RR2300", "RR2300 SATA Controller" } , - { 0x1103, 0x2310, "RR231x", "RR231x SATA Controller" } , - { 0x1103, 0x2340, "RR2340", "RR2340 SATA Controller" } , - { 0x1103, 0x2522, "RR252x", "RR252x SATA Controller" } , - { 0x1103, 0x3120, "RR312x", "RR312x SATA Controller" } , - { 0x1103, 0x3220, "RR322x", "RR322x SATA Controller" } , - { 0x1103, 0x3320, "RR332x", "RR332x SATA Controller" } , - { 0x1103, 0x3410, "RR341x", "RR341x SATA Controller" } , - { 0x1103, 0x3510, "RR35xx", "RR35xx SATA Controller" } , - { 0x1103, 0x3511, "RR35xx", "RR35xx SATA Controller" } , - { 0x1103, 0x3520, "RR35xx", "RR35xx SATA Controller" } , - { 0x1103, 0x3521, "RR35xx", "RR35xx SATA Controller" } , - { 0x1103, 0x3522, "RR35xx", "RR35xx SATA Controller" } , - { 0x1103, 0x3540, "RR35xx", "RR35xx SATA Controller" } , - { 0x1103, 0x4320, "RR432x", "RR432x SATA Controller" } , - { 0x1103, 0x5081, "RR18xx", "RR18xx SATA Controller" } , - { 0x1103, 0x6081, "RR222x/224x", "RR222x/224x SATA Controller" } , - { 0x1103, 0x7042, "RR231x", "RR231x SATA Controller" } , - { 0x1681, 0x0050, "HWGPCI-54", "Hercules WiFi PCI 802.11G" } , - { 0x18F7, 0x0001, "ESCC-PCI-335", "Fastcom:ESCC-PCI-335 Syncronous RS422/485 serial communication adapter" } , - { 0x18F7, 0x0002, "422/4-PCI-335", "Fastcom:422/4-PCI-335 Asyncronous RS422/485 serial adapter" } , - { 0x18F7, 0x0004, "422/2-PCI-335", "Fastcom:422/2-PCI-335 Asyncronous RS422/485 serial adapter" } , - { 0x18F7, 0x000a, "232/4-PCI-335", "Fastcom:232/4-PCI-335 Asyncronous RS232 serial adapter" } , - { 0x1737, 0x1032, "EG1032 v3", "Linksys Instant Gigabit Desktop Network Interface" } , - { 0x19AC, 0x0001, "ACA2400", "Crypto Accelerator" } , - { 0x110A, 0x2101, "PEB 20321", "Multichannel Network Interface Controller for HDLC" } , - { 0x110A, 0x2102, "PEB 20534", "DMA supported serial communication controller with 4 channels" } , - { 0x110A, 0x3141, "01", "PROFIBUS Communication Processor CP5611 A2" } , - { 0x110A, 0x4033, "ERTEC400", "EB400 ProfiNet Device-Kit" } , - { 0x104B, 0x1040, "", "BT958 SCSI Host Adaptor" } , - { 0x104B, 0x8130, "-", "Flashpoint LT" } , - { 0x1180, 0x0475, "RL5c475", "Cardbus Controller" } , - { 0x1180, 0x0476, "unknown", "Ricoh R/RL/5C476(II)" } , - { 0x1180, 0x0478, "RB5c478", "Cardbus Controller" } , - { 0x1180, 0x0552, "R5C552", "FireWire (IEEE 1394) Controller" } , - { 0x1180, 0x0592, "13871043", "Ricoh Memory Stick Host Controller" } , - { 0x1180, 0x0822, "R5C832, R5C843", "SDA Standard Compliant SD Host Controller" } , - { 0x1180, 0x0832, "unknown", "IEEE 1394 (4 pin firewire) chip)" } , - { 0x1180, 0x0843, "R5C853", "Ricoh SD/MMC Host Controller" } , - { 0x1180, 0x0852, "01cf1028", "Ricoh xD-Picture Card Host Controller" } , - { 0x1180, 0x5551, "Unknown", "IEEE 1394 Controller" } , - { 0x14F1, 0x1035, "unknown", "unknown" } , - { 0x14F1, 0x1059, "DI15630-5, DI5631, DI5633", "SmartHCF" } , - { 0x14F1, 0x1456, "1456", "HCFp Modem" } , - { 0x14F1, 0x1611, "?", "AccessRunner ADSL Modem" } , - { 0x14F1, 0x2400, "unknown", "unknown" } , - { 0x14F1, 0x2702, "cx11252-15", "HSFp or Soft V92 Data Fax Modem" } , - { 0x14F1, 0x2BFA, "Unknown", "HDA D100 MDC v.92 Modem" } , - { 0x14F1, 0x2C06, "1002", "HDAUDIO Soft Data fax Modem with SmartPC" } , - { 0x14F1, 0x2F00, "00101767", "HSF 56k HSFi Modem" } , - { 0x14F1, 0x2F20, "CX11252-11", "HSFi PCI Internal Modem" } , - { 0x14F1, 0x2F30, "01", "Zyxel OMNI 56K PCI Plus Rev.3 " } , - { 0x14F1, 0x2F30, "01", "hp/compaq alhena 5-gl6" } , - { 0x14F1, 0x2F40, "71030277", "Conexant Modem RD02-D490" } , - { 0x14F1, 0x2F82, "cx9510-11z", "Conexant PCI-E Soft Data/Fax Modem with SmartCP" } , - { 0x14F1, 0x5045, "4.0.3.1", "HDAUDIO Soft Data fax Modem with SmartPC / Conexant High Definition SmartAudio HD2" } , -//# { 0x14F1, 0x50452, "1179FF31", "Conextant High Definition Audio-Venice 5045" } , - { 0x14F1, 0x5051, "4.0.1.6", "Audio" } , - { 0x14F1, 0x5051, "unknow", "Realtek High Definition audio" } , - { 0x14F1, 0x5051, "nForce 630M", "Conexant HD-Audio SmartAudio 221" } , - { 0x14F1, 0x5B7A, "Belived to be a CX23418", "Single-Chip MPEG-2 Encoder with Integrated Analog Video/Broadcast Audio Decoder" } , - { 0x14F1, 0x8800, "2003", "Conexant 23881 Video Capture (NTSC)" } , - { 0x14F1, 0x8852, "0x7717", "CX23881-21" } , - { 0x1971, 0x0001, "", "AGEIA PhysX 100 Series PCI Express Card" } , - { 0x1971, 0x1011, "PCIVEN_1971&DEV_1011&CC_FF00", "AGEIA PhysX 100 Series PCI Card" } , - { 0x1971, 0x1021, "", "AGEIA PhysX 200 Series PCI Express Card" } , - { 0x17C0, 0x12ab, "", "" } , - { 0x1682, 0x9875, "", "" } , - { 0x168C, 0x0007, "AR5005", "802.11a Wireless Adapter" } , - { 0x168C, 0x0011, "AR5bmb5", "802.11a Wireless Adapter" } , - { 0x168C, 0x0012, "AR5211", "802.11a/b/g Mini-PCI Wireless Adapter" } , - { 0x168C, 0x0013, "AR5212", "802.11a/b/g Wireless Adapter" } , - { 0x168C, 0x001A, "Atheros AR5005G", "Atheros AR5005G 802.11abg NIC Chipset / TP-Link (TL-WN551G)" } , - { 0x168C, 0x001B, "AR5006X", "802.11abg NIC" } , - { 0x168C, 0x001c, "VEN_10DE&DEV_0649&SUBSYS_059717FF&REV_A14&2DEFBOA", "HDAUDIOFUNC_01&VEN_10DE&DEV_0003&SUBSYS_10DE0101&REV_10004&6641A29&0&0201" } , - { 0x168C, 0x0023, "AR5416", "802.11a/b/g/n Wireless PCI Adapter" } , - { 0x168C, 0x0024, "AR5008", "Atheros 802.11a/b/g/n (pre-N) radio" } , - { 0x168C, 0x002A, "0001", "Atheros AR5B91 Wireless Network Adapter" } , - { 0x168C, 0x1014, "AR5212", "Atheros AR5212 802.11abg wireless" } , - { 0x168C, 0xFF96, "AR5212", "LAN-Express AS IEEE 802.11g miniPCI adapter" } , - { 0x1303, 0x0001, "0239", "cM67 CompactPCI DSP Card" } , - { 0x1303, 0x0002, "1", "M44/cM44 DSP board" } , - { 0x1303, 0x0003, "1", "Quattro6x DSP board" } , - { 0x1303, 0x0004, "1", "Chico/ChicoPlus Data Acquisition Board" } , - { 0x1303, 0x0005, "1", "Code Hammer Jtag Debugger board" } , - { 0x1303, 0x0006, "1", "Matador DSP board" } , - { 0x1303, 0x0007, "1", "Quixote DSP board" } , - { 0x1303, 0x0008, "1", "Quadia C64x DSP" } , - { 0x1303, 0x0009, "1", "Quadia DSP Baseboard" } , - { 0x4144, 0x0040, "ADM-XRC", "Virtex-E Bridge" } , - { 0x4144, 0x0041, "ADM-XRC-II Lite", "Virtex-II Bridge" } , - { 0x4144, 0x0042, "ADM-XRC-II", "Virtex-II Bridge" } , - { 0x4144, 0x0043, "ADM-XPL", "Virtex-II Pro Bridge" } , - { 0x4144, 0x0044, "ADM-XP", "Virtex-II Pro PCI/PCI-X Bridge" } , - { 0x4144, 0x0045, "ADP-WRC-II", "Virtex-II Bridge" } , - { 0x4144, 0x0046, "ADP-DRC-II", "Virtex-II Bridge" } , - { 0x4144, 0x0049, "ADP-XPI", "Virtex-II Pro PCI" } , - { 0x4144, 0x004A, "ADP-XPI (PCI-X)", "Virtex-II Pro PCI-X Bridge" } , - { 0x4144, 0x004F, "ADM-XRC-4FX", "Virtex-II Pro PCI-X Bridge" } , - { 0x4144, 0x0050, "ADM-XRC-5LX", "Virtex-4LX Bridge" } , - { 0x4144, 0x0051, "ADM-XRC-5T1", "ADM-XRC-5T1" } , - { 0x1332, 0x5410, "MM-5410D", "PCI 32bit Bulk Memory w/DMA" } , - { 0x1332, 0x5415, "MM-5415CN", "PCI Battery Backed SDRAM Adapter" } , - { 0x1332, 0x5425, "MM-5425CN", "PCI Memory Module with Battery Backup" } , - { 0x1332, 0x6140, "MM-6140D", "Memory Module" } , - { 0x1888, 0x0301, "", "" } , - { 0x1888, 0x0601, "", "" } , - { 0x1888, 0x0710, "", "" } , - { 0x1888, 0x0720, "", "" } , - { 0x1888, 0x2503, "Bt881", "Video Capture (10 bit High qualtiy cap)" } , - { 0x1888, 0x2504, "Bt878", "Video Capture" } , - { 0x1888, 0x3503, "nVidia NV28", "VGA Geforce4 MX440" } , - { 0x1888, 0x3505, "nVidia NV28", "VGA Geforce4 Ti4200" } , - { 0x167F, 0x4634, "", "FOB-IO Card" } , - { 0x167F, 0x4C32, "", "L2B PCI Board" } , - { 0x167F, 0x5344, "", "FOB-SD Card" } , - { 0x167F, 0x5443, "", "FOB-TDC Card" } , - { 0x14B5, 0x0200, "Scope", "" } , - { 0x14B5, 0x0300, "Pulsar", "" } , - { 0x14B5, 0x0400, "Pulsar SRB", "" } , - { 0x14B5, 0x0600, "Pulsar 2", "" } , - { 0x14B5, 0x0800, "", "DSP-Board" } , - { 0x14B5, 0x0900, "", "DSP-Board" } , - { 0x14B5, 0x0A00, "", "DSP-Board" } , - { 0x14B5, 0x0B00, "", "DSP-Board" } , - { 0x148C, 0x4011, "RV250", "RADEON 9000 PRO EVIL COMMANDO" } , - { 0x148C, 0x4152, "0x1002", "0x2079" } , - { 0x174B, 0x0260, "RV280", "Saphire Radeon 9250" } , - { 0x174B, 0x0261, "RV280", "Sapphire Radeon 9250 - Secondary" } , - { 0x174B, 0x7176, "RV250", "RADEON 9000 ATLANTIS PRO" } , - { 0x174B, 0x7177, "RV280", "RADEON 9000 ATLANTIS PRO - Secondary" } , - { 0x174B, 0x7C12, "RV280", "RADEON 9200 ATLANTIS - Secondary" } , - { 0x174B, 0x7C13, "RV280", "RADEON 9200 ATLANTIS" } , - { 0x174B, 0x9501, "RV670 ", "ATI Radeon HD 3870 " } , - { 0x17EE, 0x4153, "RV350", "Radeon 9550" } , - { 0x1328, 0x2048, "", "" } , - { 0x1328, 0x8888, "rev 1.5", "cPEG� C 3.0 DVD/MPEG2 decoder" } , - { 0x16EC, 0x0116, "RTL8169S", "RealTek 8169S chip" } , - { 0x16EC, 0x1007, "0637", "U.S. Robotics 56K Win INT" } , - { 0x16EC, 0x2013, "11323A", "U.S. Robotics 56K Voice Host Int" } , - { 0x16EC, 0x2F00, "USRobotics 5660A - Internal Soft Modem", "http://www.usr.com/support/product-template.asp?prod=5660a" } , - { 0x16EC, 0x2f12, "E129336-1", "U.S.Robotic (A- Modem/PCI)" } , - { 0x16EC, 0x3685, "???", "Wireless Access Adapter Model 022415" } , - { 0x16EC, 0x5685, "E129336-1", "U.S. Robotics 56K Voice Host Int (A-Modem/ PCI)" } , - { 0x003D, 0x00D1, "mx98715/25", "i740 PCI" } , - { 0x0E11, 0x0001, "", "PCI to EISA Bridge" } , - { 0x0E11, 0x0002, "ISA Bridge", " [URL=http://bjlsgpvs.com]zyqdruqt[/URL] pkooxpbn http://khmycdty.com znrqsyvm syeowswq " } , - { 0x13D0, 0x2200, "", "" } , - { 0x13D1, 0xAB02, "", "" } , - { 0x13D1, 0xAB03, "", "" } , - { 0x13D1, 0xAB06, "FE2000VX", "CardBus /Atelco Fibreline Ethernet Adptr" } , - { 0x13D1, 0xAB08, "SMC8035TX", "EZ Card� 10/100 Fast Ethernet CardBus Adapter" } , - { 0x13D7, 0x8086, "8086", "toshiba" } , - { 0x13D8, 0x1000, "XQ11800FP", "XaQti 1000Mbit/sec Gbit Ethernet Controller" } , - { 0x106B, 0x0001, "Bandit", "PowerPC Host-PCI Bridge" } , - { 0x106B, 0x0002, "Grand Central", "I/O Controller" } , - { 0x106B, 0x0003, "Control Video", "" } , - { 0x106B, 0x0004, "PlanB", "Video-in" } , - { 0x106B, 0x0007, "OHare", "I/O Controller" } , - { 0x106B, 0x000C, "", "" } , - { 0x106B, 0x000E, "Hydra", "Mac I/O Controller" } , - { 0x106B, 0x0010, "Heathrow", "Mac I/O Controller" } , - { 0x106B, 0x0017, "Paddington", "Mac I/O Controller" } , - { 0x106B, 0x0018, "UniNorth", "FireWire Controller" } , - { 0x106B, 0x001F, "UniNorth", "Host-PCI bridge" } , - { 0x106B, 0x0020, "UniNorth", "AGP interface" } , - { 0x106B, 0x0026, "Pangea", "USB Interface" } , - { 0x106B, 0x0027, "Pangea", "AGP interface" } , - { 0x106B, 0x002D, "UniNorth 1.5", "AGP Bridge" } , - { 0x106B, 0x002E, "UniNorth 1.5", "PCI Bridge" } , - { 0x106B, 0x002F, "UniNorth 1.5", "Internal PCI" } , - { 0x106B, 0x0030, "UniNorth/Pangea", "FireWire Controller" } , - { 0x106B, 0x003B, "Intrepid", "Integrated ATA Controller" } , - { 0x106B, 0x003F, "OHCI", "OHCI Controller" } , - { 0x106B, 0x004f, "Shasta", "Mac I/O controler" } , - { 0x106B, 0x0050, "Shasta", "IDE controler" } , - { 0x106B, 0x0051, "Shasta", "Sungem ethernet controler" } , - { 0x106B, 0x0052, "Shasta", "Firewire controler" } , - { 0x106B, 0x0053, "Shasta", "PCI Bridge" } , - { 0x106B, 0x0054, "Shasta", "PCI Bridge" } , - { 0x106B, 0x0055, "Shasta", "PCI Bridge" } , - { 0x106B, 0x0058, "U3L", "AGP Bridge" } , - { 0x106C, 0x8801, "", "Dual Pentium ISA/PCI Motherboard" } , - { 0x106C, 0x8802, "P54C Tr8", "PowerPC ISA/PCI Motherboard" } , - { 0x106C, 0x8803, "", "Dual Window Graphics Accelerator" } , - { 0x106C, 0x8804, "ht019a", "PCI LAN Controller" } , - { 0x106C, 0x8805, "", "100-BaseT LAN Controller" } , - { 0x106E, 0x4362, "88E8053", "Yukon PCI-E Gigabit Ethernet Controller (copper)" } , - { 0x1657, 0x0646, "BRE040", "Brocade 400 series PCIe HBA" } , - { 0x1073, 0x0001, "", "3D graphics Cntrlr" } , - { 0x1073, 0x0002, "YGV615", "RPA3 3D-Graphics Controller" } , - { 0x1073, 0x0003, "00011179", "" } , - { 0x1073, 0x0004, "YMF754B", "PCI Audio Controller" } , - { 0x1073, 0x0005, "DS1", "DS1 Audio" } , - { 0x1073, 0x0006, "DS1", "DS1 Audio" } , - { 0x1073, 0x0008, "DS1", "DS1 Audio" } , - { 0x1073, 0x000A, "YMF740", "DS-1L PCI Audio Controller" } , - { 0x1073, 0x000C, "YMF740C", "DS-1L PCI audio controller" } , - { 0x1073, 0x000D, "YMF724F", "Yamaha Onboard Sound System" } , - { 0x1073, 0x0010, "YMF744B-V", "DS-1 PCI audio controller" } , - { 0x1073, 0x0012, "YMF754B", "DS-1E PCI Audio Controller" } , - { 0x1073, 0x0020, "744", "DS-1 Audio" } , - { 0x1073, 0x1000, "SW1000XG", "Sound system" } , - { 0x1073, 0x2000, "DS2416", "Digital Mixing Card" } , - { 0x1074, 0x4E78, "82C500/1", "Nx586 Chipset" } , - { 0x1077, 0x1016, "ISP10160", "Single Channel Ultra3 SCSI Processor" } , - { 0x1077, 0x1020, "ISP1040B/1020A", "Fast-wide SCSI - Sparc PCI" } , - { 0x1077, 0x1022, "ISP1022A", "Fast-wide SCSI" } , - { 0x1077, 0x1080, "ISP1080", "SCSI Host Adapter" } , - { 0x1077, 0x1216, "ISP12160", "Dual Channel Ultra3 SCSI Processor" } , - { 0x1077, 0x1240, "ISP1240", "SCSI Host Adapter" } , - { 0x1077, 0x1280, "ISP1280", "SCSI Host Adapter" } , - { 0x1077, 0x2020, "ISP2020A", "Fast!SCSI Basic Adapter" } , - { 0x1077, 0x2100, "ISP2100", "64-bit Fibre Channel Adapter" } , - { 0x1077, 0x2200, "ISP2200", "PCI Fibre Channel Adapter" } , - { 0x1077, 0x2300, "ISP 2300", "64-bit PCI FC-AL Adapter" } , - { 0x1077, 0x2312, "ISP 2312", "Fibre Channel Adapter" } , - { 0x1077, 0x2422, "ISP2422", "QLogic PCI to Fibre Channel Host Adapter for QLA2460" } , - { 0x1077, 0x2432, "ISP2432", "Dual Channel 4G PCIe Fibre Channel Adapter" } , - { 0x1077, 0x3010, "n/a", "n/a" } , - { 0x1077, 0x4000, "", "" } , - { 0x1077, 0x4010, "", "" } , - { 0x1077, 0x6422, "EP2422", "4-Gbps Fibre Channel to PCI-X 2.0 266MHz controller for Embedded Applications" } , - { 0x1077, 0x6432, "EP2432", "4-Gbps Fibre Channel to PCIe controller for Embedded Applications" } , - { 0x1078, 0x0000, "Cx5520", "ISA Bridge" } , - { 0x1078, 0x0001, "MediaGXm", "Cyrix Integrated CPU" } , - { 0x1078, 0x0002, "Cx5520", "ISA Bridge" } , - { 0x1078, 0x0100, "Cx5530", "ISA bridge" } , - { 0x1078, 0x0101, "Cx5530", "SMI status and ACPI timer" } , - { 0x1078, 0x0102, "Cx5530", "IDE Controller" } , - { 0x1078, 0x0103, "Cx5530", "XpressAUDIO" } , - { 0x1078, 0x0104, "Cx5530", "Video Controller" } , - { 0x1078, 0x0400, "ZFMicro", "CPU to PCI Bridge" } , - { 0x1078, 0x0401, "ZFMicro", "Power Management Controller" } , - { 0x1078, 0x0402, "ZFMicro", "IDE Controller" } , - { 0x1078, 0x0403, "ZFMicro", "Expansion Bus" } , - { 0x1079, 0x0d01, "", "" } , - { 0x544C, 0x0350, "", "" } , - { 0x107D, 0x0000, "P86C850", "Graphic GLU-Logic" } , - { 0x107E, 0x0001, "FLIPPER", "FRED Local Bus I/F to PCI Peripheral" } , - { 0x107E, 0x0002, "", "100 vg anylan Cntrlr" } , - { 0x107E, 0x0004, "5526", "Fibre Channel Host Adapter" } , - { 0x107E, 0x0005, "x526", "Fibre Channel Host Adapter" } , - { 0x107E, 0x0008, "4575/5525/5575/6575", "(i)chipSAR+ 155 MBit ATM controller" } , - { 0x107E, 0x9003, "5535-4P-BRI-ST", "" } , - { 0x107E, 0x9007, "5535-4P-BRI-U", "" } , - { 0x107E, 0x9008, "5535-1P-SR", "" } , - { 0x107E, 0x900C, "5535-1P-SR-ST", "" } , - { 0x107E, 0x900E, "5535-1P-SR-U", "" } , - { 0x107E, 0x9011, "5535-1P-PRI", "" } , - { 0x107E, 0x9013, "5535-2P-PRI", "" } , - { 0x107E, 0x9023, "5535-4P-BRI-ST", "" } , - { 0x107E, 0x9027, "5536-4P-BRI-U", "" } , - { 0x107E, 0x9031, "5535-1P-PRI", "" } , - { 0x107E, 0x9033, "5536-2P-PRI", "Adapter" } , - { 0x107E, 0x9060, "6535", "CompactPCI T1/E1/J1Communications Ctrlr" } , - { 0x107E, 0x9070, "4538", "PMC T1/E1/J1 Communications Controller" } , - { 0x107E, 0x9080, "4532-002/005", "PMC ATM Over OC-3/STM-1 Comm Controller" } , - { 0x107E, 0x9081, "4532-001/004", "PMC ATM Over OC-3/STM-1 Comm Controller" } , - { 0x107E, 0x9082, "4532-000/003", "PMC ATM Over OC-3/STM-1 Comm Controller" } , - { 0x107E, 0x9090, "107", "PMC ATM Over T3/E3 Communications Ctrlr" } , - { 0x107E, 0x90A0, "4539", "PMC Quad T1/E1/J1 Communications Ctrlr" } , - { 0x107F, 0x0802, "SL82C105", "EIDE Ctrlr" } , - { 0x107F, 0x0803, "", "EIDE Bus Master Controller" } , - { 0x107F, 0x0806, "", "EIDE Controller" } , - { 0x107F, 0x2015, "", "EIDE Controller" } , - { 0x1080, 0x0600, "82C596/9", "CPU to PCI & PCI to ISA Bridge" } , - { 0x1080, 0xC691, "Cypress CY7c68001", "AN2131QC 0230" } , - { 0x1080, 0xC693, "82C693", "PCI to ISA Bridge" } , - { 0x1081, 0x0D47, "2330", "Radius PCI to NuBUS Bridge" } , - { 0x1083, 0x0001, "FR710", "PCI Enhanced IDE Adapter" } , - { 0x1083, 0x0613, "", "Host Bridge" } , - { 0x1085, 0x0001, "UsbDgn", "Datalaster Interface for OBD automotive" } , - { 0x1087, 0x9200, "", "" } , - { 0x108A, 0x0001, "Model 617", "PCI-VME Bus Adapter" } , - { 0x108A, 0x0010, "Model 618", "VME Bridge" } , - { 0x108A, 0x0040, "dataBLIZZARD", "" } , - { 0x108A, 0x3000, "Model 2106", "VME Bridge" } , - { 0x108D, 0x0001, "OC-3136/37", "Token-Ring 16/4 PCI Adapter" } , - { 0x108D, 0x0002, "OC-3139f", "Fastload 16/4 PCI/III Token Ring Adapter" } , - { 0x108D, 0x0004, "OC-3139/40", "RapidFire Token Ring 16/4 Adapter" } , - { 0x108D, 0x0005, "OC-3250", "GoCard Token Ring 16/4 Adapter" } , - { 0x108D, 0x0006, "OC-3530", "RapidFire Token Ring 100 Adapter" } , - { 0x108D, 0x0007, "OC-3141", "RapidFire Token Ring 16/4 Adapter" } , - { 0x108D, 0x0008, "OC-3540", "RapidFire HSTR 100/16/4 Adapter" } , - { 0x108D, 0x000A, "OC-3150", "RapidFire Token-Ring 16/4 PCI Adapter" } , - { 0x108D, 0x0011, "OC-2805", "Ethernet Controller" } , - { 0x108D, 0x0012, "OC-2325", "Ethernet PCI/II 10/100 Controller" } , - { 0x108D, 0x0013, "OC-2183/85", "PCI/II Ethernet Controller" } , - { 0x108D, 0x0014, "OC-2326", "Ethernet PCI/II 10/100 Controller" } , - { 0x108D, 0x0019, "OC-2327/50", "10/100 Ethernet Controller" } , - { 0x108D, 0x0021, "OC-6151/52", "155 Mbit ATM Adapter" } , - { 0x108D, 0x0022, "", "ATM Adapter" } , - { 0x108E, 0x0001, "SPARC EBUS", "" } , - { 0x108E, 0x1000, "PCIO", "PCI Input/Output Controller" } , - { 0x108E, 0x1001, "PCIO", "Happy Meal Ethernet" } , - { 0x108E, 0x1100, "RIO EBUS", "" } , - { 0x108E, 0x1101, "RIO GEM", "" } , - { 0x108E, 0x1102, "RIO 1394", "" } , - { 0x108E, 0x1103, "RIO USB", "" } , - { 0x108E, 0x2BAD, "GEM", "Sun Gigabit Ethernet Card" } , - { 0x108E, 0x5000, "SME2411", "UltraSPARC-IIi Advanced PCI Bridge" } , - { 0x108E, 0x5043, "SunPCI", "Co-processor" } , - { 0x108E, 0x7063, "SunPCi", "PCI card with Intel or AMD processor" } , - { 0x108E, 0x8000, "STP2223BGA", "UPA to PCI Interface (UPA)" } , - { 0x108E, 0x8001, "Schizo", "PCI Bus Module" } , - { 0x108E, 0xA000, "UltraSPARC IIi", "Sabre" } , - { 0x108E, 0xA001, "UltraSPARC IIe", "Hummingbird" } , - { 0x108E, 0xabba, "CE (Cassini Ethernet)", "10/100/1000 Ethernet adapter" } , - { 0x1091, 0x0020, "", "3D Graphics Processor" } , - { 0x1091, 0x0021, "", "3D graphics processor w/texturing" } , - { 0x1091, 0x0040, "", "3D graphics frame buffer" } , - { 0x1091, 0x0041, "", "3D graphics frame buffer" } , - { 0x1091, 0x0060, "", "Proprietary bus Bridge" } , - { 0x1091, 0x00E4, "Powerstorm 4D50T", "" } , - { 0x1091, 0x0720, "", "Motion JPEG Codec" } , - { 0x1092, 0x00A0, "SpeedStar Pro SE", "GUI Accelerator" } , - { 0x1092, 0x00A8, "SpeedStar 64", "GUI Accelerator" } , - { 0x1092, 0x0550, "Viper V550", "" } , - { 0x1092, 0x08D4, "Supra 2260", "WinModem" } , - { 0x1092, 0x094C, "SupraExpress 56i Pro", "SupraExpress 56i Pro" } , - { 0x1092, 0x09C8, "SUP2761", "SupraExpress 56i Pro VCC" } , - { 0x1092, 0x1002, "R6793-12", "RS56-pci" } , - { 0x1092, 0x1092, "Viper V330", "2710a" } , - { 0x1092, 0x6120, "Maximum", "DVD" } , - { 0x1092, 0x8810, "Stealth SE", "GUI Accelerator" } , - { 0x1092, 0x8811, "Stealth 64/SE", "GUI Accelerator" } , - { 0x1092, 0x8880, "Stealth Video", "" } , - { 0x1092, 0x8881, "Stealth Video", "GUI Accelerator" } , - { 0x1092, 0x88B0, "Stealth 64 Video", "GUI Accelerator" } , - { 0x1092, 0x88B1, "Stealth 64 Video", "GUI Accelerator" } , - { 0x1092, 0x88C0, "Stealth 64", "GUI Accelerator" } , - { 0x1092, 0x88C1, "Stealth 64", "GUI Accelerator" } , - { 0x1092, 0x88D0, "Stealth 64", "GUI Accelerator" } , - { 0x1092, 0x88D1, "Stealth 64", "GUI Accelerator" } , - { 0x1092, 0x88F0, "Stealth 64 Video", "GUI Accelerator" } , - { 0x1092, 0x88F1, "Stealth 64 Video", "GUI Accelerator" } , - { 0x1092, 0x9876, "", "Supra Express 56i Pro CW #2" } , - { 0x1092, 0x9999, "Monster Sound", "Diamand Technology DT0398" } , - { 0x1093, 0x0160, "PCI-DIO-96", "data adquisition input and output" } , - { 0x1093, 0x0161, "PCI-1200", "Multifunction data acquisition board" } , - { 0x1093, 0x0162, "PCI-MIO-16XE-50", "24MIO 6-03-2" } , - { 0x1093, 0x1150, "PCI-DIO-32HS", "High Speed Digital I/O Board" } , - { 0x1093, 0x1170, "PCI-MIO-16XE-10", "" } , - { 0x1093, 0x1180, "PCI-MIO-16E-1", "" } , - { 0x1093, 0x1190, "PCI-MIO-16E-4", "" } , - { 0x1093, 0x11B0, "", "" } , - { 0x1093, 0x11C0, "", "" } , - { 0x1093, 0x11D0, "", "" } , - { 0x1093, 0x11E0, "", "" } , - { 0x1093, 0x1270, "PCI-6032E", "Multifunction Data Acquisition Card" } , - { 0x1093, 0x12b0, "PCI-6534", "High Speed DIO" } , - { 0x1093, 0x1310, "PCI-6602", "Data Acquisition Device" } , - { 0x1093, 0x1320, "", "" } , - { 0x1093, 0x1330, "PCI-6031E", "" } , - { 0x1093, 0x1340, "PCI-6033E", "Multifunction Data Acquisition Card" } , - { 0x1093, 0x1350, "PCI-6071E", " NI PCI-6071E Multifunction I/O & NI-DAQ" } , - { 0x1093, 0x1360, "", "" } , - { 0x1093, 0x17D0, "PCI-6503", "" } , - { 0x1093, 0x18B0, "", "" } , - { 0x1093, 0x28b0, "NI 6014", "I/O Terminal NI-DAQ (Legacy) and NI-DAQmx" } , - { 0x1093, 0x2A60, "PCI-6023E", "" } , - { 0x1093, 0x2A70, "PCI-6024E", "Multifunction Data Acquisition Card" } , - { 0x1093, 0x2A80, "PCI-6025E", "Multifunction Data Acquisition Card" } , - { 0x1093, 0x2B20, "", "" } , - { 0x1093, 0x2C80, "PCI-6035E", "" } , - { 0x1093, 0x2CA0, "", "" } , - { 0x1093, 0x70af, "PCI-6221", "16-Bit, 250 kS/s, 16 Analog Inputs" } , - { 0x1093, 0x70b8, "NI PCI-6251", "Multifunction DAQ Device" } , - { 0x1093, 0xB001, "IMAQ-PCI-1408", "" } , - { 0x1093, 0xB011, "IMAQ-PXI-1408", "" } , - { 0x1093, 0xB021, "IMAQ-PCI-1424", "" } , - { 0x1093, 0xB031, "IMAQ-PCI-1413", "" } , - { 0x1093, 0xB041, "IMAQ-PCI-1407", "" } , - { 0x1093, 0xB051, "IMAQ-PXI-1407", "" } , - { 0x1093, 0xB061, "IMAQ-PCI-1411", "" } , - { 0x1093, 0xB071, "IMAQ-PCI-1422", "" } , - { 0x1093, 0xB081, "IMAQ-PXI-1422", "" } , - { 0x1093, 0xB091, "IMAQ-PXI-1411", "" } , - { 0x1093, 0xC801, "PCI-GPIB", "GPIB Controller Interface Board" } , - { 0x1093, 0xC811, "", "" } , - { 0x1093, 0xC821, "", "" } , - { 0x1093, 0xC831, "", "" } , - { 0x1093, 0xC840, "", "" } , - { 0x1093, 0xd130, "PCI-232/2", "2-port RS-232 Serial Interface Board" } , - { 0x1095, 0x0240, "SIL3112", "SATA/Raid controller(2XSATA150)" } , - { 0x1095, 0x0242, "SIL3132", "SATAII/Raid controller" } , - { 0x1095, 0x0244, "SIL3132", "eSATA/Raid controller" } , - { 0x1095, 0x0640, "PCI0640A/B", "EIDE Ctrlr" } , - { 0x1095, 0x0641, "PCI0640", "PCI EIDE Adapter with RAID 1" } , - { 0x1095, 0x0642, "PCI0642", "IDE Cntrlr w/RAID 1" } , - { 0x1095, 0x0643, "PCI0643", "PCI EIDE controller" } , - { 0x1095, 0x0646, "PCI0646", "bus master IDE" } , - { 0x1095, 0x0647, "PCI0647", "9738" } , - { 0x1095, 0x0648, "PCI-648", "Bus Master Ultra DMA PCI-IDE/ATA Chip" } , - { 0x1095, 0x0649, "PCI-649", "PATA100 RAID Controller" } , - { 0x1095, 0x0650, "PBC0650A", "Fast SCSI-II Ctrlr" } , - { 0x1095, 0x0670, "USB0670", "PCI-USB" } , - { 0x1095, 0x0673, "USB0673", "PCI-USB ASIC" } , - { 0x1095, 0x0680, "SiI 0680", "PATA133 Controller/RAID Controller" } , - { 0x1095, 0x1392, "1392", "INTEL HDMI AUDIO" } , - { 0x1095, 0x2455, "SI3124", "SATALink 4-Port PCI-X Host Controller" } , - { 0x1095, 0x3112, "SIL3112", "SATA/Raid controller(2XSATA150)" } , - { 0x1095, 0x3114, "Sil 3114", "SATALink/SATARaid Controller" } , - { 0x1095, 0x3124, "SiI 3124", "PCI-X to Serial ATA Controller" } , - { 0x1095, 0x3132, "SiI 3132", "PCI Express (1x) to 2 Port SATA300" } , - { 0x1095, 0x3512, "Sil 3512", "SATALink/SATARaid Controller" } , - { 0x1095, 0x3531, "3531", "SiI 3531 SATA Controller" } , - { 0x1096, 0x1106, "0x3059", "0x47204005&RE" } , - { 0x1097, 0x0038, "", "EIDE Controller (single FIFO)" } , - { 0x1098, 0x0001, "QD8500", "EIDE Controller" } , - { 0x1098, 0x0002, "QD8580", "EIDE Controller" } , - { 0x109A, 0x8280, "0x8280", "0x8280" } , - { 0x109E, 0x0350, "BT848KPF", "Bt848AKPF video decoder" } , - { 0x109E, 0x0350, "Bt878", "Multimedia Video Controller" } , - { 0x109E, 0x0351, "B t878 khf", "tc card" } , - { 0x109E, 0x0369, "Bt878fusion 878a", "Video Capture" } , - { 0x109E, 0x036C, "thık", "jfgj" } , - { 0x109E, 0x036E, "878Asad", "SVR-2000 V1.02" } , - { 0x109E, 0x036F, "Bt878", "Video Capturee" } , - { 0x109E, 0x0370, "Bt880", "Video Capture (10 bit High qualtiy cap)" } , - { 0x109E, 0x0878, "7610144D&REV_02\4&1F7DBC9F&0&09F0", "TV Video Capture" } , - { 0x109E, 0x0879, "Bt879khf", "Video Capture (Audio Section)" } , - { 0x109E, 0x0880, "Bt880", "Video Capture (Audio Section)" } , - { 0x109E, 0x109E, "Brooktree Corp BT848 SVR-2000 V1.02", "Multimedia Video Controller" } , - { 0x109E, 0x2115, "BtV 2115 Mera Lun", "BtV Mediastream Controller 9x" } , - { 0x109E, 0x2125, "BtV 2125", "BtV Mediastream Controller" } , - { 0x109E, 0x2164, "BtV 2164", "Display Adapter" } , - { 0x109E, 0x2165, "BtV 2165", "MediaStream Controller" } , - { 0x109E, 0x36e, "878a", "25878-13" } , - { 0x109E, 0x36E, "Bt360 MediaStream Controller", "Brooktree Corp" } , - { 0x109E, 0x36E, "CONEXANT FUSION 878A 25878-13 E349764.7", "conexant 878a" } , - { 0x109E, 0x8230, "BtV 8230", "ATM Segment/Reassembly Controller (SRC)" } , - { 0x109E, 0x8472, "Bt8471/72", "32/64-channel HDLC Controllers" } , - { 0x109E, 0x8474, "Bt8474", "128-channel HDLC Controller" } , - { 0x10A4, 0X5969, "", "" } , - { 0x9902, 0x0001, "SG2010", "PCI-to-PCI Bridge" } , - { 0x9902, 0x0002, "SG2010", "PCI to high speed serial bridge" } , - { 0x9902, 0x0003, "SG1010", "6 port serial switch /PCI-to-PCI bridge" } , - { 0x10A8, 0x0000, "?", "64-bit GUI Accelerator" } , - { 0x10A9, 0x0004, "O2 MACE", "" } , - { 0x10A9, 0x0005, "RAD Audio", "" } , - { 0x10A9, 0x0006, "HPCEX", "" } , - { 0x10A9, 0x0007, "RPCEX", "" } , - { 0x10A9, 0x0008, "DiVO VIP", "" } , - { 0x10A9, 0x0009, "Alteon", "Gigabit Ethernet" } , - { 0x10A9, 0x0010, "AMP", "Video I/O" } , - { 0x10A9, 0x0011, "GRIP", "" } , - { 0x10A9, 0x0012, "SGH PSHAC GSN", "" } , - { 0x10A9, 0x1001, "Magic Carpet", "" } , - { 0x10A9, 0x1002, "Lithium", "" } , - { 0x10A9, 0x1003, "Dual JPEG 1", "" } , - { 0x10A9, 0x1004, "Dual JPEG 2", "" } , - { 0x10A9, 0x1005, "Dual JPEG 3", "" } , - { 0x10A9, 0x1006, "Dual JPEG 4", "" } , - { 0x10A9, 0x1007, "Dual JPEG 5", "" } , - { 0x10A9, 0x1008, "Cesium", "" } , - { 0x10A9, 0x2001, "", "Fibre Channel" } , - { 0x10A9, 0x2002, "ASDE", "" } , - { 0x10A9, 0x8001, "O2 1394", "" } , - { 0x10A9, 0x8002, "G-net NT", "" } , - { 0x10AB, 0x1005, "USBVID_0000&PID_00005&5657949&0&8", "USB Bluetooth" } , - { 0x10AD, 0x0001, "W83769F", "EIDE Ctrlr" } , - { 0x10AD, 0x0103, "sl82c103", "PCI-ide mode 4.5 Cntrlr" } , - { 0x10AD, 0x0105, "W83789F", "Sonata bus master PCI-IDE controller" } , - { 0x10AD, 0x0565, "W83C553F", "PCI/ISA bridge" } , - { 0x10B5, 0x0324, "", "" } , - { 0x10B5, 0x0480, "IOP 480", "Integrated PowerPC I/O Processor" } , - { 0x10B5, 0x0960, "PCI 9080RDK-960", "PCI Reference Design Kit for PCI 9080" } , - { 0x10B5, 0x1030, "Gazel R685", "ISDN card" } , - { 0x10B5, 0x1054, "Gazel R697", "dual channel ISDN card" } , - { 0x10B5, 0x1078, "PCI 9050", "Vision Systems VScom PCI-210" } , - { 0x10B5, 0x1103, "PCI 9050", "Vision Systems VScom PCI-200" } , - { 0x10B5, 0x1146, "PCI 9050", "Vision Systems VScom PCI-010S" } , - { 0x10B5, 0x1147, "PCI 9050", "Vision Systems VScom PCI-020S" } , - { 0x10B5, 0x1151, "Gazel R753", "ISDN card" } , - { 0x10B5, 0x1152, "Gazel R753", "ISDN card" } , - { 0x10B5, 0x2724, "", "Thales PCSM Security Card" } , - { 0x10B5, 0x3001, "plx9030", "gpscard" } , - { 0x10B5, 0x5406, "PCI RDK9054-LITE", "PCI Reference Design Kit for PLX PCI 9054" } , - { 0x10B5, 0x5601, "PCI 9056", "32-bit; 66MHz PCI Bus Master I/O Accelerator, 17 x 17mm FPBGA" } , - { 0x10B5, 0x6520, "PCI6520", "PCI-X to PCI-X Bridge" } , - { 0x10B5, 0x8111, "PEX 8111, PEX 8311", "1 Lane PCI Express to PCI bridge (PEX8111); 1 Lane PCI Express to Generic Local Bus bridge (PEX8311)" } , - { 0x10B5, 0x8112, "PEX8112", "1 Lane PCI Express to PCI bridge" } , - { 0x10B5, 0x8509, "PEX8509", "8-lane PCI-Express Switch" } , - { 0x10B5, 0x8516, "PEX 8516", "Versatile PCI Express Switch" } , - { 0x10B5, 0x8518, "PEX8518-AB25BI", "PLX PCI-e switch" } , - { 0x10B5, 0x8532, "PEX 8532", "Versatile PCI Express Switch" } , - { 0x10B5, 0x8548, "8548", "48-lane PCIe switch" } , - { 0x10B5, 0x9030, "PCI 9030", "PCI SMARTarget I/O Accelerator" } , - { 0x10B5, 0x9036, "PCI9036", "Interface chip - value 1k" } , - { 0x10B5, 0x9050, "PCI 9050", "Target PCI Interface Chip - value 1k" } , - { 0x10B5, 0x9052, "PCI 9052", "PCI 9052 Target PLX PCI Interface Chip" } , - { 0x10B5, 0x9054, "PCI 9054", "PCI I/O Accelerator" } , - { 0x10B5, 0x9056, "PCI9056", "32-bit, 66 MHz PCI Bus-Mastering I/O Accelerator for PowerQUICC and Generic 32-bit, 66 MHz Local Bus" } , - { 0x10B5, 0x9060, "PCI9060", "PCI Bus Master Interface Chip" } , - { 0x10B5, 0x906D, "PCI 9060SD", "PCI Bus Master Interface Chip" } , - { 0x10B5, 0x906E, "PCI 9060ES", "PCI Bus Master Interface Chip" } , - { 0x10B5, 0x9080, "PCI 9080", "High performance PCI to Local Bus chip" } , - { 0x10B6, 0x0001, "Smart 16/4", "Ringnode (PCI1b)" } , - { 0x10B6, 0x0002, "Smart 16/4", "Ringnode (PCIBM2/CardBus)" } , - { 0x10B6, 0x0003, "Smart 16/4", "Ringnode" } , - { 0x10B6, 0x0004, "", "Smart 16/4 Ringnode Mk1 (PCIBM1)" } , - { 0x10B6, 0x0006, "", "16/4 CardBus Adapter (Eric 2)" } , - { 0x10B6, 0x0007, "Presto PCI", "" } , - { 0x10B6, 0x0009, "", "Smart 100/16/4 PCi-HS Ringnode" } , - { 0x10B6, 0x000A, "", "Smart 100/16/4 PCI Ringnode" } , - { 0x10B6, 0x000B, "", "16/4 CardBus Adapter Mk2" } , - { 0x10B6, 0x1000, "Horizon", "ATM adapter" } , - { 0x10B6, 0x1001, "Ambassador", "ATM adapter" } , - { 0x10B6, 0x1002, "Ambassador", "ATM Adapter" } , - { 0x10B7, 0x0001, "3C985", "1000BaseSX Gigabit Etherlink" } , - { 0x10B7, 0x0013, "3com p/n: 3CRDAG675", "3Com11a/b/g Wireless PCI Adapter " } , - { 0x10B7, 0x1000, "3C905CX-TXNM", "3COM 3C905CX-TXNM with 40-0664-003 ASIC" } , - { 0x10B7, 0x1006, "14e4:1645", "Broadcom Corporation NetXtreme BCM5701 Gigabit Ethernet" } , - { 0x10B7, 0x1007, "3C556", "V.90 Mini-PCI Modem" } , - { 0x10B7, 0x1700, "3C940", "Gigabit Ethernet PCI CODEC" } , - { 0x10B7, 0x1F1F, "3CRWE777A", "AirConnect Wireless LAN PCI Card" } , - { 0x10B7, 0x3390, "3C339", "Token Link Velocity" } , - { 0x10B7, 0x3590, "3C359", "TokenLink Velocity XL Adapter" } , - { 0x10B7, 0x4500, "3C450", "Cyclone" } , - { 0x10B7, 0x5055, "3C555", "Laptop Hurricane" } , - { 0x10B7, 0x5057, "3C575", "Megahertz 10/100 LAN CardBus PC Card" } , - { 0x10B7, 0x5157, "3C575B", "Megahertz 10/100 LAN CardBus PC Card" } , - { 0x10B7, 0x5257, "3CCFE575CT", "Cyclone Fast Ethernet CardBus PC Card" } , - { 0x10B7, 0x5900, "3C590", "Ethernet III Bus Fast PCI" } , - { 0x10B7, 0x5920, "3C592", "PCI/EISA 10Mbps Demon/Vortex" } , - { 0x10B7, 0x5950, "3C595", "Fast EtherLink PCI TX" } , - { 0x10B7, 0x5951, "3C595", "Fast EtherLink PCI T4" } , - { 0x10B7, 0x5952, "3C595", "Fast EtherLink PCI MII" } , - { 0x10B7, 0x5970, "3C597", "PCI/EISA Fast Demon/Vortex" } , - { 0x10B7, 0x5B57, "3C595", "Megahertz 10/100 LAN CardBus" } , - { 0x10B7, 0x6055, "3C556", "10/100 Fast Ethernet MiniPCI Adapter" } , - { 0x10B7, 0x6056, "3CN3AC1556B", "MiniPCI 10/100 Ethernet+Modem56k (see devid:1007)" } , - { 0x10B7, 0x6560, "3CCFE656", "Cyclone CardBus PC Card" } , - { 0x10B7, 0x6561, "FEM656", "10/100 LAN+56K Modem CardBus PC Card" } , - { 0x10B7, 0x6562, "3CCFEM656", "Cyclone CardBus PC Card" } , - { 0x10B7, 0x6563, "FEM656B", "10/100 LAN+56K Modem CardBus PC Card" } , - { 0x10B7, 0x6564, "3CCFEM656", "Cyclone CardBus PC Card" } , - { 0x10B7, 0x6565, "3CCFEM656C", "Global 10/100 Fast Ethernet+56K Modem" } , - { 0x10B7, 0x7646, "3CSOHO100B-TX", "Hurricane" } , - { 0x10B7, 0x7770, "???", "AirConnect Wireless PCI" } , - { 0x10B7, 0x8811, "", "Token Ring" } , - { 0x10B7, 0x9000, "3C900-TPO", "Fast Etherlink PCI TPO NIC" } , - { 0x10B7, 0x9001, "3C900-COMBO", "Fast Etherlink XL PCI Combo NIC" } , - { 0x10B7, 0x9004, "3C900-TPO", "EtherLink XL TPO 10Mb" } , - { 0x10B7, 0x9005, "3C900B-COMBO", "Fast Etherlink 10Mbps Combo NIC" } , - { 0x10B7, 0x9006, "3C900B-TPC", "EtherLink XL TPC" } , - { 0x10B7, 0x900A, "3C900B-FL", "EtherLink PCI Fiber NIC" } , - { 0x10B7, 0x9050, "3C905B - Combo", "Fast Etherlink XL PCI 10/100" } , - { 0x10B7, 0x9051, "3C905-T4", "Fast Etherlink XL 10/100" } , - { 0x10B7, 0x9055, "3C905-TX", "Fast Etherlink 10/100 PCI TX NIC" } , - { 0x10B7, 0x9056, "3C905B-T4", "Fast EtherLink XL 10/100" } , - { 0x10B7, 0x9058, "3C905B-COMBO", "Deluxe EtherLink 10/100 PCI Combo NIC" } , - { 0x10B7, 0x905A, "3C905B-FX", "Fast EtherLink 100 Fiber NIC" } , - { 0x10B7, 0x9200, "3C905 CX-TX-M", "Fast EtherLink for PC Management NIC" } , - { 0x10B7, 0x9201, "3C920B-EMB", "Integrated Fast Ethernet Controller" } , - { 0x10B7, 0x9202, "3C920B-EMB", "3C920B-EMB 3Com + Realtek 8201L" } , - { 0x10B7, 0x9210, "3C920B-EMB-WNM", "Integrated Fast Ethernet Controller" } , - { 0x10B7, 0x9300, "3csoho100b-tx", "3ComSOHO100B-TX" } , - { 0x10B7, 0x9800, "3C980-TX", "Fast EtherLink XL Server Adapter2" } , - { 0x10B7, 0x9805, "3C980-TX", "Python-T 10/100baseTX NIC" } , - { 0x10B7, 0x9902, "3CR990-TX-95", "EtherLink 10/100 PCI with 3XP Processor" } , - { 0x10B7, 0x9903, "3CR990-TX-97", "EtherLink 10/100 PCI with 3XP Processor" } , - { 0x10B7, 0x9905, "3C990B-FX", "100FX PCI Server NIC w/3XP" } , - { 0x10B7, 0x9908, "3CR990SVR95", "EtherLink 10/100 Server PCI with 3XP" } , - { 0x10B7, 0x9909, "3CR990SVR97", "EtherLink 10/100 Server PCI with 3XP" } , - { 0x10B7, 0xD004, "3C900B-TPO", "EtherLink XL PCI" } , - { 0x10B8, 0x0005, "LAN83C170QF/171", "EPIC/XF 10/100 Mbps Fast Ethernet Ctrlr" } , - { 0x10B8, 0x0006, "LAN83C175", "EPIC/C Ethernet CardBus Integrated Ctrlr" } , - { 0x10B8, 0x1000, "37C665", "FDC" } , - { 0x10B8, 0x1001, "37C922", "FDC" } , - { 0x10B8, 0xA011, "83C170QF", "Fast ethernet controller" } , - { 0x10B8, 0xB106, "SMC34C90", "CardBus Controller" } , - { 0x10B9, 0x0101, "CMI8338/C3DX", "PCI Audio Device (OEM)" } , - { 0x10B9, 0x0102, "CMI8338/C3DX", "PCI Audio Device (OEM)" } , - { 0x10B9, 0x0111, "CMI8738/C3DX", "C-Media Audio Device (OEM)" } , - { 0x10B9, 0x0780, "???", "Multi-IO Card" } , - { 0x10B9, 0x0782, "???", "Multi-IO Card" } , - { 0x10B9, 0x10b9, "ALI M5273 A1", "0539 TS05 CKB42321000B" } , - { 0x10B9, 0x1435, "M1435", "VL Bridge" } , - { 0x10B9, 0x1445, "M1445", "CPU to PCI & PCI to ISA Bridge w/EIDE" } , - { 0x10B9, 0x1449, "M1449", "ISA Bridge" } , - { 0x10B9, 0x1451, "M1451", "Pentium CPU to PCI Bridge" } , - { 0x10B9, 0x1461, "M1461", "P54C Chipset" } , - { 0x10B9, 0x1489, "M1489", "486 PCI Chipset" } , - { 0x10B9, 0x1511, "M1511", "Aladdin 2 Host Bridge" } , - { 0x10B9, 0x1513, "M1513", "Aladdin 2 South Bridge" } , - { 0x10B9, 0x1521, "M1521", "Bios" } , - { 0x10B9, 0x1523, "M1523", "ISA Bridge" } , - { 0x10B9, 0x1533, "M1535+", "PCI South Bridge" } , - { 0x10B9, 0x1535, "M1535x", "ISA Bridge" } , - { 0x10B9, 0x1541, "M1541", "Aladdin V AGPset Host Bridge" } , - { 0x10B9, 0x1543, "M1543 a1", "Aladdin V chipset South Bridge" } , - { 0x10B9, 0x1561, "M1561", "North Bridge" } , - { 0x10B9, 0x1563, "M1563", "South Bridge with Hypertransport Support" } , - { 0x10B9, 0x1632, "M1632", "North Bridge" } , - { 0x10B9, 0x1641, "M1641", "CPU to PCI Bridge" } , - { 0x10B9, 0x1644, "M1644", "AGP System Controller" } , - { 0x10B9, 0x1646, "M1646", "AGP System Controller" } , - { 0x10B9, 0x1647, "M1647", "CPU to PCI Bridge" } , - { 0x10B9, 0x1651, "M1651", "CPU to PCI Bridge" } , - { 0x10B9, 0x1661, "M1661", "AGP System Controller" } , - { 0x10B9, 0x1667, "M1667", "AGP System Controller" } , - { 0x10B9, 0x1671, "M1671", "Super P4 Nouth Bridge" } , - { 0x10B9, 0x1672, "M1672", "AGP System Controller" } , - { 0x10B9, 0x1681, "M1681", "P4 Nouth Bridge with HyperTransport" } , - { 0x10B9, 0x1687, "M1687", "K8 North Bridge with HyperTransport" } , - { 0x10B9, 0x3141, "M3141", "GUI Accelerator" } , - { 0x10B9, 0x3143, "M3143", "GUI Accelerator" } , - { 0x10B9, 0x3145, "M3145", "GUI Accelerator" } , - { 0x10B9, 0x3147, "M3147", "GUI Accelerator" } , - { 0x10B9, 0x3149, "M3149", "GUI Accelerator" } , - { 0x10B9, 0x3151, "M3151", "GUI Accelerator" } , - { 0x10B9, 0x3307, "M3307", "MPEG-1 Decoder" } , - { 0x10B9, 0x3309, "M3309", "MPEG Decoder" } , - { 0x10B9, 0x5212, "M4803", "" } , - { 0x10B9, 0x5215, "MS4803", "EIDE Ctrlr" } , - { 0x10B9, 0x5217, "m5217h", "I/O (?)" } , - { 0x10B9, 0x5219, "?", "Ali M5219 PCI BUS MASTER IDE Controller" } , - { 0x10B9, 0x5225, "M5225", "IDE Controller" } , - { 0x10B9, 0x5228, "M1563", "M5228 PATA/RAID Controller" } , - { 0x10B9, 0x5229, "M5229 Southbridge", "EIDE Controller" } , - { 0x10B9, 0x5229, "?", "Ali EIDE" } , - { 0x10B9, 0x5229, "?", "PATA 33" } , - { 0x10B9, 0x5229, "?", "PATA 66" } , - { 0x10B9, 0x5229, "?", "PATA 100" } , - { 0x10B9, 0x5229, "?", "PATA 133" } , - { 0x10B9, 0x5235, "M1621", "I/O Controller" } , - { 0x10B9, 0x5236, "M5273", "EHCI USB 2.0" } , - { 0x10B9, 0x5237, "M5273 A1 for windows 98", "OpenHCI 1.1 USB to 2.0" } , - { 0x10B9, 0x5239, "527210B9", "USB EHCI2.0 Controller" } , - { 0x10B9, 0x5249, "M5249", "HyperTransport to PCI Bridge" } , - { 0x10B9, 0x5251, "M5251", "IEEE P1394 OpenHCI 1.0 Controller" } , - { 0x10B9, 0x5253, "M5253", "IEEE P1394 OpenHCI 1.0 Controller" } , - { 0x10B9, 0x5261, "M5261", "Ethernet Controller" } , - { 0x10B9, 0x5263, "Albatron K8ULTRA-U Pro", "ULi PCI Fast Ethernet Controller" } , - { 0x10B9, 0x5281, "M1565/1566", "ALI M5281/5283 SATA/RAID Controller" } , - { 0x10B9, 0x5287, "ULI M1573", "SATA/Raid controller" } , - { 0x10B9, 0x5288, "ULI M1575/M1697 ", "M5288 SATA/Raid controller" } , - { 0x10B9, 0x5289, "ULI M1567/M1689 ", "M5289 SATA/Raid controller" } , - { 0x10B9, 0x5450, "65525", "Agere Systems AC97 Modem" } , - { 0x10B9, 0x5451, "M5451", "Ali Audio Accelerator" } , - { 0x10B9, 0x5455, "M1563M Southbridge", "AC'97 Audio Controller" } , - { 0x10B9, 0x5457, "M1563M", "AC97 Modem controller" } , - { 0x10B9, 0X5459, "MDV92XP NetoDragon", "PCI Soft Modem V92 NetoDragon" } , - { 0x10B9, 0x5461, "M5461", "High Definition Audio Controller" } , - { 0x10B9, 0x5471, "M1563M Southbridge", "Memory Stick Host" } , - { 0x10B9, 0x5473, "M1563M Southbridge", "MMC/SD controller" } , - { 0x10B9, 0x7101, "M7101", "Power Management Controller" } , - { 0x10B9, 0x7471, "M1563M Southbridge", "Memory Stick Host" } , - { 0x10B9, 0x9876, "mdv92xp", "xhcth700000b" } , - { 0x10BA, 0x0304, "", "GUI Accelerator" } , - { 0x10BD, 0x0803, " MYSON Technology Inc SURECOM EP-320X-S 100/10M Et", "Ethernet PCI Adapter" } , - { 0x10BD, 0x0E34, "NE34", "Ethernet Adapter (NE2000 PCI clone)" } , - { 0x10BD, 0x5240, "0055", "IDE Cntrlr" } , - { 0x10BD, 0x5241, "", "PCMCIA Bridge" } , - { 0x10BD, 0x5242, "", "General Purpose Cntrlr" } , - { 0x10BD, 0x5243, "00000000", "Bus Cntrlr" } , - { 0x10BD, 0x5244, "", "FCD Cntrlr" } , - { 0x10BD, 0x8139, "surecom EP-320X-R adapter with realtek 8139c chip", "realtek 8139c" } , - { 0x10C3, 0x8920, "5335fn800829", "" } , - { 0x10C3, 0x8925, "", "" } , - { 0x10C4, 0x8363, "s/n124102160", "pci pnp686" } , - { 0x10C8, 0x0004, "", "" } , - { 0x10C8, 0x0000, "", "Graphics Cntrlr" } , - { 0x10C8, 0x0003, "NM2093", "MagicGraph 128ZV Video Controller" } , - { 0x10C8, 0x0004, "NM2160", "MagicGraph 128XD" } , - { 0x10C8, 0x0005, "NM2200", "MagicMedia 256AV" } , - { 0x10C8, 0x0006, "NM2360", "MagicMedia 256ZX/256M6D" } , - { 0x10C8, 0x0016, "NM2380", "MagicMedia 256XL+" } , - { 0x10C8, 0x0025, "NM2230", "MagicMedia 256AV+" } , - { 0x10C8, 0x0083, "NM2097", "Graphic Controller NeoMagic MagicGraph128ZV+" } , - { 0x10C8, 0x8005, "NM2200", "MagicMedia 256AV Audio Device" } , - { 0x10C8, 0x8006, "NM2360", "MagicMedia 256ZX Audio Device" } , - { 0x10C8, 0x8016, "NM2380", "MagicMedia 256XL+ Audio Device" } , - { 0x10CD, 0x1100, "ASC1100", "PCI SCSI Host Adapter" } , - { 0x10CD, 0x1200, "ASC1200", "Fast SCSI-II" } , - { 0x10CD, 0x1300, "ASC-3550b", "ASC-3550b" } , - { 0x10CD, 0x2300, "F914C536", "PCI Ultra Wide SCSI Host Adapter" } , - { 0x10CD, 0x2500, "ASC38C0800/1600", "PCI Ultra 80/160 SCSI Controllers" } , - { 0x10CD, 0x4000, "ASC30C0400", "IEEE-1394 OHCI PCI Controller" } , - { 0x10CF, 0x10C5, "FMV-103", "Serial Parallel Card" } , - { 0x10CF, 0x2001, "MB86605", "PCI SCSI Host Adapter (Fast Wide SCSI-2)" } , - { 0x10CF, 0x2002, "MB86606", "Fast Wide SCSI Controller" } , - { 0x10CF, 0x2005, "MB86974", "10/100 Fast Ethernet Adapter" } , - { 0x10CF, 0x200C, "MB86974", "IEEE1394 OpenHCI Controller" } , - { 0x10CF, 0x2010, "", "OHCI FireWire Controller" } , - { 0x10CF, 0x2011, "", "MPEG2 R-Engine (MPEG2 Hardware Encoder)" } , - { 0x10CF, 0x2019, "MB86295", "Coral-P Graphics Chip" } , - { 0x10CF, 0x201E, "MB86296", "Coral-PA Graphics Chip" } , - { 0x10D6, 0xFF51, "0x0100", "C87899D" } , - { 0x10D6, 0xff66, "0x0100", "C87899D" } , - { 0x1658, 0x0704, "905410B5", "DIG 704 PCI - Interface with Millisecond Timer and Interrupts" } , - { 0x10D9, 0x0066, "MX86101P", "sdas" } , - { 0x10D9, 0x0512, "MX98713", "Fast Ethernet Adapter" } , - { 0x10D9, 0x0531, "MX98715/25", "Single Chip Fast Ethernet NIC Controller" } , - { 0x10D9, 0x0532, "MX98723/727", "PCI/CardBus Fast Ethernet Controller" } , - { 0x10D9, 0x0553, "MX987x5", "Ethernet Adapter" } , - { 0x10D9, 0x8625, "MX86250", "xiankasqudong" } , - { 0x10D9, 0x8626, "MX86251", "" } , - { 0x10D9, 0x8627, "MX86251", "" } , - { 0x10D9, 0x8888, "MX86250", "9619E" } , - { 0x10D9, 0xC115, "lc82c115", "" } , - { 0x10DC, 0x0001, "STAR/RD24", "PCI-SCI PMC mezzanine" } , - { 0x10DC, 0x0002, "ATT 2C15-3 (FPGA)", "SCI bridge on PCI 5 Volt card" } , - { 0x10DC, 0x0004, "EP20S780", "ALTERA STRATIX" } , - { 0x10DC, 0x0010, "680-1110-150/400", "Simple PMC/PCI to S-LINK interface" } , - { 0x10DC, 0x0011, "680-1110-200/450", "Simple S-LINK to PMC/PCI interface" } , - { 0x10DC, 0x0012, "S32PCI64", "32-bit S-LINK to 64-bit PCI interface" } , - { 0x10DC, 0x0021, "", "HIPPI destination" } , - { 0x10DC, 0x0022, "", "HIPPI source" } , - { 0x10DC, 0x0033, "EP20KE (APEX-FPGA)", "ALICE DDL to PCI interface (RORC)" } , - { 0x10DC, 0x0101, "SL651 7057 C200", "Acquisition card for the SPS Orbit System (MACI)" } , - { 0x10DC, 0x016A, "XC4VFX100", "CALICE ODR" } , - { 0x10DC, 0x10DC, "ATT 2C15-3 (FPGA)", "TTC sr first TTC chip receiver PMC" } , - { 0x10DC, 0x301, "PLX PCI 9030", "based on the PLX PCI 9030 to build a MIL1553 bus interface" } , - { 0x10DC, 0x324, "PLX PCI96556", "64 Bit/66MHz PCI to Local Bus Bridge" } , - { 0x10DD, 0x0001, "", "3D graphics processor" } , - { 0x10DE, 0x04EF, "NV3", "Riva 128" } , - { 0x10DE, 0x0001, "Lucent 0x00da", "SoundMAX Integrated Digital Audio" } , - { 0x10DE, 0x0003, "It seems to be Realtek ALC888/9", "nVIDIA High Definition Audio/HDMI " } , - { 0x10DE, 0x0008, "NV1", "Edge 3D" } , - { 0x10DE, 0x0009, "NV1", "Edge 3D" } , - { 0x10DE, 0x0010, "NV2", "Mutara V08" } , - { 0x10DE, 0x0018, "NV3", "Riva 128" } , - { 0x10DE, 0x0019, "NV3", "Riva 128ZX" } , - { 0x10DE, 0x0020, "NV4", "Riva TNT" } , - { 0x10DE, 0x0028, "NV5", "TNT2 / TNT2 Pro" } , - { 0x10DE, 0x0029, "NV5", "TNT2 Ultra" } , - { 0x10DE, 0x002A, "NV5", "TNT2" } , - { 0x10DE, 0x002B, "NV5", "Riva TNT2" } , - { 0x10DE, 0x002C, "8.0", "Vanta/Vanta LT" } , - { 0x10DE, 0x002D, "NV5", "TNT2 Model 64 / TNT2 Model 64 Pro" } , - { 0x10DE, 0x002E, "NV6", "VANTA" } , - { 0x10DE, 0x002F, "NV6", "VANTA" } , - { 0x10DE, 0x0035, "MCP04", "MCP04 PATA Controller" } , - { 0x10DE, 0x0036, "MCP04", "MCP04 SATA/RAID Controller" } , - { 0x10DE, 0x003E, "MCP04", "MCP04 SATA/RAID Controller" } , - { 0x10DE, 0x0040, "NV40.0", "GeForce 6800 Ultra" } , - { 0x10DE, 0x0041, "NV40.1", "GeForce 6800" } , - { 0x10DE, 0x0042, "NV40.2", "Geforce 6800LE" } , - { 0x10DE, 0x0043, "NV40.3", "nforce3 250" } , - { 0x10DE, 0x0045, "NV40.5", "GeForce 6800 GT" } , - { 0x10DE, 0x0049, "NV40GL", "???" } , - { 0x10DE, 0x004E, "NV40GL", "Quadro FX 4000" } , - { 0x10DE, 0x0053, "CK804", "CK804 PATA Controller" } , - { 0x10DE, 0x0054, "CK804", "CK804 SATA/RAID Controller" } , - { 0x10DE, 0x0055, "CK804", "CK804 SATA/RAID Controller" } , - { 0x10DE, 0x0057, "nForce4 Ultra", "NVidia Network Bus Enumerator Description du p�riph�rique nVIDIA nForce4 SLI (CK8-04) - LAN Controll" } , - { 0x10DE, 0x0059, "Realtek ALC850", "Realtek AC'97 Audio" } , - { 0x10DE, 0x0060, "nForce MCP2", "ISA Bridge" } , - { 0x10DE, 0x0064, "nForce MCP-T", "SMBus Controller" } , - { 0x10DE, 0x0065, "nForce MCP2/MCP2-T/MCP2-U", "PATA Controller" } , - { 0x10DE, 0x0066, "nForce MCP-T", "Ethernet Adapter Chip 10/100/HD/FD-Autosense" } , - { 0x10DE, 0x0067, "nForce MCP2", "OpenHCI USB Controller" } , - { 0x10DE, 0x0068, "nForce MCP2", "EHCI USB 2.0 Controller" } , - { 0x10DE, 0x006A, "nForce MCP2", "Audio Codec Interface" } , - { 0x10DE, 0x006B, "nForce MCP-T?", "Audio Processing Unit (Dolby Digital)" } , - { 0x10DE, 0x006C, "nForce", "PCI to PCI Bridge" } , - { 0x10DE, 0x006D, "nForce MCP-T", "Audio Codec Interface" } , - { 0x10DE, 0x006E, "nForce MCP2", "OHCI Compliant IEEE 1394 Controller" } , - { 0x10DE, 0x0085, "MCP2S", "MCP2S PATA Controller" } , - { 0x10DE, 0x008C, "RLT8201BL", "Single-Port 10/100M Fast Ethernet PHYceiver" } , - { 0x10DE, 0x008E, "MCP2S", "MCP2S SATA/RAID Controller" } , - { 0x10DE, 0x0091, "G70", "GeForce 7800 GTX" } , - { 0x10DE, 0x0092, "NV47 (20x1,7vp)", "GeForce 7800GT" } , - { 0x10DE, 0x009C, "G70.1", "Quadro FX 350M" } , - { 0x10DE, 0x009D, "?", "NVIDIA GPU Quadro FX 4500" } , - { 0x10DE, 0x00A0, "NV5", "Aladdin TNT2" } , - { 0x10DE, 0x00C0, "NV41.0", "NV41GS" } , - { 0x10DE, 0x00C1, "NV41.1", "NVIDIA GeForce 6800" } , - { 0x10DE, 0x00C2, "NV41.2", "???" } , - { 0x10DE, 0x00C8, "NV41", "GeForce FX 6800 Go" } , - { 0x10DE, 0x00C9, "NV41", "GeForce FX 6800 Ultra Go" } , - { 0x10DE, 0x00CC, "NV41", "Quadro FX 1400 Go" } , - { 0x10DE, 0x00CD, "NV41GL", "Quadro FX 3450/4000 SDI" } , - { 0x10DE, 0x00CE, "NV41GL", "NVIDIA Quadro FX1400" } , - { 0x10DE, 0x00D0, "nForce 3", "LPC Bridge" } , - { 0x10DE, 0x00D1, "nForce 3", "Host Bridge" } , - { 0x10DE, 0x00D2, "nForce 3?", "PCI-to-PCI Bridge" } , - { 0x10DE, 0x00D4, "nForce MCp2", "SMBus Controller" } , - { 0x10DE, 0x00D5, "nForce3-150", "CK8 PATA 133/PATA to SATA Bridge" } , - { 0x10DE, 0x00D6, "nForce MCP3?", "Networking Controller" } , - { 0x10DE, 0x00D7, "nForce MCP3?", "OpenHCD USB Host Controller" } , - { 0x10DE, 0x00D8, "nForce MCP3?", "Enhanced PCI to USB Host Controller" } , - { 0x10DE, 0x00D9, "nForce 3", "Agere System PCI Soft Modem" } , - { 0x10DE, 0x00DA, "Lucent", "SoundMAX Integrated Digital Audio" } , - { 0x10DE, 0x00DD, "nForce MCP3?", "PCI-to-PCI Bridge" } , - { 0x10DE, 0x00DF, "Marvell 88E1111", "Network adapter" } , - { 0x10DE, 0x00E0, "nForce3 250", "LPC Interface Bridge" } , - { 0x10DE, 0x00E1, "nForce3 250", "Host/PCI Bridge" } , - { 0x10DE, 0x00E2, "nForce3 250", "AGP Host to PCI Bridge" } , - { 0x10DE, 0x00E3, "nForce 250", "CK8S SATA/RAID Controller" } , - { 0x10DE, 0x00E4, "nForce3 250", "PCI System Management" } , - { 0x10DE, 0x00E5, "nForce3 250", "Parallel ATA Controller" } , - { 0x10DE, 0x00E7, "nForce3 250", "OpenHCD USB Controller" } , - { 0x10DE, 0x00E8, "nForce3 250", "Enhanced PCI to USB Controller" } , - { 0x10DE, 0x00EA, "nForce3 250", "Audio Codec Interface" } , - { 0x10DE, 0x00ED, "nForce3 250", "PCI-PCI Bridge" } , - { 0x10DE, 0x00EE, "nForce 250", "CK8S SATA/RAID Controller" } , - { 0x10DE, 0x00F0, "NVBR02", "???" } , - { 0x10DE, 0x00F1, "NV43+BR02", "GeForce 6600 GT AGP" } , - { 0x10DE, 0x00F2, "NV43", "GeForce 6600" } , - { 0x10DE, 0x00F5, "G70", "GeForce 7800 GS" } , - { 0x10DE, 0x00F6, "NV41", "Geforce 6800GS" } , - { 0x10DE, 0x00F8, "NVBR02", "NVIDIA Quadro FX 3400/4400" } , - { 0x10DE, 0x00F9, "NVBR02", "GeForce 6800 GTO" } , - { 0x10DE, 0x00FA, "NVBR02.2", "GeForce PCX 5750" } , - { 0x10DE, 0x00FB, "NVBR02.3", "GeForce PCX 5900" } , - { 0x10DE, 0x00FC, "NVBR02.4", "GeForce PCX 5300" } , - { 0x10DE, 0x00FD, "NVBR02GL", "Quadro NVS 280 PCI-E" } , - { 0x10DE, 0x00FE, "NVBR02GL", "Quadro FX 1300" } , - { 0x10DE, 0x00FF, "NVBR02.7", "GeForce PCX 4300" } , - { 0x10DE, 0x0100, "NV10", "GeForce 256" } , - { 0x10DE, 0x0101, "NV10", "GeForce 256 DDR" } , - { 0x10DE, 0x0102, "NV10", "GeForce 256 Ultra" } , - { 0x10DE, 0x0103, "NV10GL", "Quadro (GeForce 256 GL)" } , - { 0x10DE, 0x0110, "NV11", "GeForce2 MX / MX 400" } , - { 0x10DE, 0x0111, "NV11DDR", "GeForce2 MX 100/200Â� (DDR)" } , - { 0x10DE, 0x0112, "NV11", "GeForce2 Go / MX Ultra" } , - { 0x10DE, 0x0112, "???", "Nvidia GeForce2 Go/MX Ultra Video Adapter" } , - { 0x10DE, 0x0113, "NV11GL", "Quadro2 MXR / EX / Go" } , - { 0x10DE, 0x0141, "NV43", "NVIDIA GeForce 6600" } , - { 0x10DE, 0x0145, "NV43", "NVIDIA GeForce 6610 XL" } , - { 0x10DE, 0x0148, "unknown", "GeForce Go 6600" } , - { 0x10DE, 0x014D, "unknown", "NVIDIA Quadro FX 5500" } , - { 0x10DE, 0x014E, "NV43", "NVIDIA Quadro FX 540" } , - { 0x10DE, 0x014F, "NV43", "NVIDIA GeForce 6200" } , - { 0x10DE, 0x0150, "NV15", "GeForce2 GTS / Pro" } , - { 0x10DE, 0x0151, "NV15 DDR", "GeForce2 Ti" } , - { 0x10DE, 0x0152, "NV15BR", "GeForce2 Ultra (BladeRunner)" } , - { 0x10DE, 0x0153, "NV15GL", "Quadro2 Pro" } , - { 0x10DE, 0x0160, "NV44 (Code Name)", "GPU 6500 " } , - { 0x10DE, 0x0162, "NV44?", "GeForce 6200SE TurboCache" } , - { 0x10DE, 0x0163, "00", "Geforce 6200 LE" } , - { 0x10DE, 0x0164, "NV44?", "GeForce FX 6200 Go" } , - { 0x10DE, 0x0165, "NVS285", "Quadro NVS 285" } , - { 0x10DE, 0x016a, "NVidia GeForce 7100 GS", "VGA" } , - { 0x10DE, 0x0170, "NV17.2", "GeForce4 MX 460" } , - { 0x10DE, 0x0171, "NV17.2", "GeForce4 MX 440" } , - { 0x10DE, 0x0172, "NV17.3", "GeForce4 MX 420" } , - { 0x10DE, 0x0173, "NV17.4", "GeForce4 MX 440-SE" } , - { 0x10DE, 0x0174, "NV17M", "GeForce4 440 Go 64MB" } , - { 0x10DE, 0x0175, "NV17M", "GeForce4 420 Go" } , - { 0x10DE, 0x0176, "NV17M", "GeForce4 420 Go 32M" } , - { 0x10DE, 0x0177, "NV17M", "GeForce4 460 Go" } , - { 0x10DE, 0x0178, "NV17GL.1", "Quadro4 500/550 XGL" } , - { 0x10DE, 0x0179, "NV17M", "GeForce4 440 Go 64M" } , - { 0x10DE, 0x017A, "NV17GL.2", "Quadro4 200/400 NVS" } , - { 0x10DE, 0x017B, "NV17GL.3", "Quadro4 550 XGL" } , - { 0x10DE, 0x017C, "NV17M", "Quadro4 500 GoGL" } , - { 0x10DE, 0x0181, "NV18B", "NVIDIA GeForce MX440 with AGP8X" } , - { 0x10DE, 0x0182, "NV18.2", "GeForce4 MX 440 with AGP 8X" } , - { 0x10DE, 0x0183, "NV18.4", "GeForce4 MX 420 with AGP 8X" } , - { 0x10DE, 0x0185, "NV18.6", "GeForce4 MX 4000" } , - { 0x10DE, 0x0186, "NV18M", "GeForce4 448 Go" } , - { 0x10DE, 0x0187, "nv18m", "Geforce4 488 Go" } , - { 0x10DE, 0x018A, "Quadro NVS", "Quadro NVS with AGP8X" } , - { 0x10DE, 0x018D, "NV18M", "GeForce4 448 Go" } , - { 0x10DE, 0x0191, "G80", "Geforce 8800GTX 768MB" } , - { 0x10DE, 0x0193, "G80", "NVIDIA GeForce 8800 GTS" } , - { 0x10DE, 0x019D, "G80", "Nvidia Quadro FX 5600" } , - { 0x10DE, 0x019E, "G80", "Nvidia Quadro FX4600" } , - { 0x10DE, 0x01A0, "NVCrush11", "GeForce2 Integrated Graphics" } , - { 0x10DE, 0x01A4, "nForce", "AGP Controller" } , - { 0x10DE, 0x01A5, "nForce", "AGP Controller" } , - { 0x10DE, 0x01A6, "nForce", "AGP Controller" } , - { 0x10DE, 0x01A8, "nForce 220", "Memory Controller (SDR)" } , - { 0x10DE, 0x01A9, "nForce 420", "Memory Controller (SDR)" } , - { 0x10DE, 0x01AA, "nForce 220/230", "Memory Controller (DDR)" } , - { 0x10DE, 0x01AB, "nForce 415/420/430", "Memory Controller (DDR)" } , - { 0x10DE, 0x01AC, "nForce 2x0/415/4x0", "Memory Controller" } , - { 0x10DE, 0x01AD, "nForce 2x0/415/4x0", "Memory Controller" } , - { 0x10DE, 0x01B0, "nForce MCP", "Audio Processing Unit (Dolby Digital)" } , - { 0x10DE, 0x01B1, "nForce MCP-S", "Audio Codec Interface" } , - { 0x10DE, 0x01B2, "nForce", "HUB Interface" } , - { 0x10DE, 0x01B4, "nForce MCP", "SMBus Controller" } , - { 0x10DE, 0x01B7, "nForce", "AGP Bridge" } , - { 0x10DE, 0x01B8, "nForce", "PCI Bridge" } , - { 0x10DE, 0x01BC, "nForce MCP", "ATA Controller" } , - { 0x10DE, 0x01C1, "nForce MCP", "AC97 Modem" } , - { 0x10DE, 0x01C2, "nForce MCP", "OHCI USB Controller" } , - { 0x10DE, 0x01C3, "nForce MCP", "Networking Adapter" } , - { 0x10DE, 0x01D1, "unknown", "NVIDIA GeForce 7300 LE" } , - { 0x10DE, 0x01D3, "nVidia", "nVidia GeForce 7300 SE" } , - { 0x10DE, 0x01D7, "unknown", "nVIDIA Quadro NVS 110M" } , - { 0x10DE, 0x01D8, "G72M", "GeForce Go 7400" } , - { 0x10DE, 0x01DC, "nvidia mobile graphics", "NVIDIA Quadro FX 350M" } , - { 0x10DE, 0x01DD, "7500LE", "?" } , - { 0x10DE, 0x01DF, "0000", "0000" } , - { 0x10DE, 0x01E0, "nForce2", "AGP Controller" } , - { 0x10DE, 0x01E1, "nForce2", "AGP Controller" } , - { 0x10DE, 0x01E8, "nForce2", "AGP Host to PCI Bridge" } , - { 0x10DE, 0x01EA, "nForce2", "Memory Controller 0" } , - { 0x10DE, 0x01EB, "nForce2", "Memory Controller 1" } , - { 0x10DE, 0x01EC, "nForce2", "Memory Controller 2" } , - { 0x10DE, 0x01ED, "nForce2", "Memory Controller 3" } , - { 0x10DE, 0x01EE, "nForce2", "Memory Controller 4" } , - { 0x10DE, 0x01EF, "nForce2", "Memory Controller 5" } , - { 0x10DE, 0x0200, "NV20", "GeForce3" } , - { 0x10DE, 0x0201, "NV2", "GeForce3 Ti 200" } , - { 0x10DE, 0x0202, "NV20BR", "GeForce3 Ti 500" } , - { 0x10DE, 0x0203, "NV20DCC", "Quadro DCC" } , - { 0x10DE, 0x0221, "unknown", "NVIDIA GeForce 6200" } , - { 0x10DE, 0x0241, "NVS 210S", "nVidia GForce 6150, build in DELL Optiplex 740 (AMD Processor)" } , - { 0x10DE, 0x0242, "unknown", "NVIDIA GeForce 6100" } , - { 0x10DE, 0x0244, "Geforce Go 6150", "Geforce Go 6150" } , - { 0x10DE, 0x0250, "NV25", "GeForce4 Ti 4600" } , - { 0x10DE, 0x0251, "NV25.2", "Gforce4 Ti 4400" } , - { 0x10DE, 0x0253, "NVIDIA Corporation", "Geforce4 TI 4200 128 Mo" } , - { 0x10DE, 0x0258, "NV25GL.1", "Quadro4 900 XGL" } , - { 0x10DE, 0x0259, "NV25GL.2", "Quadro4 750 XGL" } , - { 0x10DE, 0x025B, "NV25GL.4", "Quadro4 700 XGL" } , - { 0x10DE, 0x0264, "NVIDIA SMB Bus Controller", "NVIDIA nForce PCI System Management" } , - { 0x10DE, 0x0265, "MCP51", "PATA Controller" } , - { 0x10DE, 0x0266, "MCP51S", "NVIDIA nForce 430/410 Serial ATA Controller" } , - { 0x10DE, 0x0267, "MCP51S", "NVIDIA nForce 430/410 Serial ATA Controller" } , - { 0x10DE, 0x0268, "430", "NVIDIA nForce Networking Controller" } , - { 0x10DE, 0x0269, "2A34103C", "MCP51 Ethernet Controller " } , - { 0x10DE, 0x026C, "6150", "AMD" } , - { 0x10DE, 0x0271, "unknown", "Coprocessor" } , - { 0x10DE, 0x0280, "NV28.1", "GeForce4 Ti 4800" } , - { 0x10DE, 0x0281, "NV28.2", "GeForce4 Ti 4200 with AGP 8X" } , - { 0x10DE, 0x0282, "NV28.3", "GeForce4 Ti 4800 SE" } , - { 0x10DE, 0x0286, "???", "GeForce4 4200 Go" } , - { 0x10DE, 0x0288, "NV28GL.1", "Quadro4 980 XGL" } , - { 0x10DE, 0x0289, "NV28GL.2", "Quadro4 780 XGL" } , - { 0x10DE, 0x028C, "NV28GL", "Quadro4 700 GoGL" } , - { 0x10DE, 0x0291, "0x0401", "BLISS GeForce 7900 GT bios" } , - { 0x10DE, 0x0297, "G71", "NVIDIA GeForce Go 7950 GTX" } , - { 0x10DE, 0x029C, "G71", "Nvidia Quadro FX 5500" } , - { 0x10DE, 0x029D, "G71", "Quadro FX 3500" } , - { 0x10DE, 0x02A0, "NV2A", "GeForce3 Integrated GPU" } , - { 0x10DE, 0x02e0, "???", "GeForce 7600 GT" } , - { 0x10DE, 0x02E2, "-", "Video Card GPU BFG 7300 512MB GT" } , - { 0x10DE, 0x0300, "NV30.1", "GeForce FX" } , - { 0x10DE, 0x0301, "NV30.2", "GeForce FX 5800 Ultra" } , - { 0x10DE, 0x0302, "NV30.3", "GeForce FX 5800" } , - { 0x10DE, 0x0308, "NV30GL.1", "Quadro FX 2000" } , - { 0x10DE, 0x0309, "NV30GL.2", "Quadro FX 1000" } , - { 0x10DE, 0x030A, "NV30GL", "ICE FX 2000" } , - { 0x10DE, 0x0311, "NV31.1", "GeForce FX 5600 Ultra" } , - { 0x10DE, 0x0312, "NV31.2", "GeForce FX 5600" } , - { 0x10DE, 0x0313, "NV31?", "???" } , - { 0x10DE, 0x0314, "NV31", "GeForce FX 5600XT" } , - { 0x10DE, 0x0318, "NV31GL.1", "???" } , - { 0x10DE, 0x0319, "NV31GL.2", "???" } , - { 0x10DE, 0x031A, "NV31GL", "NVIDIA NV31GL" } , - { 0x10DE, 0x031B, "NV31B", "NVIDIA GeForce FX Go5600" } , - { 0x10DE, 0x031C, "NV31C", "NVIDIA Quadro FX Go700" } , - { 0x10DE, 0x0321, "NV34.2", "GeForce FX 5200 Ultra" } , - { 0x10DE, 0x0322, "NV34.3", "GeForce FX 5200" } , - { 0x10DE, 0x0323, "NV34.4", "GeForce FX 5200LE" } , - { 0x10DE, 0x0324, "NV", "nVidia GeForce FX Go 5200, 128MB" } , - { 0x10DE, 0x0325, "nv36m", "GeForce FX Go 5700" } , - { 0x10DE, 0x0326, "NV34.6", "GeForce FX 5500" } , - { 0x10DE, 0x0327, "NV34.7", "GeForce FX 5100" } , - { 0x10DE, 0x0328, "NV34GL", "Nvidia NV34GL" } , - { 0x10DE, 0x0329, "G73", "Geforce 7600GS" } , - { 0x10DE, 0x032A, "NV34GL.3", "Quadro NVS 280" } , - { 0x10DE, 0x032B, "NV34GL.4", "Quadro FX 500" } , - { 0x10DE, 0x032C, "NV34GL", "NVIDIA NV34GL" } , - { 0x10DE, 0x032D, "NV34M", "GeForce FX Go5100" } , - { 0x10DE, 0x032F, "NV34GL", "???" } , - { 0x10DE, 0x0330, "???", "GeForce FX 5900 Ultra" } , - { 0x10DE, 0x0331, "???", "GeForce FX 5900" } , - { 0x10DE, 0x0332, "???", "GeForce FX 5900XT" } , - { 0x10DE, 0x0333, "NV38", "GeForce FX 5950 Ultra" } , - { 0x10DE, 0x0334, "NV35.4", "GeForce FX 5900ZT" } , - { 0x10DE, 0x0338, "NV35GL", "Quadro FX 3000" } , - { 0x10DE, 0x0341, "NV36.1", "GeForce FX 5700 Ultra" } , - { 0x10DE, 0x0342, "NV36.2", "GeForce FX 5800" } , - { 0x10DE, 0x0343, "NV36.3", "GeForce FX 5700LE" } , - { 0x10DE, 0x0344, "NV36.4", "GeForce FX 5700VE" } , - { 0x10DE, 0x0345, "NV36.5", "???" } , - { 0x10DE, 0x0347, "??", "Nvidia 5700 from hp" } , - { 0x10DE, 0x0348, "NV36M", "GeForce FX Go5600" } , - { 0x10DE, 0x034E, "nv36GL", "Quadro FX 1100" } , - { 0x10DE, 0x034F, "NV36GL?", "???" } , - { 0x10DE, 0x036C, "81FB1043", "Standard OpenHCD USB Hostcontroller" } , - { 0x10DE, 0x036d, "81FB1043", "Standard PCI-to-USB Enhanced Hostcontroller" } , - { 0x10DE, 0x036E, "MCP55", "MCP55 PATA Controller" } , - { 0x10DE, 0x036F, "MCP55", "MCP55 SATA/RAID Controller" } , - { 0x10DE, 0x0371, "ADI 1988", "MCP55 High Definition Audio" } , - { 0x10DE, 0x037E, "MCP55", "MCP55 SATA/RAID Controller" } , - { 0x10DE, 0x037F, "MCP55S", "MCP55 SATA/RAID Controller" } , - { 0x10DE, 0x0391, "G73 B1", "Ge-Force 7600GT" } , - { 0x10DE, 0x0392, "NVIDIA GeForce 7600 GS", "NVIDIA GeForce 7600 GS" } , - { 0x10DE, 0x0393, "UNKOWN", "NVIDIA GeForce 7300GT" } , - { 0x10DE, 0x0398, "G73", "NVIDIA GeForce Go 7600" } , - { 0x10DE, 0x039E, "Quadro FX 560", "Quadro FX 560" } , - { 0x10DE, 0x03D0, "unknown", "NVIDIA GeForce 6100 nForce 430" } , - { 0x10DE, 0x03E0, "nForce 430", "PCI standard ISA bridge" } , - { 0x10DE, 0x03E7, "MCP61", "MCP61 SATA/RAID Controller" } , - { 0x10DE, 0x03EC, "MCP61", "MCP61 PATA Controller" } , - { 0x10DE, 0x03EF, "nForce 405", "Nvidia Networking Card" } , - { 0x10DE, 0x03F0, "MCP61", "High Definition Audio" } , - { 0x10DE, 0x03F6, "MCP61", "MCP61 SATA/RAID Controller" } , - { 0x10DE, 0x03F7, "MCP61", "MCP61 SATA/RAID Controller" } , - { 0x10DE, 0x0402, "0402", "gainward bliss 8600 gt 512mo silent fx pcx" } , - { 0x10DE, 0x0407, "NVIDIA GeForce 8600M GT", "NVIDIA GeForce 8600M GT" } , - { 0x10DE, 0x040C, "NVIDIA Quadro NVS 570M", "Mobile Quadro FX/NVS video card" } , - { 0x10DE, 0x0421, "G86", "GeForce 8500 GT" } , - { 0x10DE, 0x0423, "G86", "NVIDIA Geforce 8300 GS" } , - { 0x10DE, 0x0427, "unknown", "Geforce 8400M GS" } , - { 0x10DE, 0x0428, "NVIDIA� GeForce 8400M G", "NVIDIA� GeForce 8400M G" } , - { 0x10DE, 0x0429, "Unknown", "nVidia Quadro FX 570M" } , - { 0x10DE, 0x042b, "8400 ??", "NVIDIA Quadro NVS 135M" } , - { 0x10DE, 0x042D, "Quadro FX 360 M", "Quadro FX 360 M (Mobile)" } , - { 0x10DE, 0x042f, "NVS 290", "NVIDIA Quadro NVS 290" } , - { 0x10DE, 0x0448, "MCP65", "MCP65 PATA Controller" } , - { 0x10DE, 0x044C, "MCP65", "MCP65 RAID" } , - { 0x10DE, 0x044D, "MCP65", "MCP65 AHCI" } , - { 0x10DE, 0x044E, "MCP67D", "MCP67D AHCI" } , - { 0x10DE, 0x044F, "MCP65", "MCP65 ?AHCI" } , - { 0x10DE, 0x045D, "MCP65", "MCP65 SATA Controller(IDE mode)" } , - { 0x10DE, 0x054, "NVidia nForce 4 SLI", "IDE Controller" } , - { 0x10DE, 0x0550, "MCP67", "MCP67 SATA Controller(IDE mode)" } , - { 0x10DE, 0x0554, "MCP67", "MCP67 AHCI" } , - { 0x10DE, 0x0555, "MCP67", "MCP67 AHCI" } , - { 0x10DE, 0x0556, "MCP67", "MCP67 AHCI" } , - { 0x10DE, 0x0558, "MCP67", "MCP67 RAID" } , - { 0x10DE, 0x0559, "MCP67", "MCP67 RAID" } , - { 0x10DE, 0x055A, "MCP67", "MCP67 RAID" } , - { 0x10DE, 0x0560, "MCP67", "MCP67 PATA Controller" } , - { 0x10DE, 0x056C, "MCP73", "MCP73 PATA" } , - { 0x10DE, 0x0611, "8800 GT", "Alphadog edition from XFX" } , - { 0x10DE, 0x0622, "nVidia GeForce 9600GT", "nVidia" } , - { 0x10DE, 0x0640, "G96-300-A1", "Nvidia 9500GT graphic controller" } , - { 0x10DE, 0x0644, "G96", "GeForce 9500 GS" } , - { 0x10DE, 0x0645, "G96", "GeForce 9500 GS" } , - { 0x10DE, 0x0649, "G96", "nVidia GeForce 9600M GT" } , - { 0x10DE, 0x0760, "MCP78 NIC", "NForce Network Controller" } , - { 0x10DE, 0x0768, "MCP ?", "AHCI Controller" } , - { 0x10DE, 0x07B5, "MCP72", "MCP72 AHCI" } , - { 0x10DE, 0x07B9, "MCP72", "MCP72 RAID" } , - { 0x10DE, 0x07D8, "nForce 7100-630i (MCP73PV)", "nForce 7100-630i (MCP73PV)" } , - { 0x10DE, 0x07DC, "nForce 7100-630i (MCP73PV)", "nForce 7100-630i (MCP73PV)" } , - { 0x10DE, 0x07F0, "MCP73", "MCP73 SATA(IDE mode)" } , - { 0x10DE, 0x07F4, "MCP73", "MCP73 AHCI1" } , - { 0x10DE, 0x07F5, "MCP73", "MCP73 AHCI2" } , - { 0x10DE, 0x07F6, "MCP73", "MCP73 AHCI3" } , - { 0x10DE, 0x07F7, "MCP73", "MCP73 AHCI4" } , - { 0x10DE, 0x07F8, "MCP73", "MCP73 RAID1" } , - { 0x10DE, 0x07F9, "MCP73", "MCP73 RAID2" } , - { 0x10DE, 0x07FA, "MCP73", "MCP73 RAID3" } , - { 0x10DE, 0x07FB, "MCP73", "MCP73 RAID4" } , - { 0x10DE, 0x0aa3, "nForce", "NVIDIA nForce System Management Controller" } , - { 0x10DE, 0x0AB8, "MCP79", "MCP79 AHCI1" } , - { 0x10DE, 0x0AB9, "MCP79", "MCP79 AHCI2" } , - { 0x10DE, 0x0ABC, "MCP79", "MCP79 RAID1" } , - { 0x10DE, 0x0ABD, "MCP79", "MCP79 RAID2" } , - { 0x10DE, 0x0AD0, "MCP78", "SATA Controller IDE mode" } , - { 0x10DE, 0x0BC4, "MCP?", "AHCI Controller" } , - { 0x10DE, 0x0BC5, "MCP?", "AHCI Controller" } , - { 0x10DE, 0x0BCC, "MCP?", "Raid Controller" } , - { 0x10DE, 0x0BCD, "MCP?", "Raid Controller" } , - { 0x10DE, 0x10DE, "NV3", "Riva 128" } , - { 0x10DE, 0x110, "nv11", "geforcemx/mx400" } , - { 0x10DE, 0x161, "NV44", "GeForce 6200 TurboCache" } , - { 0x10DE, 0x181, "NV18B", "GeForce4 MX 440 AGP 8X" } , - { 0x10DE, 0x247, "NVS210S", "GF6150" } , - { 0x10DE, 0x26C, "6150", "AMD" } , - { 0x10DE, 0x69, "nVidia MCP2T", "nVidia MCP2T in MSI MEGA 180" } , - { 0x10DE, 0x8001, "MCP73", "nVidia MCP73 HDMI Audio Driver" } , - { 0x10DE, 0x026C, "6150", "nVidia GeForce" } , - { 0x10DF, 0x10DF, "Light Pulse", "Fibre Channel Adapter" } , - { 0x10DF, 0x1AE5, "LP6000", "Fibre Channel Host Adapter" } , - { 0x10DF, 0xF0A5, "PL1050Ex", "Emulex 1050EX FC HBA - 2GB PCI-EXPRESS" } , - { 0x10DF, 0xF0E5, "?", "LPe1150" } , - { 0x10DF, 0xF100, "LPe12000", "Fibre Channel Adapter" } , - { 0x10DF, 0xF700, "LP7000", "Fibre Channel Host Adapter" } , - { 0x10DF, 0xF800, "LP8000", "Fibre Channel Host Adapter" } , - { 0x10DF, 0xF900, "????", "Light Pulse LP9002 2Gb" } , - { 0x10DF, 0xF980, "LP9802 / DC", "LP9802 & LP9802DC HBA adapter" } , - { 0x10DF, 0xFA00, "LP10000", "Fibre Channel Host Adapter" } , - { 0x10DF, 0xfd00, "L2A2860 HELIOS v1.11", "Emulex LP11002" } , - { 0x10DF, 0xfe00, "LPe11002-M4", "Dual Channel 4Gb/s" } , - { 0x10E1, 0x0391, "TRM-S1040", "0000" } , - { 0x10E1, 0x690C, "DC-690c", "" } , - { 0x10E1, 0xDC20, "DC-290", "EIDE Controller" } , - { 0xC0DE, 0x5600, "62802", "" } , - { 0xC0DE, 0xC0DE, "62802-51", "oZ0030" } , - { 0x10E3, 0x0000, "CA91C042/142", "Universe/II VMEbus Bridge" } , - { 0x10E3, 0x0148, "Tundra Tsi148", "PCI/X-to-VME Bridge" } , - { 0x10E3, 0x0513, "Tsi320", "Dual-Mode PCI-to-PCI Bus Bridge" } , - { 0x10E3, 0x0850, "Tsi850", "Power PC Dual PCI Host Bridge" } , - { 0x10E3, 0x0854, "Tsi850", "Power PC Single PCI Host Bridge" } , - { 0x10E3, 0x0860, "CA91C860", "QSpan Motorola Processor Bridge" } , - { 0x10E3, 0x0862, "CA91L862A", "QSpan II PCI-to-Motorola CPU Bridge" } , - { 0x10E3, 0x8260, "CA91L8200/8260", "PowerSpan II PowerPC-to-PCI Bus Switch" } , - { 0x10E3, 0x8261, "CA91L8200/8260", "PowerSpan II PowerPC-to-PCI Bus Switch" } , - { 0x10E8, 0x2011, "Q-Motion pci 264", "Video Capture/Edit board" } , - { 0x10E8, 0x4750, "S5920Q 00144 a038", "amcc PCI MatchMaker" } , - { 0x10E8, 0x5920, "S5920q", "amcc" } , - { 0x10E8, 0x8033, "BBK-PCI light", "Transputer Link Interface" } , - { 0x10E8, 0x8043, "LANai4.x", "Myrinet LANai interface chip" } , - { 0x10E8, 0x8062, "S5933", "Parastation" } , - { 0x10E8, 0x807D, "S5933", "PCI44" } , - { 0x10E8, 0x8088, "FS", "Kingsberg Spacetec Format Synchronizer" } , - { 0x10E8, 0x8089, "SOB", "Kingsberg Spacetec Serial Output Board" } , - { 0x10E8, 0x809C, "S5933", "Traquair HEPC3" } , - { 0x10E8, 0x80b1, "Data Fire Basic 4MB PCI", "Active ISDN Controller" } , - { 0x10E8, 0x80b9, "PCI MATCHMAKER S5933QC", "Some sort of Bridge?" } , - { 0x10E8, 0x80D7, "PCI-9112", "Data Acquisition Card (ADLINK)" } , - { 0x10E8, 0x80D8, "PCI-7200", "40MB/s 32-channels Digital I/O card (ADLINK)" } , - { 0x10E8, 0x80D9, "PCI-9118", "Data Acquisition Card (ADLINK)" } , - { 0x10E8, 0x80DA, "", "" } , - { 0x10E8, 0x811A, "PCI-DSlink", "PCI-IEEE1355-DS-DE interface" } , - { 0x10E8, 0x8170, "S5933", "Matchmaker PCI Chipset Development Tool" } , - { 0x10EA, 0x1680, "IGA-1680", "svga" } , - { 0x10EA, 0x1682, "IGA-1682", "video" } , - { 0x10EA, 0x1683, "IGA-1683", "" } , - { 0x10EA, 0x2000, "CyberPro 2010", "TV output ram 2MB Cyberpro2010" } , - { 0x10EA, 0x2010, "CyberPro 20xx/2000A", "vbcvbcvbcvb" } , - { 0x10EA, 0x5000, "CyberPro 5000", "" } , - { 0x10EA, 0x5050, "CyberPro 5050", "" } , - { 0x10EB, 0x0101, "3GA", "64 bit graphics processor" } , - { 0x10EB, 0x8111, "Twist3", "Frame Grabber" } , - { 0x9005, 0x0010, "AIC-7890AB scsi controller", "AHA-2940U2W/U2B,2950U2W Ultra2 SCSI" } , - { 0x9005, 0x0011, "11111", "AHA-2930U2 Ultra2 SCSI Host Adapter" } , - { 0x9005, 0x0013, "AIC-7890/1", "SCSI Controller" } , - { 0x9005, 0x001F, "AIC-7890 AB for Windows XP", "Ultra2-Wide SCSI controller" } , - { 0x9005, 0x0020, "AIC-789x", "SCSI Controller" } , - { 0x9005, 0x002F, "AIC-789x", "SCSI Controller" } , - { 0x9005, 0x0030, "AIC-789x", "SCSI Controller" } , - { 0x9005, 0x003F, "AIC-789x", "SCSI Controller" } , - { 0x9005, 0x0050, "", "AHA-3940U2x/3950U2x Ultra2 SCSI Adapter" } , - { 0x9005, 0x0051, "", "AHA-3950U2x Ultra2 SCSI Adapter" } , - { 0x9005, 0x0053, "AIC-7896", "SCSI Controller" } , - { 0x9005, 0x005F, "AIC-7896/7", "Ultra2 SCSI Controller" } , - { 0x9005, 0x0080, "AIC-7892Q", "Ultra160/m PCI SCSI Controller" } , - { 0x9005, 0x0081, "AIC-7892B", "Ultra160 SCSI Controller" } , - { 0x9005, 0x0083, "AIC-7892D", "Ultra160 SCSI Controller" } , - { 0x9005, 0x008F, "AIC-7892", "Ultra160 SCSI Controller" } , - { 0x9005, 0x00C0, "AIC-7899A", "Ultra160 SCSI Controller" } , - { 0x9005, 0x00C1, "AIC-7899B", "Ultra160 SCSI Controller" } , - { 0x9005, 0x00C3, "AIC-7899D", "Ultra160 SCSI Controller" } , - { 0x9005, 0x00C5, "", "RAID Subsystem HBA" } , - { 0x9005, 0x00CF, "AIC-7899G", "Ultra160 SCSI Controller" } , - { 0x9005, 0x0258, "AAC-RAID", "Adaptec AAR-2610SA SATA 6-Port Raid" } , - { 0x9005, 0x0285, "Adaptec 2410SA SATA RAID", "PCIX133 32/64bit" } , - { 0x9005, 0x041F, "AIC 9410", "SAS/SATA Controller" } , - { 0x9005, 0x043E, "AIC9450W", "SAS/SATA Controller" } , - { 0x9005, 0x8000, "ASC-29320A", "Ultra320 SCSI Controller" } , - { 0x9005, 0x800F, "AIC-7901", "Ultra320 SCSI Controller" } , - { 0x9005, 0x8010, "ASC-39320", "Ultra320 SCSI Controller" } , - { 0x9005, 0x8011, "ASC-39320D", "Ultra320 SCSI Controller" } , - { 0x9005, 0x8012, "ASC-29320", "Ultra320 SCSI Controller" } , - { 0x9005, 0x8014, "ASC-29320LP", "Ultra320 SCSI Controller" } , - { 0x9005, 0x8015, "ASC-39320", "Ultra320 SCSI Controller" } , - { 0x9005, 0x8016, "ASC-39320A", "Ultra320 SCSI Controller" } , - { 0x9005, 0x8017, "ASC-29320ALP", "Ultra320 SCSI Controller" } , - { 0x9005, 0x801C, "AIC-?????", "Ultra320 SCSI Controller" } , - { 0x9005, 0x801D, "AIC-7902B", "Ultra320 SCSI Controller" } , - { 0x9005, 0x801E, "AIC-7901", "Ultra320 SCSI Controller" } , - { 0x9005, 0x801F, "AIC-7902", "Ultra320 SCSI Controller" } , - { 0x9005, 0x8080, "ASC-29320A", "Ultra320 HostRAID Controller" } , - { 0x9005, 0x808F, "AIC-7901", "Ultra320 HostRAID Controller" } , - { 0x9005, 0x8090, "ASC-39320", "HostRAID SCSI Controller" } , - { 0x9005, 0x8091, "ASC-39320D", "HostRAID SCSI Controller" } , - { 0x9005, 0x8092, "ASC-29320", "HostRAID SCSI Controller" } , - { 0x9005, 0x8093, "ASC-29320B", "HostRAID SCSI Controller" } , - { 0x9005, 0x8094, "ASC-29320LP", "HostRAID SCSI Controller" } , - { 0x9005, 0x8095, "ASC-39320", "HostRAID SCSI Controller" } , - { 0x9005, 0x8096, "ASC-39320A", "HostRAID SCSI Controller" } , - { 0x9005, 0x8097, "ASC-29320ALP", "HostRAID SCSI Controller" } , - { 0x9005, 0x809C, "ASC-39320D", "HostRAID SCSI Controller" } , - { 0x9005, 0x809D, "AIC-7902B", "HostRAID SCSI Controller" } , - { 0x9005, 0x809E, "AIC-7901A", "HostRAID SCSI Controller" } , - { 0x9005, 0x809F, "AIC-7902B", "HostRAID SCSI Controller" } , - { 0x10EC, 0x0139, "rtl8139B", "ethernet 10/100" } , - { 0x10EC, 0x0139, "rtl8139B", "ethernet 10/100" } , - { 0x10EC, 0x0260, "RTL260", "Driver MS UAA for HD Audio" } , - { 0x10EC, 0x0262, "ALC882", "Realtek High Definition Audio" } , - { 0x10EC, 0x0268, "Realtek ALC268", "Audio Device on High Definition Audio Bus" } , - { 0x10EC, 0x0660, "Realtek HD Audio", "High Definition Audio" } , - { 0x10EC, 0x0662, "ALC662", "Realtek ALC662 HD Audio" } , - { 0x10EC, 0x0880, "al880", "REALTEK ALC880" } , - { 0x10EC, 0x0883, "alc888S", "Realtek High Definition Audio" } , - { 0x10EC, 0x0885, "ALC885", "7.1+2 Channel High-Performance HDA Codec with Content Protection" } , - { 0x10EC, 0x0888, "realtek high definition audio", "Realtek Azak lia chipset" } , - { 0x10EC, 0x8021, "RTL8029AS", "NIC" } , - { 0x10EC, 0x8029, "RTL8029(as)pci ethernet nic", "RTL8029(as)pci ethernet nic" } , - { 0x10EC, 0x8101L, "8101E", "10/100 Ethernet" } , - { 0x10EC, 0x8119, "10", "32BIT Card Bus 10/100 (10EC-8119)" } , - { 0x10EC, 0x8129, "RTL8139d", "10/100 Fast Ethernet Controller" } , - { 0x10EC, 0x8131, "LFE8139ATX", "" } , - { 0x10EC, 0x8136, "RTL8100-8101E-8102E-PCIEXPRESS", "RTL8100E/RTL8101E/RTL8102E-GR" } , - { 0x10EC, 0x8138, "RT8139B/C", "CardBus Fast Ethernet Adapter" } , - { 0x10EC, 0x8139, "RTL-8139/8139C/8139C+", "Realtek RTL8139 Family PCI Fast Ethernet NIC" } , - { 0x10EC, 0x8167, "8169", "PCI Gigabit Ethernet" } , - { 0x10EC, 0x8168, "RTL8168/8111", "Gigabit Ethernet NIC(NDIS 6.0)" } , - { 0x10EC, 0x8169, "RTL8119", "Single Gigabit LOM Ethernet Controller" } , - { 0x10EC, 0x8180, "RTL8180", "Realtek RTL8180 Wireless LAN (Mini-)PCI NIC" } , - { 0x10EC, 0x8185, "RTL-8185", "IEEE 802.11a/b/g Wireless LAN Controller (rev 20)" } , - { 0x10EC, 0x8186, "RTL8111/8168B", "PCI Express Gigabit Ethernet controller" } , - { 0x10EC, 0x8197, "8187B", "Wireless 802.11b/g 54Mbps USB 2.0 Network Adapter" } , - { 0x10EC, 0x8199, "RTL8187SE", "Single-Chip IEEE 802.11b/g WLAN Controller w/PCI Express Interface" } , - { 0x10EC, 0x9876, "RTL 8168/8111", "GIGABIT ETHERNET LOM" } , - { 0x10ED, 0x7310, "V7310", "VGA Video Overlay Adapter" } , - { 0x10EE, 0x0314, "Spartan XC2S50E", "Communications Controller" } , - { 0x10EE, 0X1001, "8343176", "PCI to H.100 audio interface" } , - { 0x10EE, 0x3FC0, "RME Digi96", "" } , - { 0x10EE, 0x3FC1, "RME Digi96/8", "" } , - { 0x10EE, 0x3FC2, "RME Digi 96/8 Pro", "" } , - { 0x10EE, 0x3FC3, "RME Digi96/8 Pad", "RME Digi96/8 Pad" } , - { 0x10EE, 0x3FC4, "Digi9652", "Hammerfall" } , - { 0x10EE, 0x3FC5, "0", "HDSP 9632" } , - { 0x10EE, 0x5343, "Seamont SC100", "Security Adapter" } , - { 0x10EE, 0x8130, "Durango PMC", "Virtex-II Bridge, XC2V1000-4FG456C" } , - { 0x10EE, 0x8381, "Santos", "Frame Grabber" } , - { 0x10EE, 0xA123, "XA3S1600E", "Spartan 3E" } , - { 0x10EE, 0xA124, "Spartan 3E", "XA3S1600E" } , - { 0x10EF, 0x8154, "M815x", "Token Ring Adapter" } , - { 0x10F0, 0xA800, "VCL-P", "Graphics board" } , - { 0x10F0, 0xB300, "VCL-M", "graphics board" } , - { 0x10F1, 0x1566, "", "IDE/SCSI" } , - { 0x10F1, 0x1677, "", "Multimedia" } , - { 0x10F1, 0x2013, "RS-56 sp-pci", "Conexant RS-56 PCI Modem" } , - { 0x10F4, 0x1300, "rev1.1", "PCI to S5U13x06B0B Bridge Adapter" } , - { 0x10F5, 0xA001, "NDR4000", "NR4600 Bridge" } , - { 0x10F6, 0x0111, "PCIVEN", "CMI8738/C3DX Multimedia Audio Controller" } , - { 0x10FA, 0x0000, "BT848KPF", "GUI Accelerator" } , - { 0x10FA, 0x0001, "", "GUI Accelerator" } , - { 0x10FA, 0x0002, "", "GUI Accelerator" } , - { 0x10FA, 0x0003, "", "GUI Accelerator" } , - { 0x10FA, 0x0004, "", "GUI Accelerator" } , - { 0x10FA, 0x0005, "", "GUI Accelerator" } , - { 0x10FA, 0x0006, "", "GUI Accelerator" } , - { 0x10FA, 0x0007, "", "GUI Accelerator" } , - { 0x10FA, 0x0008, "", "GUI Accelerator" } , - { 0x10FA, 0x0009, "", "GUI Accelerator" } , - { 0x10FA, 0x000A, "", "GUI Accelerator" } , - { 0x10FA, 0x000B, "", "GUI Accelerator" } , - { 0x10FA, 0x000C, "Targa 1000", "Video Capture & Editing card" } , - { 0x10FA, 0x000D, "", "GUI Accelerator" } , - { 0x10FA, 0x000E, "", "GUI Accelerator" } , - { 0x10FA, 0x000F, "", "GUI Accelerator" } , - { 0x10FA, 0x0010, "", "GUI Accelerator" } , - { 0x10FA, 0x0011, "", "GUI Accelerator" } , - { 0x10FA, 0x0012, "", "GUI Accelerator" } , - { 0x10FA, 0x0013, "", "GUI Accelerator" } , - { 0x10FA, 0x0014, "", "GUI Accelerator" } , - { 0x10FA, 0x0015, "", "GUI Accelerator" } , - { 0x10FB, 0x186f, "TH6255", "" } , - { 0x10FC, 0x8139, "4020011B", "10" } , - { 0x10FD, 0x7E50, "-", "-" } , - { 0x1100, 0x3044, "VT6306L", "IEEE1394 Firewire 3 Port PCI Card" } , - { 0x1101, 0x0002, "INI-920", "Ultra SCSI Adapter" } , - { 0x1101, 0x1060, "INI-A100U2W", "Orchid Ultra-2 SCSI Controller" } , - { 0x1101, 0x134A, "", "Ultra SCSI Adapter" } , - { 0x1101, 0x1622, "INIC1620", "PCI SATA Controller" } , - { 0x1101, 0x9100, "INI-9010/9010W", "Fast Wide SCSI Controller" } , - { 0x1101, 0x9400, "INIC-940", "Fast Wide SCSI Controller" } , - { 0x1101, 0x9401, "INIC-935", "Fast Wide SCSI Controller" } , - { 0x1101, 0x9500, "1101", "SCSI Initio ultra" } , - { 0x1101, 0x9502, "INIC-950P", "Ultrawide SCSI controller" } , - { 0x1101, 0x9700, "", "Fast Wide SCSI" } , - { 0x1102, 0x0002, "t4780010004541", "Sound Blaster Live! (Also Live! 5.1) - OEM from DELL - CT4780" } , - { 0x1102, 0x0003, "EMU8008", "AWE64D OEM (CT4600)" } , - { 0x1102, 0x0004, "Creative SB Audigy 2 ZS (WDM)", "Audigy Audio Processor" } , - { 0x1102, 0x0005, "SB0460", "SoundBlaster X-FI XtremeMusic" } , - { 0x1102, 0x0006, "emu10k1x", "Soundblaster Live! 5.1" } , - { 0x1102, 0x0007, "C6SB0410515017656A", "Audigy ls" } , - { 0x1102, 0x0008, "ca0108", "sound blaster Audigy 2" } , - { 0x1102, 0x006, "emu10k1x", "Soundblaster Live! 5.1" } , - { 0x1102, 0x1017, "CT6760", "3D Blaster Banshee PCI CT6760" } , - { 0x1102, 0x1020, "NV5", "3D Blaster RIVA TNT2" } , - { 0x1102, 0x1047, "EV1938", "3D Blaster Annihilator 2" } , - { 0x1102, 0x1371, "ES1371-3", " ES1373 AudioPCI" } , - { 0x1102, 0x2898, "es2898", "es56t-p1" } , - { 0x1102, 0x4001, "EMU10K1", "Audigy IEEE1394a Firewire Controller" } , - { 0x1102, 0x7002, "EMU10000", "Game Port" } , - { 0x1102, 0x7003, "EMU10K2", "Creative Labs SB Audigy MIDI/Game port" } , - { 0x1102, 0x7004, "6", "Game port for SB Live! Series" } , - { 0x1102, 0x7005, "???", "Audigy LS Series Game Port" } , - { 0x1102, 0x7802, "EMU1OK1-NGF", "Environmental Audio (SB Live)" } , - { 0x1102, 0x8938, "EV1938", "Sound" } , - { 0x1102, 1371, "", "" } , - { 0x1105, 0x5000, "", "Multimedia" } , - { 0x1105, 0x8300, "EM8400", "MPEG-2 Decoder" } , - { 0x1105, 0x8400, "EM8400", "MPEG-2 Decoder" } , - { 0x1105, 0x8475, "EM8475", "MPEG-4 Decoder" } , - { 0x1106, 0x0130, "VT6305", "VIA Fire 1394.A OHCI Link Layer Ctrlr" } , - { 0x1106, 0x0198, "", "CPU to PCI Bridge" } , - { 0x1106, 0x0238, "K8T890", "CPU to PCI Bridge" } , - { 0x1106, 0x0259, "unknown", "Host Bridge" } , - { 0x1106, 0x0269, "KT880", "CPU to PCI Bridge" } , - { 0x1106, 0x0282, "K8T880Pro", "CPU to PCI Bridge" } , - { 0x1106, 0x0305, "VT8363A/8365", "Host Bridge" } , - { 0x1106, 0x0391, "VT8363/71", "Host Bridge" } , - { 0x1106, 0x0501, "VT8501", "Host Bridge" } , - { 0x1106, 0x0505, "82C505", "VLB to PCI Bridge" } , - { 0x1106, 0x0561, "82C570 MV", "IDE Controller" } , - { 0x1106, 0x0571, "VT82C586A/B/VT82C686/A/B/VT823x/A/C", "Bus Master IDE Controller" } , - { 0x1106, 0x0576, "82C576", "P54 Ctrlr" } , - { 0x1106, 0x0581, "CX700", "SATA RAID" } , - { 0x1106, 0x0585, "VT82C585VP/VPX", "Host Bus-PCI Bridge" } , - { 0x1106, 0x0586, "VT82C586VP", "PCI-to-ISA Bridge" } , - { 0x1106, 0x0591, "VT8237S", "VIA VT8237A SATA RAID Controller" } , - { 0x1106, 0x0595, "VT82C595", "Apollo VP2 PCI North Bridge" } , - { 0x1106, 0x0596, "VT82C596", "PCI ISA Bridge" } , - { 0x1106, 0x0597, "VT82C597", "Host Bridge (Apollo VP3)" } , - { 0x1106, 0x0598, "VT82C598", "Host Bridge" } , - { 0x1106, 0x0601, "VIA8601", "System Controller" } , - { 0x1106, 0x0605, "VT82c686b", "PM133 System Control" } , - { 0x1106, 0x0680, "VT82C680", "Apollo P6" } , - { 0x1106, 0x0686, "VT82C686/686A/686B", "PCI-to-ISA bridge" } , - { 0x1106, 0x0691, "VIA VT KN133", "Mainboard" } , - { 0x1106, 0x0692, "", "North Bridge" } , - { 0x1106, 0x0693, "VT82C693", "Host Bridge" } , - { 0x1106, 0x0926, "VT86C926", "Amazon PCI Ethernet Controller" } , - { 0x1106, 0x1000, "82C570MV", "Host Bridge" } , - { 0x1106, 0x1106, "060000A", "ISA Bridge w/IDE" } , - { 0x1106, 0x1204, "???", "CPU to PCI" } , - { 0x1106, 0x1238, "K8T890", "CPU to PCI Bridge" } , - { 0x1106, 0x1259, "unknown", "Host Bridge" } , - { 0x1106, 0x1269, "KT880", "CPU to PCI Bridge" } , - { 0x1106, 0x1282, "K8T880Pro", "CPU to PCI Bridge" } , - { 0x1106, 0x1571, "VT82C416", "IDE Controller" } , - { 0x1106, 0x1595, "VT82C595/97", "Host Bridge" } , - { 0x1106, 0x1708, "0x1708", "VEN_1106&DEV_1708" } , - { 0x1106, 0x2006, "VT6105M", "VIA Rhine III VT6105M Fast Ethernet controller" } , - { 0x1106, 0x204, "K8M400 chipset", "CPU to PCI" } , - { 0x1106, 0x2204, "???", "CPU to PCI" } , - { 0x1106, 0x2238, "K8T890", "CPU to PCI Bridge" } , - { 0x1106, 0x2259, "unknown", "Host Bridge" } , - { 0x1106, 0x2269, "KT880", "CPU to PCI Bridge" } , - { 0x1106, 0x2282, "K8T880Pro", "CPU to PCI Bridge" } , - { 0x1106, 0x3038, "VT83C572/6202/82C586A/B/82C596/A/B/82C686A/B etc", "USB&UHCI" } , - { 0x1106, 0x3038, "VT6202", "4 x USB1.0 PCI controller" } , - { 0x1106, 0x3040, "VT82C586A/B", "APM(or ACPIAPIC?)" } , - { 0x1106, 0x3041, "82C570MV", "ISA Bridge w/IDE" } , - { 0x1106, 0x3043, "VT86C100A", "Rhine 10/100 Ethernet Adapter" } , - { 0x1106, 0x3044, "VT6307", "VIA Fire II 1394a OHCI Link Layer Ctrlr1" } , - { 0x1106, 0x3050, "VT82C596/596A/596", "Power Management and SMBus Controller" } , - { 0x1106, 0x3051, "", "Power Management Controller" } , - { 0x1106, 0x3053, "VT6105M", "Rhine III Management Adapter" } , - { 0x1106, 0x3057, "VT82C686A/B", "ACPI Power Management Controller" } , - { 0x1106, 0x3058, "VT8237", "AC97 Audio Codec (All VIA Chipsets)" } , - { 0x1106, 0x3059, "VT8237", "AC97 Enhanced Audio Controller - the 8251 controller is different" } , - { 0x1106, 0x3065, "VT6102", "Rhine II PCI Fast Ethernet Controller||Used by GERICOM in laptop Webengine Advanced" } , - { 0x1106, 0x3068, "VT82C686A/B&VT8231", "&CC_0000=ACPIAPIC,&CC_0780=MC97 MODEM" } , - { 0x1106, 0x3068, "VT82C686A/B&VT8231", "APM(or ACPI?)" } , - { 0x1106, 0x3068, "VT82C686A/B&VT8231", "MC97 MODEM" } , - { 0x1106, 0x3074, "VT8233", "PCI to ISA Bridge" } , - { 0x1106, 0x3086, "VT82C686", "Power" } , - { 0x1106, 0x3091, "VT8633", "CPU to PCI Bridge" } , - { 0x1106, 0x3099, "VT8366/66A/67", "CPU to PCI Bridge" } , - { 0x1106, 0x3101, "VT8653", "CPU to PCI Bridge" } , - { 0x1106, 0x3102, "VT8362", "CPU to PCI Bridge" } , - { 0x1106, 0x3103, "VT8615", "CPU to PCI Bridge" } , - { 0x1106, 0x3104, "VT6202", "USB 2.0 Enhanced Host Controller" } , - { 0x1106, 0x3106, "VT6105M/LOM", "Rhine III PCI Fast Ethernet Controller" } , - { 0x1106, 0x3107, "VT8233/A AC97' Enhance Audio Controller", "PCI to ISA Bridge" } , - { 0x1106, 0x3108, "Unknown", "Via Unichrome S3 VGA - part of a VIA Northbridge" } , - { 0x1106, 0x3109, "VT8233/A AC97' Enhance Audio Controller", "PCI to ISA Bridge" } , - { 0x1106, 0x3112, "VT8361", "CPU to PCI Bridge" } , - { 0x1106, 0x3113, "", "PCI to PCI Bridge" } , - { 0x1106, 0x3116, "VT8375", "CPU-to-PCI Bridge" } , - { 0x1106, 0x3118, "CN400", "Via Built-In VGA S3 Graphics UniChrome� Pro IGP Series CN400" } , - { 0x1106, 0x3119, "VT6120/VT6121/VT6122", "'Velocity' Gigabit Ethernet Controllers" } , - { 0x1106, 0x3122, "VT8623", "CastleRock AGP 8X Controller" } , - { 0x1106, 0x3123, "VT8623", "CPU to PCI Bridge" } , - { 0x1106, 0x3128, "vt8753", "CPU-to-PCI Bridge" } , - { 0x1106, 0x3133, "VT3133", "CPU to PCI Bridge" } , - { 0x1106, 0x3147, "VT8233", "PCI to ISA Bridge" } , - { 0x1106, 0x3148, "VT8751", "CPU-to-PCI Bridge" } , - { 0x1106, 0x3149, "VT8237 Family/ VT6420", "SATA RAID Controller" } , - { 0x1106, 0x3156, "VT8372", "CPU to PCI Bridge" } , - { 0x1106, 0x3158, "", "CPU-to-PCI Bridge" } , - { 0x1106, 0x3164, "VT6410", "VIA VT6410 PATA/PATA RAID Controller" } , - { 0x1106, 0x3168, "VT8374", "P4X400 Host Controller/AGP Bridge" } , - { 0x1106, 0x3177, "VT8235", "PCI to ISA Bridge" } , - { 0x1106, 0x3178, "", "CPU to PCI Bridge" } , - { 0x1106, 0x3188, "K8HTB-8237", "CPU to PCI Bridge" } , - { 0x1106, 0x3189, "VT8377", "CPU to PCI Bridge" } , - { 0x1106, 0x3198, "VEN_1106&DEV_B198&SUBSYS_00000000&REV_00", "CPU-to-PCI Bridge" } , - { 0x1106, 0x3202, "", "CPU to PCI Bridge" } , - { 0x1106, 0x3204, "1394 i2c", "CPU to PCI Bridge" } , - { 0x1106, 0x3205, "", "CPU to PCI Bridge" } , - { 0x1106, 0x3208, "PT890", "CPU to PCI Bridge" } , - { 0x1106, 0x3209, "", "CPU to PCI Bridge" } , - { 0x1106, 0x3213, "", "PCI to PCI Bridge" } , - { 0x1106, 0x3227, "VT8237", "PCI-to-ISA Bridge" } , - { 0x1106, 0x3230, "K8N890CE Display Driver", "Integrated Graphics" } , - { 0x1106, 0x3238, "K8T890", "CPU-to-PCI Bridge" } , - { 0x1106, 0x3249, "VT6421", "VIA VT6421 RAID Controller" } , - { 0x1106, 0x3258, "PT880", "CPU-to-PCI Bridge" } , - { 0x1106, 0x3259, "???", "CPU to PCI Bridge" } , - { 0x1106, 0x3269, "KT880", "CPU to PCI Bridge" } , - { 0x1106, 0x3282, "K8T880Pro", "CPU to PCI Bridge" } , - { 0x1106, 0x3288, "040300", "VIA VT8251/8237A High Definition Audio Controller - HDA Codec Realtek ALC660" } , - { 0x1106, 0x3343, "81CE1043", "?" } , - { 0x1106, 0x3344, "P4M800PRO&8237R", "VIA/S3G UniChrome Pro IGP" } , - { 0x1106, 0x3349, "VT8251", "VIA VT8251 AHCI RAID Controller" } , - { 0x1106, 0x3371, "P4M900", "VIA Chrome9 HC IGP" } , - { 0x1106, 0x4149, "VT6420", "PATA" } , - { 0x1106, 0x4204, "???", "CPU to PCI Bridge" } , - { 0x1106, 0x4238, "???", "CPU to PCI Bridge" } , - { 0x1106, 0x4258, "???", "CPU to PCI Bridge" } , - { 0x1106, 0x4259, "???", "CPU to PCI Bridge" } , - { 0x1106, 0x4269, "KT880", "CPU to PCI Bridge" } , - { 0x1106, 0x4282, "K8T880Pro", "CPU to PCI Bridge" } , - { 0x1106, 0x5030, "VT82C596", "ACPI Power Management Controller" } , - { 0x1106, 0x6100, "VIA VT86C100A", "Rhine II PCI Fast SATA and ethernet controller" } , - { 0x1106, 0x7204, "K8M400", "CPU to PCI Bridge" } , - { 0x1106, 0x7205, "KM400", "VIA Technologies, Inc. VT8378 [S3 UniChrome] Graphics Adapter" } , - { 0x1106, 0x7238, "K8T890", "CPU to PCI Bridge" } , - { 0x1106, 0x7258, "PT880", "CPU to PCI Bridge" } , - { 0x1106, 0x7259, "PM880", "CPU to PCI Bridge" } , - { 0x1106, 0x7269, "KT880", "CPU to PCI Bridge" } , - { 0x1106, 0x7282, "K8T880Pro", "CPU to PCI Bridge" } , - { 0x1106, 0x7353, "CX700", "SATA RAID" } , - { 0x1106, 0x7372, "VT8237", "SATA RAID" } , - { 0x1106, 0x8208, "PT890?", "PCI to AGP Bridge" } , - { 0x1106, 0x8231, "VT8231", "PCI to ISA Bridge" } , - { 0x1106, 0x8235, "VT8751", "vga" } , - { 0x1106, 0x8237, "VT8237", "AC97 Enhanced Audio Controller - the 8251 controller is different" } , - { 0x1106, 0x8305, "VT8363A/65", "PCI to AGP Bridge" } , - { 0x1106, 0x8391, "VT8363/71", "PCI to AGP Bridge" } , - { 0x1106, 0x8501, "VT8501", "PCI to AGP Bridge" } , - { 0x1106, 0x8596, "VT82C596", "PCI to AGP Bridge" } , - { 0x1106, 0x8597, "VT82C597", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0x8598, "VT82C598", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0x8601, "VT82C601", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0x8602, "", "CPU to AGP Bridge" } , - { 0x1106, 0x8605, "VT8605", "PCI-to-PCI Bridge(AGP)" } , - { 0x1106, 0x8691, "VT82C691/693A/694X", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0x8693, "VT82C693", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0x9238, "K8T890", "I/O APIC" } , - { 0x1106, 0x9398, "VT8601", "2D/3D Graphics Accelerator" } , - { 0x1106, 0x9876, "VT8233/A AC97' Enhance Audio Controller", "PCI to ISA Bridge" } , - { 0x1106, 0xA208, "PT890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xA238, "K8T890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xB091, "VT8633", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB099, "VT8366/A", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB101, "VT8653", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB102, "VT8362", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB103, "VT8615", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB112, "VT8361", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB113, "", "I/O APIC" } , - { 0x1106, 0xB115, "VT8363/65", "CPU to AGP Controller" } , - { 0x1106, 0xB116, "VT8375", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB133, "vt686b", "CPU to AGP Controller" } , - { 0x1106, 0xB148, "VT8751 Apollo", "PCI-to-Host" } , - { 0x1106, 0xB156, "VT8372", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB158, "", "PCI-to-PCI Bridge (AGP)" } , - { 0x1106, 0xB168, "VT8235", "PCI-to-PCI Bridge (AGP 2.0/3.0)" } , - { 0x1106, 0xB188, "3200+", "PCI-to-PCI Bridge (AGP 2.0/3.0)" } , - { 0x1106, 0xB198, "546546", "PCI-to-PCI Bridge (AGP 2.0/3.0)" } , - { 0x1106, 0xB213, "", "I/O APIC" } , - { 0x1106, 0xC208, "PT890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xC238, "K8T890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xD208, "PT890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xD213, "", "PCI to PCI Bridge" } , - { 0x1106, 0xD238, "K8T890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xE208, "PT890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xE238, "K8T890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xF208, "PT890", "PCI-to-PCI Bridge" } , - { 0x1106, 0xF238, "K8T890", "PCI-to-PCI Bridge" } , - { 0x1107, 0x8576, "", "PCI Host Bridge" } , - { 0x1108, 0x0100, "p1690plus-AA", "Token Ring Adapter" } , - { 0x1108, 0x0101, "p1690plus-AB", "2-Port Token Ring Adapter" } , - { 0x1108, 0x0105, "P1690Plus", "Token Ring Adapter" } , - { 0x1108, 0x0108, "P1690Plus", "Token Ring Adapter" } , - { 0x1108, 0x0138, "P1690Plus", "Token Ring Adapter" } , - { 0x1108, 0x0139, "P1690Plus", "Token Ring Adapter" } , - { 0x1108, 0x013C, "P1690Plus", "Token Ring Adapter" } , - { 0x1108, 0x013D, "P1690Plus", "Token Ring Adapter" } , - { 0x1109, 0x1400, "EM110TX", "EX110TX PCI Fast Ethernet Adapter" } , - { 0x110B, 0x0001, "Mpact", "Media Processor" } , - { 0x110B, 0x0002, "GM90C7110VX", "MPACT DVD decoder." } , - { 0x110B, 0x0004, "", "" } , - { 0x13EA, 0x3131, "DS3131", "BoSS Bit Synchronous HDLC Controller" } , - { 0x13EA, 0x3134, "DS3134", "Chateau Channelized T1/E1/HDLC Controller" } , - { 0x13F0, 0x0200, "FFK 8508", "Encore ENL832-TX-ICNT Fast Ethernet PCI Adapter" } , - { 0x13F0, 0x0201, "ST201", "Fast Ehternet Adapter" } , - { 0x13F0, 0x0300, "NX1001", "Network Adapter" } , - { 0x13F0, 0x1023, "NX1101", "Gigabit Ethernet Controller" } , - { 0x13F0, 0x13F0, "-PCIVEN_13F0&DEV_1023&SUBSYS_81801043&REV_414&BC", "ST201 Fast Ethernet Adapter" } , - { 0x13FD, 0x160E, "--", "--" } , - { 0x1400, 0x0001, "", "" } , - { 0x1400, 0x0003, "", "" } , - { 0x1400, 0x0004, "m583mlr", "m583mlr" } , - { 0x1400, 0x1401, "9432 TX", "hd 2600xt" } , - { 0x1409, 0x7168, "40371409", "PCI / ISA Asynchronous UART Signal Chips Solution" } , - { 0x1409, 0x7268, "PCI / ISA IEEE1284 ECP/EPP/SPP/BPP Signal Chips So", "PCI parallel port" } , - { 0x140B, 0x0610, "", "" } , - { 0x140B, 0x615, "NA", "Na" } , - { 0x140B, 0x682, "NA", "NA" } , - { 0x1415, 0x8401, "OX9162", "PCI Interface to local bus" } , - { 0x1415, 0x8403, "OX9162", "Parallel Port" } , - { 0x1415, 0x9500, "OX16PCI954", "Quad UART (disabled)" } , - { 0x1415, 0x9501, "OX16PCI954", "Quad UART" } , - { 0x1415, 0x9505, "OXm16PCI952", "Dual UART" } , - { 0x1415, 0x950A, "OX16PCI954", "Dual PCI UARTS" } , - { 0x1415, 0x950B, "OXCB950", "Integrated High Performance UART" } , - { 0x1415, 0x9510, "OX16PCI954", "PCI Interface (disabled)" } , - { 0x1415, 0x9511, "OX9160", "PCI Interface to 8-bit local bus" } , - { 0x1415, 0x9512, "OX16PCI954", "PCI Interface to 32-bit bus" } , - { 0x1415, 0x9513, "OX16PCI954", "Parallel Port" } , - { 0x1415, 0x9521, "OX16PCI952", "Dual UART" } , - { 0x1415, 0x9523, "OX16PCI952", "Integrated Parallel Port" } , - { 0x141F, 0x6181, "KFIR", "MPEG decoder" } , - { 0x1462, 0x00C1, "NV41.1", "NX6800-TD256E" } , - { 0x1462, 0x4720, "883", "Audio controller" } , - { 0x1462, 0x5071, "883", "Audio controller" } , - { 0x1462, 0x7120, "", "" } , - { 0x1462, 0x7960, "MCP2T", "MCP2T" } , - { 0x1471, 0x0188, "RoadRunner 10", "ADSL PCI" } , - { 0x14A9, 0xad1f, "1", "1" } , - { 0x14B1, 0x1033, "R6795-12", "RH56D-PCI" } , - { 0x14C1, 0x8043, "LANai 9.2 0129", "MyriNet" } , - { 0x14CF, 0x2920, "FPMC-FIO1-F100-1", "Serial I/O Controller aka FPMC-DFLEX64" } , - { 0x14D9, 0x0010, "AP1011/SP1011", "Sturgeon HyperTransport-PCI Bridge" } , - { 0x14E4, 0x034F, "NV36GL?", "???" } , - { 0x14E4, 0x0800, "BCM33xx/47xx", "Sentry5 Chipcommon I/O Controller" } , - { 0x14E4, 0x0804, "BCM33xx/47xx", "Sentry5 PCI Bridge" } , - { 0x14E4, 0x0805, "BCM33xx/47xx", "Sentry5 MIPS32 CPU" } , - { 0x14E4, 0x0806, "BCM33xx/47xx", "Sentry5 Ethernet Controller" } , - { 0x14E4, 0x080B, "BCM33xx/47xx", "Sentry5 Crypto Accelerator" } , - { 0x14E4, 0x080F, "BCM33xx/47xx", "Sentry5 DDR/SDR RAM Controller" } , - { 0x14E4, 0x0811, "BCM33xx/47xx", "Sentry5 External Interface" } , - { 0x14E4, 0x0816, "BCM3302", "Sentry5 MIPS32 CPU" } , - { 0x14E4, 0x14E4, "BCM5787M", "802.11b/g Wireless Lan Controller" } , - { 0x14E4, 0x1600, "BCM5752", "NetXtreme BCM5752 Gigabit Ethernet PCI Express" } , - { 0x14E4, 0x1639, "BCM5709", "NetXtreme II Gigabit Ethernet" } , - { 0x14E4, 0x1644, " BCM5751F", "ven_1102dev_0004" } , - { 0x14E4, 0x1645, "BCM5701", "broadtcomBCM5701 Gigabit Ethernet" } , - { 0x14E4, 0x1646, "BCM5702x1", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x1647, "BCM5703", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x1648, "BCM5704", "NetXtreme Dual Gigabit Adapter" } , - { 0x14E4, 0x164C, "BCM5708", "Broadcom NetXtreme II Gigabit Ethernet Adapter" } , - { 0x14E4, 0x164D, "BCM5702FE", "NetXtreme Fast Ethernet Controller" } , - { 0x14E4, 0x1653, "BCM5788", "Broadcom NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x1654, "BCM5705-", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x1658, "BCM5750", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x1659, "BCM5721", "NetXtreme Gigabit Ethernet PCI Express" } , - { 0x14E4, 0x165A, "94309", "Broadcom NetXtreme BCM5722 Gigabit" } , - { 0x14E4, 0x165D, "BCM5705M", "Broadcom NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x165E, "BCM5705M", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x166a, "BCM5780", "Broadcom NetXtreme Gigabit Ethernet 5780" } , - { 0x14E4, 0x166B, "BCM5780S", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x166D, "BCM5705MFE", "NetXtreme Ethernet 100kB" } , - { 0x14E4, 0x166E, "BCM5705", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x167, "BCM5751F", "NetXtreme Fast Ethernet Controller" } , - { 0x14E4, 0x1672, "BCM5754M", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x1673, "B5755M", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x1676, "BCM5750", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x1677, "BCM5750A1", "NetXtreme Gigabit Ethernet PCI Express" } , - { 0x14E4, 0x1677, "BCM5782", "Broadcom NetExtreme Gigabit Ethernet" } , - { 0x14E4, 0x167A, "BCM5754", "Broadcom NetXtreme Gigabit Ethernet Controller" } , - { 0x14E4, 0x167B, "BCM5755/5780", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x167C, "BCM5750", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x167d, "BCM5751M", "Broadcom NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x167E, "BCM5751FKFB", "vierkant" } , - { 0x14E4, 0x1693, "BCM5787A", "Ethernet Controller Broadcom Netlink Gigabit" } , - { 0x14E4, 0x1696, "BCM5782", "Broadcom NetXtreme Gigabit Ethernet for hp" } , - { 0x14E4, 0x1698, "BCM5784M", "NetLink" } , - { 0x14E4, 0x169A, "BCM5786", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x169B, "BCM5787", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x169C, "BCM5788", "Broadcom NetLink (TM) Gigabit Ethernet" } , - { 0x14E4, 0x169D, "BCM5782k FB", "Broadcom Ethernet Adapter" } , - { 0x14E4, 0x169E, "BCM5754", "NetXtreme Gigabit Ethernet PCI Express" } , - { 0x14E4, 0x16A6, "BCM5702X", "Gigabit Ethernet" } , - { 0x14E4, 0x16A7, "BCM5703X", "Gigabit Ethernet" } , - { 0x14E4, 0x16A8, "BCM5704", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x16AA, "B06BDRV", "BroadCom NetExtreme II Server" } , - { 0x14E4, 0x16C6, "BCM5702A3", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x16C7, "BCM 5703CKHB", "Gigabit Ethernet" } , - { 0x14E4, 0x16DD, "BCM5781", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x16f7, "BCM5753", "NetXtreme BCM5753 Gigabit PCI Express" } , - { 0x14E4, 0x16FD, "BCM5753M", "NetXtreme Gigabit Ethernet PciXpress" } , - { 0x14E4, 0x16FE, "BCM5753F", "NetXtreme Gigabit Ethernet" } , - { 0x14E4, 0x170C, "BCM4401", "Broadcom NetLink 4401 10/100 Ethernet NIC" } , - { 0x14E4, 0x170D, "BCM5901", "NetXtreme" } , - { 0x14E4, 0x170E, "BCM5901", "NetXtreme 100Base-TX" } , - { 0x14E4, 0x1713, "BCM5906m", "Broadcom NetLink (TM) Fast Ethernet" } , - { 0x14E4, 0x3352, "BCM3352", "BCM3352 QAMLink� Single-Chip 4-Line VoIP" } , - { 0x14E4, 0x3360, "BCM3360", "Advanced PHY Broadband Gateway Cable Modem" } , - { 0x14E4, 0x4211, "BCM HPNA", "10Mb/s NIC" } , - { 0x14E4, 0x4212, "BCM V.90", "56k Modem" } , - { 0x14E4, 0x4301, "BCM4301 802.11b", "Dell Truemobile 1180 802.11b MiniPCI" } , - { 0x14E4, 0x4303, "BCM4303", "BCM4301 802.11b802.11b Wireless LAN Controller" } , - { 0x14E4, 0x4305, "BCM4307", "V.90 56k Modem" } , - { 0x14E4, 0x4306, "BCM4306", "Unknown device 4306 (rev 02)" } , - { 0x14E4, 0x4307, "BCM4307", "802.11b Wireless LAN Controller" } , - { 0x14E4, 0x4310, "BCM4310", "BCM4301 802.11bChipcommon I/O Controller" } , - { 0x14E4, 0x4311, "BCM4311", "Broadcom Corporation Dell Wireless 1390 WLAN Mini-PCI Card" } , - { 0x14E4, 0x4312, "BCM4310", "broadcom wireless 1490 (dell)" } , - { 0x14E4, 0x4313, "BCM4310", "usb controller, wireless network card" } , - { 0x14E4, 0x4315, "BCM2046", "Broadcom Wireless " } , - { 0x14E4, 0x4318, "BCM43XX", "Broadcom 802.11b/g" } , - { 0x14E4, 0x4320, "BCM94309", "802.11b/g Wireless LAN Controller" } , - { 0x14E4, 0x4321, "BCM4306", "802.11a Wireless LAN Controller" } , - { 0x14E4, 0x4322, "BCM4306", "UART" } , - { 0x14E4, 0x4323, "BCM4306", "V.90 56k Modem" } , - { 0x14E4, 0x4324, "BCM4309", "802.11a/b/g Wireless LAN Controller" } , - { 0x14E4, 0x4325, "BCM4306", "802.11b/g Wireless LAN Controller" } , - { 0x14E4, 0x4326, "BCM4306", "Chipcommon I/O Controller?" } , - { 0x14E4, 0x4328, "BCM94321KFBG", "Broadcom 4321AGN 802.11a/b/g/draft-n Wi-Fi Solution" } , - { 0x14E4, 0x4329, "?", "?" } , - { 0x14E4, 0x4401, "BCM4401", "10/100 Integrated Ethernet Controller" } , - { 0x14E4, 0x4402, "BCM4402", "10/100 Integrated Ethernet Controller" } , - { 0x14E4, 0x4403, "BCM4402", "V.90 56k Modem" } , - { 0x14E4, 0x4410, "BCM4413", "iLine32 HomePNA 2.0" } , - { 0x14E4, 0x4411, "BCM4212", "V.90 56k Modem" } , - { 0x14E4, 0x4412, "BCM4412", "10/100BaseT Ethernet" } , - { 0x14E4, 0x4430, "BCM44xx", "CardBus iLine32 HomePNA 2.0" } , - { 0x14E4, 0x4432, "BCM44xx", "CardBus 10/100BaseT Ethernet" } , - { 0x14E4, 0x4610, "BCM4610", "Sentry5 PCI to SB Bridge" } , - { 0x14E4, 0x4611, "BCM4610", "Sentry5 iLine32 HomePNA 1.0" } , - { 0x14E4, 0x4612, "BCM4610", "Sentry5 V.90 56k Modem" } , - { 0x14E4, 0x4613, "BCM4610", "Sentry5 Ethernet Controller" } , - { 0x14E4, 0x4614, "BCM4610", "Sentry5 External Interface" } , - { 0x14E4, 0x4615, "BCM4610", "Sentry5 USB Controller" } , - { 0x14E4, 0x4704, "BCM4704", "Sentry5 PCI to SB Bridge" } , - { 0x14E4, 0x4708, "BCM4704", "Crypto Accelerator" } , - { 0x14E4, 0x4710, "BCM4710", "Sentry5 PCI to SB Bridge" } , - { 0x14E4, 0x4711, "BCM47xx", "Sentry5 iLine32 HomePNA 2.0" } , - { 0x14E4, 0x4712, "BCM47xx", "Sentry5 V.92 56k modem" } , - { 0x14E4, 0x4713, "BCM47xx", "Sentry5 Ethernet Controller" } , - { 0x14E4, 0x4714, "BCM47xx", "Sentry5 External Interface" } , - { 0x14E4, 0x4715, "BCM47xx", "Sentry5 USB Controller" } , - { 0x14E4, 0x4716, "BCM47xx", "Sentry5 USB Host Controller" } , - { 0x14E4, 0x4717, "BCM47xx", "Sentry5 USB Device Controller" } , - { 0x14E4, 0x4718, "BCM47xx", "Sentry5 Crypto Accelerator" } , - { 0x14E4, 0x4720, "BCM4712", "MIPS CPU" } , - { 0x14E4, 0x5365, "BCM5365P", "Sentry5 PCI to SB Bridge" } , - { 0x14E4, 0x5600, "BCM5600", "StrataSwitch 24+2 Ethernet Switch Controller" } , - { 0x14E4, 0x5605, "BCM5605", "StrataSwitch 24+2 Ethernet Switch Controller" } , - { 0x14E4, 0x5615, "BCM5615", "StrataSwitch 24+2 Ethernet Switch Controller" } , - { 0x14E4, 0x5625, "BCM5625", "StrataSwitch 24+2 Ethernet Switch Controller" } , - { 0x14E4, 0x5645, "BCM5645", "StrataSwitch 24+2 Ethernet Switch Controller" } , - { 0x14E4, 0x5670, "BCM5670", "8-Port 10GE Ethernet Switch Fabric" } , - { 0x14E4, 0x5680, "BCM5680", "G-Switch 8-Port Gigabit Ethernet Switch Controller" } , - { 0x14E4, 0x5690, "BCM5690", "12-port Multi-Layer Gigabit Ethernet Switch" } , - { 0x14E4, 0x5691, "BCM5691", "GE/10GE 8+2 Gigabit Ethernet Switch Controller" } , - { 0x14E4, 0x5802, "BCM5802", "The BCM5802 Security Processor integrates Broadcom�s IPSec engine (DES, 3DES, HMAC-SHA-1, HMAC-MD5)," } , - { 0x14E4, 0x5805, "BCM5805", "The BCM5805 Security Processor integrates a high-performance IPSec engine (DES, 3DES, HMAC-SHA-1, HM" } , - { 0x14E4, 0x5820, "BCM5820", "Crypto Accelerator" } , - { 0x14E4, 0x5821, "BCM5821", "Crypto Accelerator" } , - { 0x14E4, 0x5822, "BCM5822", "Crypto Accelerator" } , - { 0x14E4, 0x5823, "BCM5823", "Crypto Accelerator" } , - { 0x14E4, 0x5824, "BCM5824", "Crypto Accelerator" } , - { 0x14E4, 0x5840, "BCM5840", "Crypto Accelerator" } , - { 0x14E4, 0x5841, "BCM5841", "Crypto Accelerator" } , - { 0x14E4, 0x5850, "BCM5850", "Crypto Accelerator" } , - { 0x14E4, 0x7321, "BCM5751", "network card integrated" } , - { 0x14E4, 0x7411, "BCM7411", "High Definition Video/Audio Decoder" } , - { 0x14E4, 0x4311, "1364103c", "subsys" } , - { 0x14EB, 0x0020, "BEMx.x", "PCI to S5U13xxxB00B Bridge Adapter" } , - { 0x14EB, 0x0C01, "S1D13808", "Embedded Memory Display Controller" } , - { 0x14F5, 0x2F00, "x", "x" } , - { 0xAA42, 0x03A3, "9400-0931", "CharKey" } , - { 0x14FD, 0x0001, "H260u", "H260u printer server for HP Printer" } , - { 0x165A, 0xC100, "PIXCI CL1", "PCI camera link video capture board" } , - { 0x165A, 0xD200, "PIXCI D2X", "PCI digital video capture board" } , - { 0x165A, 0xD300, "PIXCI D3X", "PCI digital video capture board" } , - { 0x1516, 0x0800, "MTD800", "10/100 Mbps Fast Ethernet Controller" } , - { 0x1516, 0x0803, "Myson MTD803/TAMARACK TC6020", "PCI Ethernet controller" } , - { 0x1516, 0x0891, "MTD891", "10/100/1000 Mbps Gigabit Ethernet Controller" } , - { 0x1112, 0x2200, "2200", "FDDI adapter" } , - { 0x1112, 0x2300, "2300", "Fast Ethernet adapter" } , - { 0x1112, 0X2340, "2340", "4 Port 10/100 UTP Fast Ethernet Adapter" } , - { 0x1112, 0x2400, "2400", "ATM adapter" } , - { 0x1113, 0x1211, "mpx en5038a1", "0A422T1 118F" } , - { 0x1113, 0x1216, "EN5251BE", "accton EN5251BE" } , - { 0x1113, 0x1217, "EN-2242", "Ethernet Adapter" } , - { 0x1113, 0x5105, "EN-1660", "" } , - { 0x1113, 0x9211, "EN-1207D", "Fast Ethernet Adapter" } , - { 0x1113, 0x9511, "SMC en5251be", "0445tabgf16143.1" } , - { 0x1113, 0x9876, "EN5251BE", "Ethernet Controller/ drivers" } , - { 0xA200, 0xa200, "saa1735hl", "tv" } , - { 0x1114, 0x0506, "AT76C506", "802.11b Wireless Network Adaptor" } , - { 0x1114, 0x3202, "AT97SC3202", "TPM - Trusted Platform Module" } , - { 0x1116, 0x0022, "DT3001", "" } , - { 0x1116, 0x0023, "DT3002", "" } , - { 0x1116, 0x0024, "DT3003", "" } , - { 0x1116, 0x0025, "DT3004", "" } , - { 0x1116, 0x0026, "Dt3005", "" } , - { 0x1116, 0x0027, "DT3001-PGL", "" } , - { 0x1116, 0x0028, "DT3003-PGL", "" } , - { 0x1117, 0x9500, "", "max-lc SVGA card" } , - { 0x1117, 0x9501, "", "MaxPCI image processing board" } , - { 0x1119, 0x0000, "GDT6000/6020/6050", "PCI SCSI RAID Controller" } , - { 0x1119, 0x0001, "GDT6000/6010", "PCI 1-channel SCSI RAID Controller" } , - { 0x1119, 0x0002, "GDT6110/6510", "PCI 1-channel SCSI RAID Controller" } , - { 0x1119, 0x0003, "GDT6120/6520", "PCI 2-channel SCSI RAID Controller" } , - { 0x1119, 0x0004, "GDT6530", "PCI 3-channel SCSI RAID Controller" } , - { 0x1119, 0x0005, "GDT6550", "PCI 5-channel SCSI RAID Controller" } , - { 0x1119, 0x0006, "GDT6117/6517", "Wide Ultra SCSI Controller" } , - { 0x1119, 0x0007, "GDT6127/6527", "Wide Ultra SCSI Controller" } , - { 0x1119, 0x0008, "GDT6537", "Wide Ultra SCSI Controller" } , - { 0x1119, 0x0009, "GDT6557/6557-ECC", "Wide Ultra SCSI Controller" } , - { 0x1119, 0x000A, "GDT6115/6515", "Ultra SCSI Controller" } , - { 0x1119, 0x000B, "GDT6125/6525", "Wide SCSI Controller" } , - { 0x1119, 0x000C, "GDT6535", "Wide SCSI Controller" } , - { 0x1119, 0x000D, "GDT6555/6555-ECC", "Wide SCSI Controller" } , - { 0x1119, 0x0100, "GDT6117RP/6517RP", "2 Channel Wide Ultra SCSI" } , - { 0x1119, 0x0101, "GDT6127RP/6527RP", "Wide Ultra SCSI HBA" } , - { 0x1119, 0x0102, "GDT6537RP", "Wide Ultra SCSI HBA" } , - { 0x1119, 0x0103, "GDT6557RP", "Wide Ultra SCSI HBA" } , - { 0x1119, 0x0104, "GDT6111RP/6511RP", "Ultra SCSI HBA" } , - { 0x1119, 0x0105, "GDT6121RP/6521RP", "Ultra SCSI HBA" } , - { 0x1119, 0x0110, "GDT6117RD/6517RD", "Wide Ultra SCSI HBA" } , - { 0x1119, 0x0111, "GDT6127RD/6527RD", "Wide Ultra SCSI HBA" } , - { 0x1119, 0x0112, "GDT6537RD", "Wide Ultra SCSI HBA" } , - { 0x1119, 0x0113, "GDT6557RD", "Wide Ultra SCSI HBA" } , - { 0x1119, 0x0114, "GDT6111RD/6511RD", "Ultra SCSI HBA" } , - { 0x1119, 0x0115, "GDT6127RD/6527RD", "Ultra SCSI HBA" } , - { 0x1119, 0x0118, "GDT6x18RD", "Wide Ultra2 SCSI HBA" } , - { 0x1119, 0x0119, "GDT6x28RD", "Wide Ultra2 SCSI HBA" } , - { 0x1119, 0x011A, "GDT6538RD/6638RD", "Wide Ultra2 SCSI HBA" } , - { 0x1119, 0x011B, "GDT6558RD/6658RD", "Wide Ultra2 SCSI HBA" } , - { 0x1119, 0x0120, "GDT6117RP2/6517RP2", "" } , - { 0x1119, 0x0121, "GDT6127RP2/6527RP2", "" } , - { 0x1119, 0x0122, "GDT6537RP2", "" } , - { 0x1119, 0x0123, "GDT6557RP2", "" } , - { 0x1119, 0x0124, "GDT6111RP2/6511RP2", "" } , - { 0x1119, 0x0125, "GDT6127RP2/6527RP2", "" } , - { 0x1119, 0x0136, "GDT 6x13RS", "" } , - { 0x1119, 0x0137, "GDT 6x23RS", "Disk Array Controller" } , - { 0x1119, 0x0138, "GDT 6x18RS", "" } , - { 0x1119, 0x0139, "GDT 6x28RS", "" } , - { 0x1119, 0x013A, "GDT 6x38RS", "" } , - { 0x1119, 0x013B, "GDT 6x58RS", "" } , - { 0x1119, 0x013C, "GDT 6x33RS", "" } , - { 0x1119, 0x013D, "GDT 6x43RS", "" } , - { 0x1119, 0x013E, "GDT 6x53RS", "" } , - { 0x1119, 0x013F, "GDT 6x63RS", "" } , - { 0x1119, 0x0166, "GDT 7x13RN", "" } , - { 0x1119, 0x0167, "GDT 7x23RN", "" } , - { 0x1119, 0x0168, "GDT7x18RN", "64-bit PCI Wide Untra2 SCSI HBA" } , - { 0x1119, 0x0169, "GDT7x28RN", "64-bit PCI Wide Ultra2 SCSI HBA" } , - { 0x1119, 0x016A, "GDT7538RN/7638RN", "64-bit PCI Wide Ultra2 SCSI HBA" } , - { 0x1119, 0x016B, "GDT7558RN/7658RN", "64-bit PCI Wide Ultra2 SCSI HBA" } , - { 0x1119, 0x016C, "GDT 7x33RN", "" } , - { 0x1119, 0x016D, "GDT 7x43RN", "" } , - { 0x1119, 0x016E, "GDT 7x53RN", "" } , - { 0x1119, 0x016F, "GDT 7x63RN", "" } , - { 0x1119, 0x01D6, "GDT 4x13RZ", "" } , - { 0x1119, 0x01D7, "GDT 4x23RZ", "" } , - { 0x1119, 0x01F6, "GDT 8x13RZ", "" } , - { 0x1119, 0x01F7, "GDT 8x23RZ", "" } , - { 0x1119, 0x01FC, "GDT 8x33RZ", "" } , - { 0x1119, 0x01FD, "GDT 8x43RZ", "" } , - { 0x1119, 0x01FE, "GDT 8x53RZ", "" } , - { 0x1119, 0x01FF, "GDT 8x63RZ", "" } , - { 0x1119, 0x0210, "GDT6519RD/6619RD", "Fibre Channel HBA" } , - { 0x1119, 0x0211, "GDT6529RD/6629RD", "Fibre Channel HBA" } , - { 0x1119, 0x0260, "GDT7519RN/7619RN", "64-bit PCI Fibre Channel HBA" } , - { 0x1119, 0x0261, "GDT7529RN/7629RN", "64-bit PCI Fibre Channel HBA" } , - { 0x1119, 0x0300, "GDT Rx", "" } , - { 0x111A, 0x0000, "155P-MF1", "" } , - { 0x111A, 0x0002, "166P-MF1", "" } , - { 0x111A, 0x0003, "ENI-25P", "ATM Adapter" } , - { 0x111C, 0x0001, "", "Powerbus Bridge" } , - { 0x111D, 0x0001, "IDT77201/211", "NICStAR ATM Adapter" } , - { 0x111D, 0x0003, "IDT77222/252", "MICRO ABR SAR PCI ATM Controller" } , - { 0x111D, 0x0004, "IDT77V252", "MICRO ABR SAR PCI ATM Controller" } , - { 0x111D, 0x76B2, "92HD71B7", "IDT Audio" } , - { 0x111F, 0x4A47, "Precision MX", "Video engine interface" } , - { 0x111F, 0x5243, "", "Frame Capture Bus Interface" } , - { 0x1127, 0x0200, "FireRunner PCA-200", "ATM" } , - { 0x1127, 0x0210, "PCA-200PC", "ATM" } , - { 0x1127, 0x0250, "", "ATM" } , - { 0x1127, 0x0300, "PCA-200E", "ATM adapter" } , - { 0x1127, 0x0310, "", "ATM" } , - { 0x1127, 0x0400, "ForeRunner HE", "ATM Adapter" } , - { 0x8866, 0x1689, "T2-MP3-001", "MP3 player/FM radio/voice recorder 256 Mo flash" } , - { 0x112E, 0x0000, "", "EIDE/hdd and IDE/cd-rom Ctrlr" } , - { 0x112E, 0x000B, "", "EIDE/hdd and IDE/cd-rom Ctrlr" } , - { 0x1130, 0xF211, "0x010", "USB Audio Sound Card" } , - { 0x1131, 0x1131, "Philips Semic", "gthjy" } , - { 0x1131, 0x1131, "7130", "01384E428" } , - { 0x1131, 0x1201, "PTD3000", "VPN IPSEC coprocessor" } , - { 0x1131, 0x1234, "", "EHCI USB 2.0 Controller" } , - { 0x1131, 0x1301, "PTD3210", "SSL Accelerator" } , - { 0x1131, 0x1562, "ISP1561", "EHCI USB 2.0 Controller" } , - { 0x1131, 0x2780, "TDA2780AQ", "TV deflection controller" } , - { 0x1131, 0x3400, "UCB1500", "Modem" } , - { 0x1131, 0x3401, "UCB1500", "Multimedia Audio Device" } , - { 0x1131, 0x5400, "TriMedia TM1000/1100", "Multimedia processor" } , - { 0x1131, 0x5402, "TriMedia TM-1300EH", "Media Processor" } , - { 0x1131, 0x5406, "", "TriMedia PNX1700" } , - { 0x1131, 0x7130, "73c0a1434628", "Philips SAA7135HL Multimedia Capture Device" } , - { 0x1131, 0x7133, "Pinnacle PCTV 110i", "Pinnacle PCTV 110i Capture Device" } , - { 0x1131, 0x7134, "SAA7130", "Hybrid Capture Device" } , - { 0x1131, 0x7145, "d145ah", "ddddf" } , - { 0x1131, 0x7146, "saa7135HL", "PCIVEN_1131&DEV7146" } , - { 0x1131, 0x9730, "SAA9730", "Ethernet controller" } , - { 0x1133, 0x7711, "EiconCard C91", "" } , - { 0x1133, 0x7901, "EiconCard S90", "" } , - { 0x1133, 0x7902, "", "" } , - { 0x1133, 0x7911, "", "" } , - { 0x1133, 0x7912, "", "" } , - { 0x1133, 0x7941, "", "" } , - { 0x1133, 0x7942, "", "" } , - { 0x1133, 0x7943, "", "EiconCard S94" } , - { 0x1133, 0x7944, "", "EiconCard S94" } , - { 0x1133, 0xB921, "", "" } , - { 0x1133, 0xB922, "", "" } , - { 0x1133, 0xB923, "", "EiconCard P92" } , - { 0x1133, 0xE001, "DIVA Pro 2.0 S/T", "" } , - { 0x1133, 0xE002, "DIVA 2.0 S/T", "" } , - { 0x1133, 0xE003, "DIVA Pro 2.0 U", "" } , - { 0x1133, 0xE004, "DIVA 2.0 U", "" } , - { 0x1133, 0xE005, "DIVA 2.01 S/T", "Eicon ISDN card using Siemens IPAC chip" } , - { 0x1133, 0xE00B, "DIVA ISDN 2.02 PCI", "Eicon ISDN card using Infineon chip" } , - { 0x1133, 0xE010, "Maestra", "DIVA Server BRI-2M" } , - { 0x1133, 0xE012, "MaestraQ", "DIVA Server BRI-8M" } , - { 0x1133, 0xE013, "MaestraQ-U", "DIVA Server 4BRI/PCI" } , - { 0x1133, 0xE014, "MaestraP", "DIVA Server PRI-30M" } , - { 0x1133, 0xE015, "", "Diva Server PRI-30M PCI v.2" } , - { 0x1133, 0xE018, "", "DIVA Server BRI-2M/-2F" } , - { 0x1134, 0x0001, "", "Raceway Bridge" } , - { 0x1134, 0x0002, "DPRB", "Dual PCI to RapidIO Bridge" } , - { 0x1135, 0x0001, "", "Printer Cntrlr" } , - { 0x1138, 0x8905, "8905", "STD 32 Bridge" } , - { 0x113C, 0x0000, "PCI9060", "i960 Bridge" } , - { 0x113C, 0x0001, "PCI9060", "i960 Bridge / Evaluation Platform" } , - { 0x113C, 0x0911, "PCI911", "i960Jx I/O Controller" } , - { 0x113C, 0x0912, "PCI912", "i960Cx I/O Controller" } , - { 0x113C, 0x0913, "PCI913", "i960Hx I/O Controller" } , - { 0x113C, 0x0914, "PCI914", "I/O Controller with secondary PCI bus" } , - { 0x113F, 0x0808, "SST-64P", "Adapter" } , - { 0x113F, 0x1010, "SST-128P", "Adapter" } , - { 0x113F, 0x80C0, "", "" } , - { 0x113F, 0x80C4, "", "" } , - { 0x113F, 0x80C8, "", "" } , - { 0x113F, 0x8888, "", "" } , - { 0x113F, 0x9090, "", "" } , - { 0x1141, 0x0001, "", "EIDE/ATAPI super adapter" } , - { 0x1142, 0x3210, "ProMotion 3210", "VGA/AVI Playback Accelerator" } , - { 0x1142, 0x6410, "6410 6422", "GUI Accelerator" } , - { 0x1142, 0x6412, "", "GUI Accelerator" } , - { 0x1142, 0x6420, "", "GUI Accelerator" } , - { 0x1142, 0x6422, "ProMotion-6422", "ProMotion-6422" } , - { 0x1142, 0x6424, "ProVideo 6424", "ProMotion AT24 GUI Accelerator" } , - { 0x1142, 0x6425, "ProMotion AT25", "0752 20005" } , - { 0x1142, 0x6426, "", "GUI Accelerator" } , - { 0x1142, 0x643D, "AT25", "ProMotion-AT3D" } , - { 0x1142, 0x9876, "ProMotion 6422", "139K76B 9808" } , - { 0x1142, 3210, "9809", "139K76B" } , - { 0x1144, 0x0001, "", "Noservo Cntrlr" } , - { 0x1145, 0xF020, "", "CardBus ATAPI Host Adapter" } , - { 0x1145, 0xF021, "NPATA32", "CardBus CompactFlash Adapter" } , - { 0x1145, 0xf024, "NPATA-32", "CardBus CompactFlash Adapter" } , - { 0x1147, 0x1123, "123", "131dq" } , - { 0x1148, 0x4000, "SK-NET", "FDDI adapter" } , - { 0x1148, 0x4200, "", "Token Ring Adapter" } , - { 0x1148, 0x4300, "SysKonnect Genesis", "SK-NET Gigabit Ethernet Adapter" } , - { 0x1148, 0x4320, "Marvell Yukon", "SysKonnect Gigabit Ethernet SK-98xx Version 2.0" } , - { 0x1148, 0x9000, "Marvell Yukon II PCI-X", "PCI-X 10/100/1000Base-T Server" } , - { 0x1148, 0x9E00, "Marvell Yukon EC", "PCI Express 10/100/1000Base-T Desktop" } , - { 0x114A, 0x5565, "VMIPCI-5565", "Ultrahigh-Speed Fiber-Optics Reflective Memory w/ Interrupts" } , - { 0x114A, 0x5579, "VMIPCI-5579", "Reflective Memory Card" } , - { 0x114A, 0x5588, "VMICPCI5588", "VMICPCI5588 Reflective Memory Card" } , - { 0x114A, 0x6504, "", "Timer/SRAM FPGA" } , - { 0x114A, 0x7587, "VMIVME-7587", "" } , - { 0x114D, 0x2189, "0x1002114D", "PCTel HSP56 PCI Modem" } , - { 0x114F, 0x0002, "AccelePort EPC", "" } , - { 0x114F, 0x0003, "RightSwitch SE-6", "" } , - { 0x114F, 0x0004, "AccelePort Xem", "" } , - { 0x114F, 0x0005, "AccelePort Xr", "" } , - { 0x114F, 0x0006, "AccelePort C/X", "" } , - { 0x114F, 0x0007, "DataFire PCI 1 S/T", "Digi Data Fire PCI 1 S/T" } , - { 0x114F, 0x0009, "AccelePort Xr/J", "" } , - { 0x114F, 0x000A, "AccelePort EPC/J", "" } , - { 0x114F, 0x000C, "DataFirePRIme T1", "" } , - { 0x114F, 0x000D, "SyncPort", "X.25/FR 2-port" } , - { 0x114F, 0x0011, "AccelePort8r EIA-232", "" } , - { 0x114F, 0x0012, "AccelePort8r EIA-422", "" } , - { 0x114F, 0x0013, "AccelePort Xr", "" } , - { 0x114F, 0x0014, "AccelePort8r EIA-422", "" } , - { 0x114F, 0x0015, "AccelePort Xem", "" } , - { 0x114F, 0x0016, "AccelePort EPC/X", "" } , - { 0x114F, 0x0017, "AccelePort C/X", "" } , - { 0x114F, 0x0019, "DataFire PCI 1 U", "" } , - { 0x114F, 0x001A, "DataFirePRIme E1", "" } , - { 0x114F, 0x001B, "AccelePort C/X (IBM)", "" } , - { 0x114F, 0x001D, "DataFire RAS", "T1/E1/PRI" } , - { 0x114F, 0x001F, "", "ClydeNonCsu6034" } , - { 0x114F, 0x0020, "", "ClydeNonCsu6032" } , - { 0x114F, 0x0021, "", "ClydeNonCsu4" } , - { 0x114F, 0x0022, "", "ClydeNonCsu2" } , - { 0x114F, 0x0023, "AccelePort RAS", "" } , - { 0x114F, 0x0024, "DataFire RAS B4 ST/U", "" } , - { 0x114F, 0x0026, "AccelePort 4r 920", "" } , - { 0x114F, 0x0027, "AccelePort 8r 920", "" } , - { 0x114F, 0x0029, "DigiClassic PCI", "" } , - { 0x114F, 0x0034, "AccelePort 2r 920", "" } , - { 0x114F, 0x0035, "DataFire DSP", "T1/E1/PRI, Compact PCI" } , - { 0x114F, 0x0040, "AccelePort Xp", "" } , - { 0x114F, 0x0042, "AccelePort 2p PCI", "" } , - { 0x114F, 0x0070, "DataFire Micro V", "" } , - { 0x114F, 0x0071, "DataFire Micro V", "" } , - { 0x114F, 0x0072, "DataFire Micro V", "" } , - { 0x114F, 0x0073, "DataFire Micro V", "" } , - { 0x114F, 0x6001, "Avanstar", "" } , - { 0x1155, 0x0810, "", "486 CPU/PCI Bridge" } , - { 0x1155, 0x0922, "2838", "Pentium CPU/PCI Bridge" } , - { 0x1155, 0x0926, "", "PCI/ISA Bridge" } , - { 0x1158, 0x3011, "", "Tokenet/vg 1001/10m anylan" } , - { 0x1158, 0x9050, "", "Lanfleet/Truevalue" } , - { 0x1158, 0x9051, "", "Lanfleet/Truevalue" } , - { 0x1159, 0x0001, "MV1000", "" } , - { 0x1159, 0x0002, "MV-1500", "Frame Grabber" } , - { 0x115D, 0x0003, "RBEM56G-100", "Cardbus Ethernet 10/100+Modem 56" } , - { 0x115D, 0x0005, "", "CardBus Ethernet 10/100" } , - { 0x115D, 0x0007, "", "CardBus Ethernet 10/100" } , - { 0x115D, 0x000B, "", "CardBus Ethernet 10/100" } , - { 0x115D, 0x000C, "MPCI 3A56GSP-100 PA", "Mini-PCI V.90 56k Modem" } , - { 0x115D, 0x000F, "", "CardBus Ethernet 10/100" } , - { 0x115D, 0x002b, "", "Winmodem built into NEC Versa VXi" } , - { 0x115D, 0x0076, "", "Xircom MPCI3B-56G (Lucent SCORPIO) Soft" } , - { 0x115D, 0x00d3, "2333333333333", "Xircom MPCI Modem 56" } , - { 0x115D, 0x00D4, "MPCI", "Modem 56k" } , - { 0x115D, 0x0101, "", "CardBus 56k Modem" } , - { 0x115D, 0x0103, "", "CardBus Ehternet + 56k Modem" } , - { 0x1161, 0x0001, "", "Host Bridge" } , - { 0x1163, 0x0001, "Verite 1000", "3D Blaster" } , - { 0x1163, 0x2000, "Rendition V2200 (1179-002)", "Rendition V2200 (BLITZ 2200 AGP)" } , - { 0x1165, 0x0001, "", "Motion JPEG rec/play w/audio" } , - { 0x1166, 0x0005, "NB6536 (CNB20-LE)", "PCI to PCI Bridge, bus/dev/func 0/0/1" } , - { 0x1166, 0x0006, "NB6536 (CNB20-HE)", "Host Bridge, function 2 and function 3" } , - { 0x1166, 0x0007, "NB6635 (CNB20-LE/HE)", "CPU to PCI Bridge" } , - { 0x1166, 0x0008, "NB6536 (CNB20-HE)", "Hostbridge & MCH, bus/dev/func 0/0/0" } , - { 0x1166, 0x0009, "NB6536 (CNB20-LE)", "AGP interface" } , - { 0x1166, 0x0010, "CIOB30", "" } , - { 0x1166, 0x0011, "CMIC-HE", "" } , - { 0x1166, 0x0012, "CMIC-LE", "" } , - { 0x1166, 0x0013, "CNB20-HE", "Hostbridge and MCH" } , - { 0x1166, 0x0014, "CNB20-HE", "Host Bridge" } , - { 0x1166, 0x0015, "CMIC-GC", "Hostbridge and MCH" } , - { 0x1166, 0x0016, "CMIC-GC", "Host Bridge" } , - { 0x1166, 0x0017, "CMIC-SL", "" } , - { 0x1166, 0x0101, "CIOB-X2", "" } , - { 0x1166, 0x0103, "BCM5715", "Broadcom dual gigabit, pci bridge" } , - { 0x1166, 0x0110, "CIOB-E", "I/O Bridge with Gigabit Ethernet ServerWorks Grand Champion" } , - { 0x1166, 0x0200, "OSB4", "PCI to ISA Bridge" } , - { 0x1166, 0x0201, "CSB5", "ISA bridge" } , - { 0x1166, 0x0203, "CSB6", "PCI to ISA Bridge" } , - { 0x1166, 0x0211, "OSB4", "EIDE Controller" } , - { 0x1166, 0x0212, "CSB5", "IDE interface" } , - { 0x1166, 0x0213, "OSB6", "PCI EIDE Controller" } , - { 0x1166, 0x0217, "OSB6", "PCI EIDE Controller (Tertiary)" } , - { 0x1166, 0x0220, "OSB4", "OpenHCI Compliant USB Controller" } , - { 0x1166, 0x0221, "OSB6", "OHCI Compliant USB Controller" } , - { 0x1166, 0x0223, "0x0223", "USB controller" } , - { 0x1166, 0x0225, "CSB5", "PCI Bridge" } , - { 0x1166, 0x0227, "CSB6", "PCI Bridge" } , - { 0x1166, 0x0230, "???", "PCI to ISA bridge" } , - { 0x1166, 0x0241, "BC4852", "8-Channel RAIDCore� SATA RAID Host Bus Adapter" } , - { 0x1169, 0x0102, "QL5032", "32 Channel Digital Input Card Interface" } , - { 0x1169, 0x0202, "QL5032", "16 Channel Digital Output, 16 Channel Digital Input Interface" } , - { 0x1169, 0x0302, "QL5032", "32 Channel Analog Input Interface" } , - { 0x1169, 0x0402, "QL5032", "16 Channel Analog Output / Analog Input Interface" } , - { 0x1169, 0x0502, "QL5232", "8 Channel Timer Counter Interface" } , - { 0x1169, 0x0902, "QL5232", "PCI to TigerSHARC FPGA Interface" } , - { 0x1169, 0x2001, "Ql5032-33APQ208C", "PCI to C-DAC RTU bus interface FPGA" } , - { 0x116A, 0x6100, "", "Bus/Tag Channel" } , - { 0x116A, 0x6800, "", "Escon Channel" } , - { 0x116A, 0x7100, "", "Bus/Tag Channel" } , - { 0x116A, 0x7800, "", "Escon Channel" } , - { 0x116E, 0x0015, "VX120", "Fiery EX2000D RIP Card Melbourne VX120" } , - { 0x116E, 0x0500, "Vx500", "Printer ASIC" } , - { 0x1172, 0x0001, "EPF6016ATC144-2", "S CCA5000243A" } , - { 0x1172, 0x0004, "-", "Multi-serial card" } , - { 0x1176, 0x8474, "42000133", "Conexant Multichannel Synchronous Communications Controller (MUSYCC)" } , - { 0x1178, 0xAFA1, "", "Fast Ethernet" } , - { 0x1179, 0x0102, "toshiba america info systems", "Extended PCI IDE Controller" } , - { 0x1179, 0x0103, "", "Extended PCI IDE Controller Type-B" } , - { 0x1179, 0x0179, "0x1179", "pci communication device" } , - { 0x1179, 0x0404, "", "" } , - { 0x1179, 0x0406, "Tecra a2", "Video Capture device" } , - { 0x1179, 0x0407, "", "" } , - { 0x1179, 0x0601, "0555873412", "Toshiba CPU to PCI bridge" } , - { 0x1179, 0x0602, "", "PCI to ISA Bridge for Notebooks" } , - { 0x1179, 0x0603, "ToPIC95", "PCI to CardBus Bridge for Notebooks" } , - { 0x1179, 0x0604, "", "PCI to PCI Bridge for Notebooks" } , - { 0x1179, 0x0605, "", "PCI to ISA Bridge for Notebooks" } , - { 0x1179, 0x0606, "", "PCI to ISA Bridge for Notebooks" } , - { 0x1179, 0x0609, "", "PCI to PCI Bridge for Notebooks" } , - { 0x1179, 0x060A, "ToPIC95B", "Toshiba ToPIC95 CardBus Controller" } , - { 0x1179, 0x060F, "ToPIC97", "CardBus Controller" } , - { 0x1179, 0x0611, "", "PCI to ISA Bridge" } , - { 0x1179, 0x0617, "ToPIC100", "PCI to CardBus Bridge with ZV support" } , - { 0x1179, 0x0618, "", "CPU to PCI and PCI to ISA Bridge" } , - { 0x1179, 0x0701, "vt82c693", "PCI Communication Device" } , - { 0x1179, 0x0804, "0x0804", "Toshiba Smart Media Host Controller" } , - { 0x1179, 0x0805, "PCIVEN_1180&DEV_0592&SUBSYS_828D1033&REV_064&5A9", "SD Card Controller" } , - { 0x1179, 0x0D01, "0x0D01", "FIR Port Type-O" } , - { 0x1179, 0x13A8, "XR17C158/154/152", "Multi-channel PCI UART" } , - { 0x117B, 0x8320, "NOFM12", "USB DEVICE" } , - { 0x117E, 0x0001, "", "Printer Host" } , - { 0x1185, 0x8929, "", "EIDE Controller" } , - { 0x1186, 0x0100, "88e8003", "Ethernet Adapter" } , - { 0x1186, 0x1002, "DFE-550TX/580TX/DFE-550FX", "Fast Ethernet Adapter" } , - { 0x1186, 0x1100, "driv16c003206", "Fast Ethernet Adapter" } , - { 0x1186, 0x1300, "DL10038C or DL10038D (Remark of Realtek RTL-8139)", "Fast Ethernet Adapter" } , - { 0x1186, 0x1301, "DGE-528T ", "Fast Ethernet Adapter" } , - { 0x1186, 0x1340, "DFE-690TXD", "CardBus PC Card" } , - { 0x1186, 0x1561, "DRP-32TXD", "CardBus PC Card" } , - { 0x1186, 0x3065, "14001186", "D-Link DFE-500Tx PCI fast Ethernet adapter Rev.A" } , - { 0x1186, 0x3106, "DFE 530TX+ rev E1", "Fast Ethernet Adapter" } , - { 0x1186, 0x3300, "D-Link Air Wireless Network (DWL-G510)", "IEEE 802.11g PCI card" } , - { 0x1186, 0x3b00, "0x3b001186", "D-LINK DWL-650+" } , - { 0x1186, 0x3c09, "DWL-G510 Version C1", "Ralink RT61" } , - { 0x1186, 0x4000, "DL2000", "Gigabit Ethernet Adapter" } , - { 0x1186, 0x4001, "DFE-650TX", "D Link Fast Ethernet PCMCIA Card" } , - { 0x1186, 0x4300, "dlg10028", "Used on DGE-528T Gigabit adaptor" } , - { 0x1186, 0x4B01, "DGE-530T", "Gigabit Ethernet Adapter" } , - { 0x1186, 0x4C00, "DGE-530T", "Gigabit Ethernet Adapter" } , - { 0x1189, 0x1592, "", "VL/PCI Bridge" } , - { 0x118C, 0x0014, "PCIB", "C-bus II to PCI bus host bridge chip" } , - { 0x118C, 0x1117, "MAC-94C201B3", "Corollary/Intel Memory Controller Chip" } , - { 0x118D, 0x0001, "n/a", "Raptor-PCI framegrabber" } , - { 0x118D, 0x0012, "Model 12", "Road Runner Frame Grabber" } , - { 0x118D, 0x0014, "Model 14", "Road Runner Frame Grabber" } , - { 0x118D, 0x0024, "Model 24", "Road Runner Frame Grabber" } , - { 0x118D, 0x0044, "Model 44", "Road Runner Frame Grabber" } , - { 0x118D, 0x0112, "Model 12", "Road Runner Frame Grabber" } , - { 0x118D, 0x0114, "Model 14", "Road Runner Frame Grabber" } , - { 0x118D, 0x0124, "Model 24", "Road Runner Frame Grabber" } , - { 0x118D, 0x0144, "Model 44", "Road Runner Frame Grabber" } , - { 0x118D, 0x0212, "Model 12", "Road Runner Frame Grabber" } , - { 0x118D, 0x0214, "Model 14", "Road Runner Frame Grabber" } , - { 0x118D, 0x0224, "Model 24", "Road Runner Frame Grabber" } , - { 0x118D, 0x0244, "Model 44", "Road Runner Frame Grabber" } , - { 0x118D, 0x0312, "Model 12", "Road Runner Frame Grabber" } , - { 0x118D, 0x0314, "Model 14", "Road Runner Frame Grabber" } , - { 0x118D, 0x0324, "Model 24", "Road Runner Frame Grabber" } , - { 0x118D, 0x0344, "Model 44", "Road Runner Frame Grabber" } , - { 0x118E, 0x0042, "", "" } , - { 0x118E, 0x0142, "", "" } , - { 0x118E, 0x0242, "", "" } , - { 0x118E, 0x0342, "", "" } , - { 0x118E, 0x0440, "", "" } , - { 0x118E, 0x0442, "", "" } , - { 0x118E, 0x0842, "", "" } , - { 0x1191, 0x0001, "", "IDE Ctrlr" } , - { 0x1191, 0x0002, "ATP850UF", "UltraDMA33 EIDE Controller (AEC6210UF)" } , - { 0x1191, 0x0003, "", "SCSI-2 cache Cntrlr" } , - { 0x1191, 0x0004, "ATP8400", "UltraDMA33 EIDE Controller" } , - { 0x1191, 0x0005, "ATP850UF", "UltraDMA33 EIDE Controller (AEC6210UF)" } , - { 0x1191, 0x0006, "ATP860A", "UltraDMA66 EDIE Controller (AEC6260)" } , - { 0x1191, 0x0007, "ATP860R", "UltraDMA66 EIDE Controller (AEC6260)" } , - { 0x1191, 0x0008, "ATP865", "2CH PCI UltraDMA133 IDE Controller" } , - { 0x1191, 0x0009, "ATP865", "2CH PCI UltraDMA133 IDE Controller" } , - { 0x1191, 0x000a, "aec6885", "ACARD AEC-6885/6895/6896 RAID Controller" } , - { 0x1191, 0x000B, "AEC6897/6898", "ACARD AEC-6897/6898 RAID Controller" } , - { 0x1191, 0x000D, "ATP8620", "2S1P PCI-X SATA(3G)/UDMA Combo Controller" } , - { 0x1191, 0x8001, "ATP8600", "SCSI-2 RAID (cache?) Adapter (AEC6820U)" } , - { 0x1191, 0x8002, "ATP850S", "SCSI-2 Host Adapter (AEC6710L/F/s)" } , - { 0x1191, 0x8010, "ATP870", "Ultra Wide SCSI Controller" } , - { 0x1191, 0x8020, "ATP870", "Ultra SCSI Controller" } , - { 0x1191, 0x8030, "ATP870", "Ultra SCSI Controller" } , - { 0x1191, 0x8040, "ATP870", "SCSI Controller" } , - { 0x1191, 0x8050, "", "Ultra Wide SCSI Controller" } , - { 0x1191, 0x8060, "AEC671x", "SCSI Host Adapter" } , - { 0x1191, 0x8081, "AEC-67160", "PCI Ultra160 LVD/SE SCSI Adapter" } , - { 0x1191, 0x808A, "ATP885", "AEC67162 PCI Ultra3 LVD/SE Controller" } , - { 0x1197, 0x010C, "CompuScope 82G", "8-bit 2GS/s Analog Input Card" } , - { 0x1199, 0x0001, "", "IRMA 3270 PCI Adapter" } , - { 0x1199, 0x0002, "", "Advanced ISCA PCI Adapter" } , - { 0x1199, 0x0201, "", "SDLC PCI Adapter" } , - { 0x119B, 0x1221, "82C092G", "PCI PCMCIA bridge" } , - { 0x119E, 0x0001, "MB86697", "FireStream 155 ATM adapter" } , - { 0x119E, 0x0003, "MB86695", "FireStream 50 ATM adapter" } , - { 0xECC0, 0x0050, "", "" } , - { 0xECC0, 0x0051, "", "" } , - { 0xECC0, 0x0060, "", "" } , - { 0xECC0, 0x0070, "", "" } , - { 0xECC0, 0x0071, "", "" } , - { 0xECC0, 0x0072, "", "" } , - { 0xECC0, 0x0080, "", "" } , - { 0x11A8, 0x7302, "", "NTX-8023-PCI 2MB Long Card" } , - { 0x11A8, 0x7308, "", "NTX-8023-PCI 8MB Long Card" } , - { 0x11A8, 0x7402, "", "NTX-8023-PCI 2MB Short Card" } , - { 0x11A8, 0x7408, "", "NTX-8023-PCI 8MB Short Card" } , - { 0x11A9, 0x4240, "AMCC S5933Q", "pci matchmaker 9622qac" } , - { 0x11AB, 0x0146, "GT-64010/A", "System Ctrlr for R4xxx/5000 Family CPUs" } , - { 0x11AB, 0x11AB, "88E8055 PCI-E", "Gigabit Ethernet Controler" } , - { 0x11AB, 0x11AB, "88E8055", "Marvell Yukon 88E8055 PCI-E Gigabit Ethernet Controller" } , - { 0x11AB, 0x13F8, "W8300", "802.11 Adapter" } , - { 0x11AB, 0x1fa6, "88W8300", "The Libertas WLAN 802.11b/g" } , - { 0x11AB, 0x1FA7, "00000000", "Libertas WLAN 802.11b/g" } , - { 0x11AB, 0x1FAA, "8335", "Marvell Libertas 802.11b/g Wireless (8335)" } , - { 0x11AB, 0x2A30, "88W8687", "PCI-Express 802.11bg Wireless" } , - { 0x11AB, 0x4320, "88E8058", "Marvell Yukon PCI E Gigabit" } , - { 0x11AB, 0x4350, "88E8036", "Yukon PCI-E Fast Ethernet Controller" } , - { 0x11AB, 0x4351, "88E8038", "Yukon PCI-E Fast Ethernet Controller" } , - { 0x11AB, 0x4352, "88E8038", "Marvell Yukon 88E8038 PCI-E Fast Ethernet Controller" } , - { 0x11AB, 0x4353, "88E8039 - http://www.marvell.com/drivers/driverDis", "Gigabit" } , - { 0x11AB, 0x4354, "88E8040", "Marvell Yukon 88E8040 PCI-E Fast Ethernet Controller" } , - { 0x11AB, 0x4355, "88E8040T", "Marvell Yukon 88E8040T PCI-E Fast Ethernet Controller" } , - { 0x11AB, 0x4360, "88E8050", "Yukon PCI-E ASF Gigabit Ethernet Controller" } , - { 0x11AB, 0x4361, "88E8036", "Marvell Yukon -EC 88E8036 PCI Express Fast Ethernet Controller" } , - { 0x11AB, 0x4362, "88E8053", "Marvell Yukon 88E8053 PCI-E Gigabit Ethernet Controller" } , - { 0x11AB, 0x4363, "88E8053", "Yukon PCI-E Gigabit Ethernet Controller" } , - { 0x11AB, 0x4364, "88E8056", "Yukon PCI-E Gigabit Ethernet Controller" } , - { 0x11AB, 0x4365, "88E8070", "Yukon Gigabit Controller" } , - { 0x11AB, 0x436A, "88E8058", "Marvell Yukon 88E8058" } , - { 0x11AB, 0x436b, "88E8072", "Gigabit Ethernet" } , - { 0x11AB, 0x4611, "GT-64115", "System Controller" } , - { 0x11AB, 0x4620, "GT-64120", "System Controller for R5000 & R7000 (64-bit PCI)" } , - { 0x11AB, 0x4801, "GT-48001", "8 port switched ethernet ctrlr" } , - { 0x11AB, 0x4809, "EV-48300", "Evaluation board for the GT-48300" } , - { 0x11AB, 0x5005, "F5D5005", "Belkin Desktop Gigabit PCI card" } , - { 0x11AB, 0x5040, "88SX5040", "4-port SATA I PCI-X Controller" } , - { 0x11AB, 0x5041, "88SX504", "4-port SATA I PCI-X Controller" } , - { 0x11AB, 0x5080, "RocketRAID 182x", "SATA Controller" } , - { 0x11AB, 0x5081, "RocketRAID 182x", "SATA Controller" } , - { 0x11AB, 0x6041, "MV88SX6041", "Marvell Technology Group Ltd. MV88SX6041 4-port SATA II PCI-X Controller (rev 03)" } , - { 0x11AB, 0x6081, "?", "SATA II PCI-X Controller" } , - { 0x11AB, 0x6101, "88SE6101", "PATA 133 One Channel" } , - { 0x11AB, 0x6111, "?", "61xx RAID" } , - { 0x11AB, 0x6120, "?", "61xx RAID" } , - { 0x11AB, 0x6121, "88SE6121", "61xx RAID" } , - { 0x11AB, 0x6122, "?", "61xx RAID" } , - { 0x11AB, 0x6140, "?", "61xx RAID" } , - { 0x11AB, 0x6145, "88SE6145", "Add-on IC to provide 4x SATA Ports, attached to ICH7 (SthBridge?) via PCI-Express." } , - { 0x11AB, 0x6320, "GT-64130/131", "System Controller for PowerPC Processors" } , - { 0x11AB, 0x6440, "?", "64xx/63xx SAS" } , - { 0x11AB, 0x6480, "?", "64xx/63xx SAS" } , - { 0x11AB, 0x6485, "MV6446x", "System Controller for PowerPC Processors, Revision B" } , - { 0x11AB, 0x9653, "GT-96100A", "Advanced Communication Controller" } , - { 0x11AB, 0xF003, "GT-64010", "Primary Image Piranha Image Generator" } , - { 0x11AB, 0xF004, "GT64120", "Primary Image Barracuda Image Generator" } , - { 0x11AB, 0xF006, "GT-64120A", "Primary Image Cruncher Geometry Accelerator" } , - { 0x11AB, 0xFFFF, "88SA8040", "PATA2SATA/SATA2PATA Bridge" } , - { 0x11AD, 0x0001, "LC82C168?", "Fast Ethernet Adapter" } , - { 0x11AD, 0x0002, "LC82C169C", "NETGEAR FA310TX Fast Ethernet PCI Adapter" } , - { 0x11AD, 0xC115, "LC82C115", "PNIC II PCI MAC/PHY" } , - { 0x11AE, 0x4153, "", "Bridge Controller" } , - { 0x11AE, 0x5842, "", "Bridge Controller" } , - { 0x11AF, 0x0001, "9704", "Cinema" } , - { 0x11AF, 0x000A, " ", "Nitris" } , - { 0x11AF, 0x000B, " ", "Nitris DX / Mojo DX" } , - { 0x11B0, 0x0001, "V960PBC/PSC", "i960 Local Bus to PCI Bridge" } , - { 0x11B0, 0x0002, "V961PBC/PSC", "i960Jx Local Bus to PCI Bridge" } , - { 0x11B0, 0x0004, "V962PBC/PSC", "i960Cx/Hx Local Bus to PCI Bridge" } , - { 0x11B0, 0x0010, "V292PBC/PSC", "Am29K Local Bus to PCI Bridge" } , - { 0x11B0, 0x0021, "V363EPC", "i960Sx Local Bus to PCI Bridge" } , - { 0x11B0, 0x0022, "V363EPC", "i960Jx Local Bus to PCI Bridge" } , - { 0x11B0, 0x0024, "V363EPC", "i960Cx/Hx Local Bus to PCI Bridge" } , - { 0x11B0, 0x0030, "V363EPC", "Am29K Local Bus to PCI Bridge" } , - { 0x11B0, 0x0100, "V320USC", "PCI System Ctrlr for 32-bit MIPS CPU" } , - { 0x11B0, 0x0101, "V320USC", "PCI System Ctrlr for 32-bit MIPS CPU" } , - { 0x11B0, 0x0102, "V320USC", "PCI System Ctrlr for Super-H SH3 CPU" } , - { 0x11B0, 0x0103, "V320USC", "PCI System Ctrlr for Super-H SH4 CPU" } , - { 0x11B0, 0x0200, "V370PDC", "High Performance PCI SDRAM Controller" } , - { 0x11B0, 0x0292, "V292PBC", "Am29030/40 Bridge" } , - { 0x11B0, 0x0500, "V340HPC", "PCI System Ctrlr for 64-bit MIPS CPU" } , - { 0x11B0, 0x0960, "V96xPBC", "i960 Bridges for i960 Processors" } , - { 0x11B0, 0xC960, "V96DPC", "i960 Dual PCI Bridge" } , - { 0x11B5, 0x0001, "PMC/PMX1553", "1553 Bus Interface Card" } , - { 0x11B5, 0x0002, "PMCF1", "FLASH memory Card" } , - { 0x11B5, 0x0003, "PMCMMA", "Multi Media Adapter" } , - { 0x11B5, 0x0004, "PMCVGO", "Video Graphics Overlay" } , - { 0x11B5, 0x0005, "PMCPCIS", "PPzero Slave Interface Card" } , - { 0x11B5, 0x0006, "PMCPCIM", "PPzero Master Interface Card" } , - { 0x11B5, 0x0007, "PMCQ1", "Serial/1553 Interface Card" } , - { 0x11B5, 0x0008, "EPMCQ2", "Intelligent Serial/Ethernet Card" } , - { 0x11B5, 0x0009, "PMCPIO1", "Parallel I/O Module" } , - { 0x11B5, 0x000a, "PMCFA1C", "Fibre Channel Adapter" } , - { 0x11B5, 0x000b, "PMCHH1", "High Speed DSP Gateway Module" } , - { 0x11B5, 0x000c, "PMCMA2", "Memory Adaptor Module" } , - { 0x11B5, 0x0012, "PMCF1", "FLASH memory Card (V2)" } , - { 0x11B5, 0x0013, "PMC1553EX", "1553 Bus Interface Card" } , - { 0x11B5, 0x0014, "PMC1553E", "1553 Bus Interface Card" } , - { 0x11B5, 0x2200, "PMCFA2C", "Dual Fibre Channel Adapter" } , - { 0x0070, 0x6800, " ", "Hauppage Nova -TD-500 DVB-T Tuner Device" } , - { 0x11B8, 0x0001, "Quad PeerMaster", "" } , - { 0x11B9, 0xC0ED, "SSA Ctrlr", "" } , - { 0x11BC, 0x0001, "NPI NuCard", "PCI FDDI" } , - { 0x11BD, 0x0015, "660806-2.0", "rob2d" } , - { 0x11BD, 0xBEBE, "51011810", "pinnacle, bendino V1.0A | Studio MovieBoard 500-PCI V.10" } , - { 0x11BD, 0xBEDE, "51016494", "MB87J3560" } , - { 0x11C1, 0x0440, "LT Winmodem 56k", "Data+Fax+Voice+DSVD" } , - { 0x11C1, 0x0441, "4390143", "modem driver" } , - { 0x11C1, 0x0442, "1648T00", "LT WinModem 56K Data+Fax" } , - { 0x11C1, 0x0443, "LT Winmodem", "1646T00" } , - { 0x11C1, 0x0444, "LT Winmodem", "845G" } , - { 0x11C1, 0x0445, "LT Winmodem", "" } , - { 0x11C1, 0x0446, "LT Winmodem", "" } , - { 0x11C1, 0x0447, "LT Winmodem", "windowsme" } , - { 0x11C1, 0x0448, "LT Winmodem 56k", "SV2P2" } , - { 0x11C1, 0x0449, "LT Winmodem 56k", "0449144F" } , - { 0x11C1, 0x044A, "LT Winmodem 56k", "" } , - { 0x11C1, 0x044B, "LT Winmodem", "" } , - { 0x11C1, 0x044C, "LT Winmodem", "9M56PML-G" } , - { 0x11C1, 0x044D, "LT Winmodem", "" } , - { 0x11C1, 0x044E, "12232", "LT WinModem 56k Data+Fax or Agere F-1156IV/A3" } , - { 0x11C1, 0x044F, "90094-1", "LT V.90+DSL WildFire Modem" } , - { 0x11C1, 0x0450, "1456VQH19R-1(INT)", "LT Winmodem 56K" } , - { 0x11C1, 0x0451, "LT Winmodem", "LT WinModem 56k Data+Fax+Voice+DSVD" } , - { 0x11C1, 0x0452, "LT Winmodem", "1513144" } , - { 0x11C1, 0x0453, "LT Winmodem", "" } , - { 0x11C1, 0x0454, "LT Winmodem", "" } , - { 0x11C1, 0x0455, "LT Winmodem", "" } , - { 0x11C1, 0x0456, "LT Winmodem", "" } , - { 0x11C1, 0x0457, "LT Winmodem", "" } , - { 0x11C1, 0x0458, "1648C", "Mars 3 Mercury v.92 v.44" } , - { 0x11C1, 0x0459, "LT Winmodem", "" } , - { 0x11C1, 0x045A, "LT Winmodem", "" } , - { 0x11C1, 0x045D, "LT WinModem", "mars2" } , - { 0x11C1, 0x0461, "", "V90 Wildfire Modem" } , - { 0x11C1, 0x0462, "1690", "56K.V90/ADSL Wildwire Modem" } , - { 0x11C1, 0x0464, "This is NOT a Riptide! (as previously stated)", "Lucent Wildwire v.90 + DSL modem" } , - { 0x11C1, 0x0480, "Venus Winmodem", "56k.V90/ADSL Wildfire Modem" } , - { 0x11C1, 0x048b, "1648T00", "creative modem blaster di5733-1" } , - { 0x11C1, 0x048C, "1648c-tv5", "creative modem blaster di5733-1" } , - { 0x11C1, 0x048E, "svp92pl-t00", "56k V.92modem" } , - { 0x11C1, 0x048F, "SV92P-T00", "Agere PCI Soft Modem. SV92PL" } , - { 0x11C1, 0x0540, "", "" } , - { 0x11C1, 0x0600, "sv92p2", "SV92P-T00 Agere PCI Soft Modem. SV92PL" } , - { 0x11C1, 0x0620, "SV92PP", "Agere PCI Soft Modem for linux unbuntu" } , - { 0x11C1, 0x1040, "Prespa", "Agere Systems HDA Modem" } , - { 0x11C1, 0x3026, "0x11c13026", "Agere Systems HDA Modem" } , - { 0x11C1, 0x5400, "OR3TP12", "FPSC FPGA with 32/64bit, 33/66MHz core" } , - { 0x11C1, 0x5801, "", "USB Open Host Controller" } , - { 0x11C1, 0x5802, "USS-312MC", "2-port PCI-to-USB OpenHCI Host Ctrlr" } , - { 0x11C1, 0x5803, "USS-344", "QuadraBus 4-port USB OpenHCI Host Ctrlr" } , - { 0x11C1, 0x5805, "uss344", "USB Advanced Host Controller" } , - { 0x11C1, 0x5811, "FW322", "1394A PCI PHY/Link Open Host Ctrlr I/F" } , - { 0x11C1, 0x5901, "unknown", "firewire chip for macbook pro" } , - { 0x11C1, 0x9876, "lucent 1646T00", "LT WinModem 56K Data+Fax" } , - { 0x11C1, 0xAB20, "WaveLAN", "PCI Wireless LAN Adapter" } , - { 0x11C1, 0xAB30, "Hermes2?", "Mini-PCI WaveLAN a/b/g" } , - { 0x11C1, 0xED00, "ET-131x", "PCI-E Ethernet Controller" } , - { 0x11C1, 7121, "", "" } , - { 0x11C6, 0x3001, "1", "VM-1200 Opto Unit Controller" } , - { 0x11C8, 0x0658, "PSB 32", "32 bit , 33 Mhz PCI-SCI Bridge" } , - { 0x11C8, 0xD665, "PSB64", "64 bit , 33 Mhz PCI-SCI Bridge" } , - { 0x11C8, 0xD667, "PSB66", "64 bit , 66 Mhz PCI-SCI Bridge. (D33x)" } , - { 0x11C9, 0x0010, "", "16-line serial port w/DMA" } , - { 0x11C9, 0x0011, "", "4-line serial port w/DMA" } , - { 0x11CB, 0x2000, "PCI-9050-1100083-11", "port small IC" } , - { 0x11CB, 0x4000, "SUPI-1", "XIO/SIO Host" } , - { 0x11CB, 0x8000, "T225", "Bridge RIO Host" } , - { 0x11CE, 0x102B, "1001", "FF00102B" } , - { 0x11D1, 0x01F7, "VxP524", "PCI Video Processor" } , - { 0x11D1, 0x01F8, "VxP524", "PCI Video Processor" } , - { 0x11D1, 0x01f9, "rev_03", "tuner card" } , - { 0x11D1, 0x1520, "tag4769", "Video card" } , - { 0x11D4, 0x1535, "ADSP-21535", "Blackfin DSP PCI Bus Interface" } , - { 0x11D4, 0x1805, "62412-51", "U35545.2-0.6" } , - { 0x11D4, 0x1884, "AD1884HD", "SoundMAX Integrated Digital HD Audio" } , - { 0x11D4, 0x1889, "AD1980", "Sound Chip" } , - { 0x11D4, 0x1981, "AD1981HD", "SoundMAX Integrated Digital HD Audio" } , - { 0x11D4, 0x1983, "AD1983HD", "SoundMAX Integrated Digital HD Audio" } , - { 0x11D4, 0x1984, "Analog Devices ADI 198x", "Analog Devices ADI 198x Integrated HD Audio" } , - { 0x11D4, 0x1986, "AD198b", "SoundMAX Integrated Digital HD Audio" } , - { 0x11D4, 0x198B, "AD1988B", "AD1988B HD Audio CODEC" } , - { 0x11D4, 0x2192, "ADSP-2192", "DSP Microcomputer (function #0)" } , - { 0x11D4, 0x219A, "ADSP-2192", "DSP Microcomputer (function #1)" } , - { 0x11D4, 0x219E, "ADSP-2192", "DSP Microcomputer (function #2)" } , - { 0x11D4, 0x2F44, "ADSP-2141", "SafeNet Crypto Accelerator chip" } , - { 0x11D5, 0x0115, "10115", "Versatec Parallel Interface (VPI) + Centronics" } , - { 0x11D5, 0x0116, "10118", "DR11-W emulator" } , - { 0x11D5, 0x0117, "10117", "Versatec Parallel Interface (VPI) + Centronics" } , - { 0x11D5, 0x0118, "10118", "DR11-W emulator" } , - { 0x1234, 0x1111, "BGE", "VGA BIOS Extensions Graphics Adapter" } , -} ; - - -// Use this value for loop control during searching: -#define PCI_DEVTABLE_LEN (sizeof(PciDevTable)/sizeof(PCI_DEVTABLE)) - -typedef struct _PCI_CLASSCODETABLE -{ - unsigned char BaseClass ; - unsigned char SubClass ; - unsigned char ProgIf ; - const char * BaseDesc ; - const char * SubDesc ; - const char * ProgDesc ; -} PCI_CLASSCODETABLE, *PPCI_CLASSCODETABLE ; - -PCI_CLASSCODETABLE PciClassCodeTable [] = -{ - { 0x00, 0x00, 0x00, "Pre-2.0 PCI Specification Device", "Non-VGA","" } , - { 0x00, 0x01, 0x00, "Pre-2.0 PCI Specification Device", "VGA Compatible", "" } , - - { 0x01, 0x00, 0x00, "Mass Storage Controller", "SCSI", "" } , - { 0x01, 0x01, 0x00, "Mass Storage Controller", "IDE", "" } , - { 0x01, 0x02, 0x00, "Mass Storage Controller", "Floppy", "" } , - { 0x01, 0x03, 0x00, "Mass Storage Controller", "IPI", "" } , - { 0x01, 0x04, 0x00, "Mass Storage Controller", "RAID", "" } , - { 0x01, 0x80, 0x00, "Mass Storage Controller", "Other", "" } , - - { 0x02, 0x00, 0x00, "Network Controller", "Ethernet", "" } , - { 0x02, 0x01, 0x00, "Network Controller", "Token Ring", "" } , - { 0x02, 0x02, 0x00, "Network Controller", "FDDI", "" } , - { 0x02, 0x03, 0x00, "Network Controller", "ATM", "" } , - { 0x02, 0x80, 0x00, "Network Controller", "Other", "" } , - - { 0x03, 0x00, 0x00, "Display Controller", "PC Compatible", "VGA" } , - { 0x03, 0x00, 0x01, "Display Controller", "PC Compatible", "8514" } , - { 0x03, 0x01, 0x00, "Display Controller", "XGA", "" } , - { 0x03, 0x80, 0x00, "Display Controller", "Other", "" } , - - { 0x04, 0x00, 0x00, "Multimedia Device", "Video", "" } , - { 0x04, 0x01, 0x00, "Multimedia Device", "Audio", "" } , - { 0x04, 0x80, 0x00, "Multimedia Device", "Other", "" } , - - { 0x05, 0x00, 0x00, "Memory Controller", "RAM", "" } , - { 0x05, 0x01, 0x00, "Memory Controller", "Flash", "" } , - { 0x05, 0x80, 0x00, "Memory Controller", "Other", "" } , - - { 0x06, 0x00, 0x00, "Bridge Device", "Host/PCI", "" } , - { 0x06, 0x01, 0x00, "Bridge Device", "PCI/ISA", "" } , - { 0x06, 0x02, 0x00, "Bridge Device", "PCI/EISA", "" } , - { 0x06, 0x03, 0x00, "Bridge Device", "PCI/Micro Channel", "" } , - { 0x06, 0x04, 0x00, "Bridge Device", "PCI/PCI", "" } , - { 0x06, 0x05, 0x00, "Bridge Device", "PCI/PCMCIA", "" } , - { 0x06, 0x06, 0x00, "Bridge Device", "PCI/NuBus", "" } , - { 0x06, 0x07, 0x00, "Bridge Device", "PCI/CardBus", "" } , - { 0x06, 0x80, 0x00, "Bridge Device", "Other", "" } , - - { 0x07, 0x00, 0x00, "Simple Communications Controller", "Serial", "Generic XT Compatible" } , - { 0x07, 0x00, 0x01, "Simple Communications Controller", "Serial", "16450 Compatible" } , - { 0x07, 0x00, 0x02, "Simple Communications Controller", "Serial", "16550 Compatible" } , - { 0x07, 0x01, 0x00, "Simple Communications Controller", "Parallel", "Standard" } , - { 0x07, 0x01, 0x00, "Simple Communications Controller", "Parallel", "Bidirectional" } , - { 0x07, 0x01, 0x01, "Simple Communications Controller", "Parallel", "ECP 1.X Compliant" } , - { 0x07, 0x80, 0x02, "Simple Communications Controller", "Other", "" } , - - { 0x08, 0x00, 0x00, "Base Systems Peripheral", "PIC (Programmable Interrupt Controller)", "Generic 8259" } , - { 0x08, 0x00, 0x01, "Base Systems Peripheral", "PIC (Programmable Interrupt Controller)", "ISA" } , - { 0x08, 0x00, 0x02, "Base Systems Peripheral", "PIC (Programmable Interrupt Controller)", "PCI" } , - { 0x08, 0x01, 0x00, "Base Systems Peripheral", "DMA (Direct Memory Access)", "Generic 8259" } , - { 0x08, 0x01, 0x01, "Base Systems Peripheral", "DMA (Direct Memory Access)", "ISA" } , - { 0x08, 0x01, 0x02, "Base Systems Peripheral", "DMA (Direct Memory Access)", "EISA" } , - { 0x08, 0x02, 0x00, "Base Systems Peripheral", "System Timer", "Generic 8259" } , - { 0x08, 0x02, 0x01, "Base Systems Peripheral", "System Timer", "ISA" } , - { 0x08, 0x02, 0x02, "Base Systems Peripheral", "System Timer", "EISA" } , - { 0x08, 0x03, 0x00, "Base Systems Peripheral", "RTC (Real Time Clock)", "Generic" } , - { 0x08, 0x03, 0x01, "Base Systems Peripheral", "RTC (Real Time Clock)", "ISA" } , - { 0x08, 0x80, 0x00, "Base Systems Peripheral", "Other", "" } , - - { 0x09, 0x00, 0x00, "Input Device", "Keyboard", "" } , - { 0x09, 0x01, 0x00, "Input Device", "Digitizer (Pen)", "" } , - { 0x09, 0x02, 0x00, "Input Device", "Mouse", "" } , - { 0x09, 0x80, 0x00, "Input Device", "Other", "" } , - - { 0x0A, 0x00, 0x00, "Docking Station", "Generic", "" } , - { 0x0A, 0x80, 0x00, "Docking Station", "Other", "" } , - - { 0x0B, 0x00, 0x00, "Processor", "i386", "" } , - { 0x0B, 0x01, 0x00, "Processor", "i486", "" } , - { 0x0B, 0x02, 0x00, "Processor", "Pentium", "" } , - { 0x0B, 0x10, 0x00, "Processor", "Alpha", "" } , - { 0x0B, 0x20, 0x00, "Processor", "Power PC", "" } , - { 0x0B, 0x80, 0x00, "Processor", "Co-processor", "" } , - - { 0x0C, 0x00, 0x00, "Serial Bus Controller", "Firewire (IEEE 1394)", "" } , - { 0x0C, 0x01, 0x00, "Serial Bus Controller", "ACCESS.bus", "" } , - { 0x0C, 0x02, 0x00, "Serial Bus Controller", "SSA (Serial Storage Archetecture)", "" } , - { 0x0C, 0x03, 0x00, "Serial Bus Controller", "USB (Universal Serial Bus)", "" } , - { 0x0C, 0x04, 0x00, "Serial Bus Controller", "Fibre Channel", "" } , - - { 0xFF, 0x00, 0x00, "Unknown", "Device Does Not Fit In Class Codes", "UDF" } , -} ; - -// Use this value for loop control during searching: -#define PCI_CLASSCODETABLE_LEN (sizeof(PciClassCodeTable)/sizeof(PCI_CLASSCODETABLE)) - -const char * PciCommandFlags [] = -{ - "I/O Access", - "Memory Access", - "Bus Mastering", - "Special Cycles", - "Memory Write & Invalidate", - "Palette Snoop", - "Parity Errors", - "Wait Cycles", - "System Errors", - "Fast Back-To-Back", - "Reserved 10", - "Reserved 11", - "Reserved 12", - "Reserved 13", - "Reserved 14", - "Reserved 15" -} ; - -// Use this value for loop control during searching: -#define PCI_COMMANDFLAGS_LEN (sizeof(PciCommandFlags)/sizeof(char *)) - - -const char * PciStatusFlags [] = -{ - "Reserved 0", - "Reserved 1", - "Reserved 2", - "Reserved 3", - "Reserved 4", - "66 MHz Capable", - "User-Defined Features", - "Fast Back-To-Back", - "Data Parity Reported", - "", - "", - "Signalled Target Abort", - "Received Target Abort", - "Received Master Abort", - "Signalled System Error", - "Detected Parity Error" -} ; - -// Use this value for loop control during searching: -#define PCI_STATUSFLAGS_LEN (sizeof(PciStatusFlags)/sizeof(char *)) - - -const char * PciDevSelFlags [] = -{ - "Fast Devsel Speed", // TypeC - "Medium Devsel Speed", // TypeB - "Slow Devsel Speed", // TypeA - "Reserved 9&10" -} ; - -// Use this value for loop control during searching: -#define PCI_DEVSELFLAGS_LEN (sizeof(PciDevSelFlags)/sizeof(char *)) - diff --git a/kernel/include/signal_defs.h b/kernel/include/signal_defs.h deleted file mode 120000 index a62c4fb7..00000000 --- a/kernel/include/signal_defs.h +++ /dev/null @@ -1 +0,0 @@ -../../toolchain/patches/newlib/toaru/sys/signal_defs.h \ No newline at end of file diff --git a/kernel/include/syscall_nums.h b/kernel/include/syscall_nums.h deleted file mode 120000 index be6b2a03..00000000 --- a/kernel/include/syscall_nums.h +++ /dev/null @@ -1 +0,0 @@ -../../toolchain/patches/newlib/include/syscall_nums.h \ No newline at end of file diff --git a/kernel/include/termemu.h b/kernel/include/termemu.h deleted file mode 120000 index 84fcb8f4..00000000 --- a/kernel/include/termemu.h +++ /dev/null @@ -1 +0,0 @@ -../../userspace/gui/terminal/lib/termemu.h \ No newline at end of file diff --git a/kernel/include/termios.h b/kernel/include/termios.h deleted file mode 120000 index 1f41bdce..00000000 --- a/kernel/include/termios.h +++ /dev/null @@ -1 +0,0 @@ -../../toolchain/patches/newlib/toaru/sys/termios.h \ No newline at end of file diff --git a/kernel/include/tree.h b/kernel/include/tree.h deleted file mode 100644 index 0fa774d8..00000000 --- a/kernel/include/tree.h +++ /dev/null @@ -1,37 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * General-purpose tree implementation - */ -#pragma once - -#include "list.h" - -typedef struct tree_node { - void * value; - list_t * children; - struct tree_node * parent; -} tree_node_t; - -typedef struct { - size_t nodes; - tree_node_t * root; -} tree_t; - -typedef uint8_t (*tree_comparator_t) (void *, void *); - -tree_t * tree_create(void); -void tree_set_root(tree_t * tree, void * value); -void tree_node_destroy(tree_node_t * node); -void tree_destroy(tree_t * tree); -void tree_free(tree_t * tree); -tree_node_t * tree_node_create(void * value); -void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node); -tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value); -tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle); -void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node); -void tree_node_remove(tree_t * tree, tree_node_t * node); -void tree_remove(tree_t * tree, tree_node_t * node); -tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator); -void tree_break_off(tree_t * tree, tree_node_t * node); - - diff --git a/kernel/include/utsname.h b/kernel/include/utsname.h deleted file mode 120000 index b78897fd..00000000 --- a/kernel/include/utsname.h +++ /dev/null @@ -1 +0,0 @@ -../../toolchain/patches/newlib/toaru/sys/utsname.h \ No newline at end of file diff --git a/kernel/libc.c b/kernel/libc.c index e3779ca6..c61652cd 100644 --- a/kernel/libc.c +++ b/kernel/libc.c @@ -7,7 +7,7 @@ * */ -#include +#include #include #define ALIGN (sizeof(size_t)) diff --git a/kernel/main.c b/kernel/main.c index 1df665b2..2e1e0a6d 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -39,15 +39,16 @@ * WITH THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include uintptr_t initial_esp = 0; @@ -174,6 +175,7 @@ int kmain(struct multiboot *mboot, uint32_t mboot_mag, uintptr_t esp) { syscalls_install(); /* Install the system calls */ shm_install(); /* Install shared memory */ modules_install(); /* Modules! */ + pci_remap(); DISABLE_EARLY_BOOT_LOG(); @@ -257,7 +259,7 @@ int kmain(struct multiboot *mboot, uint32_t mboot_mag, uintptr_t esp) { while (argv[argc]) { argc++; } - system(argv[0], argc, argv); /* Run init */ + system(argv[0], argc, argv, NULL); /* Run init */ debug_print(CRITICAL, "init failed"); switch_task(0); diff --git a/kernel/mem/alloc.c b/kernel/mem/alloc.c index dc5ed4bc..927b5868 100644 --- a/kernel/mem/alloc.c +++ b/kernel/mem/alloc.c @@ -1,6 +1,6 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * - * Kevin Lange's Slab Allocator + * klange's Slab Allocator * * Implemented for CS241, Fall 2010, machine problem 7 * at the University of Illinois, Urbana-Champaign. @@ -8,9 +8,9 @@ * Overall competition winner for speed. * Well ranked in memory usage. * - * Copyright (c) 2010 Kevin Lange. All rights reserved. + * Copyright (c) 2010-2018 K. Lange. All rights reserved. * - * Developed by: Kevin Lange + * Developed by: K. Lange * Dave Majnemer * Assocation for Computing Machinery * University of Illinois, Urbana-Champaign @@ -102,7 +102,7 @@ **/ /* Includes {{{ */ -#include +#include /* }}} */ /* Definitions {{{ */ diff --git a/kernel/mem/mem.c b/kernel/mem/mem.c index 7d344c91..2386c4a4 100644 --- a/kernel/mem/mem.c +++ b/kernel/mem/mem.c @@ -1,19 +1,20 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * Copyright (C) 2012 Markus Schober * * Kernel Memory Manager */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include + +#include #define KERNEL_HEAP_INIT 0x00800000 #define KERNEL_HEAP_END 0x20000000 @@ -203,13 +204,6 @@ uint32_t first_frame(void) { debug_video_crash(msgs); } -#if 0 - signal_t * sig = malloc(sizeof(signal_t)); - sig->handler = current_process->signals.functions[SIGSEGV]; - sig->signum = SIGSEGV; - handle_signal((process_t *)current_process, sig); -#endif - STOP; return -1; @@ -296,6 +290,17 @@ void paging_install(uint32_t memsize) { uintptr_t phys; kernel_directory = (page_directory_t *)kvmalloc_p(sizeof(page_directory_t),&phys); memset(kernel_directory, 0, sizeof(page_directory_t)); + + /* Set PAT 111b to Write-Combining */ + asm volatile ( + "mov $0x277, %%ecx\n" /* IA32_MSR_PAT */ + "rdmsr\n" + "or $0x1000000, %%edx\n" /* set bit 56 */ + "and $0xf9ffffff, %%edx\n" /* unset bits 57, 58 */ + "wrmsr\n" + : : : "ecx", "edx", "eax" + ); + } void paging_mark_system(uint64_t addr) { @@ -485,13 +490,11 @@ page_fault( size_t d; if (a <= r->eip) { d = r->eip - a; - } else { - d = a - r->eip; - } - if (d < distance) { - closest = key; - distance = d; - addr = a; + if (d < distance) { + closest = key; + distance = d; + addr = a; + } } } free(hash_keys); @@ -519,11 +522,7 @@ page_fault( #endif - signal_t * sig = malloc(sizeof(signal_t)); - sig->handler = current_process->signals.functions[SIGSEGV]; - sig->signum = SIGSEGV; - handle_signal((process_t *)current_process, sig); - + send_signal(current_process->id, SIGSEGV, 1); } /* diff --git a/kernel/mem/shm.c b/kernel/mem/shm.c index 89b63274..8468e08b 100644 --- a/kernel/mem/shm.c +++ b/kernel/mem/shm.c @@ -1,18 +1,19 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2014 Kevin Lange + * Copyright (C) 2012-2018 K. Lange * Copyright (C) 2012 Markus Schober * * Shared Memory */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + +#include +#include //static volatile uint8_t bsl; // big shm lock @@ -104,7 +105,7 @@ static shm_chunk_t * create_chunk (shm_node_t * parent, size_t size) { /* Now grab some frames for this guy. */ for (uint32_t i = 0; i < chunk->num_frames; i++) { - page_t tmp = {0,0,0,0,0,0,0}; + page_t tmp = {0}; alloc_frame(&tmp, 0, 0); chunk->frames[i] = tmp.frame; #if 0 diff --git a/kernel/misc/args.c b/kernel/misc/args.c index 93f7567d..25d305c6 100644 --- a/kernel/misc/args.c +++ b/kernel/misc/args.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2013 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * Kernel Argument Manager * @@ -11,11 +11,12 @@ * * This module provides access */ -#include -#include -#include -#include -#include +#include +#include +#include +#include + +#include char * cmdline = NULL; diff --git a/kernel/misc/elf.c b/kernel/misc/elf.c index 771861ae..25c735aa 100644 --- a/kernel/misc/elf.c +++ b/kernel/misc/elf.c @@ -1,17 +1,17 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * ELF Static Executable Loader * */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include int exec_elf(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp) { Elf32_Header header; @@ -40,7 +40,7 @@ int exec_elf(char * path, fs_node_t * file, int argc, char ** argv, char ** env, close_fs(file); /* Find interpreter? */ - debug_print(WARNING, "Dynamic executable"); + debug_print(INFO, "Dynamic executable"); unsigned int nargc = argc + 3; char * args[nargc+1]; @@ -88,6 +88,9 @@ int exec_elf(char * path, fs_node_t * file, int argc, char ** argv, char ** env, Elf32_Phdr phdr; read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr); if (phdr.p_type == PT_LOAD) { + /* TODO: These virtual address bounds should be in a header somewhere */ + if (phdr.p_vaddr < 0x20000000) return -EINVAL; + /* TODO Upper bounds */ for (uintptr_t i = phdr.p_vaddr; i < phdr.p_vaddr + phdr.p_memsz; i += 0x1000) { /* This doesn't care if we already allocated this page */ alloc_frame(get_page(i, 1, current_directory), 0, 1); @@ -190,6 +193,7 @@ int exec_shebang(char * path, fs_node_t * file, int argc, char ** argv, char ** char tmp[100]; read_fs(file, 0, 100, (unsigned char *)tmp); close_fs(file); char * cmd = (char *)&tmp[2]; + if (*cmd == ' ') cmd++; /* Handle a leading space */ char * space_or_linefeed = strpbrk(cmd, " \n"); char * arg = NULL; @@ -274,11 +278,15 @@ int exec( return -ENOENT; } + if (!has_permission(file, 01)) { + return -EACCES; + } + /* Read four bytes of the file */ unsigned char head[4]; read_fs(file, 0, 4, head); - debug_print(WARNING, "First four bytes: %c%c%c%c", head[0], head[1], head[2], head[3]); + debug_print(INFO, "First four bytes: %c%c%c%c", head[0], head[1], head[2], head[3]); current_process->name = strdup(path); gettimeofday((struct timeval *)¤t_process->start, NULL); @@ -299,7 +307,8 @@ int system( char * path, /* Path to the executable to run */ int argc, /* Argument count (ie, /bin/echo hello world = 3) */ - char ** argv /* Argument strings (including executable path) */ + char ** argv, /* Argument strings (including executable path) */ + char ** envin ) { char ** argv_ = malloc(sizeof(char *) * (argc + 1)); for (int j = 0; j < argc; ++j) { @@ -314,7 +323,7 @@ system( current_process->cmdline = argv_; - exec(path,argc,argv_,env); + exec(path,argc,argv_,envin ? envin : env); debug_print(ERROR, "Failed to execute process!"); kexit(-1); return -1; diff --git a/kernel/misc/kprintf.c b/kernel/misc/kprintf.c index 25d5e92b..de31b2a5 100644 --- a/kernel/misc/kprintf.c +++ b/kernel/misc/kprintf.c @@ -1,17 +1,18 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * Kernel printf implementation * * Simple, painfully lacking, implementation of printf(), * for the kernel of all things. */ -#include -#include +#include +#include +#include + #include -#include /* * Integer to string diff --git a/kernel/misc/logging.c b/kernel/misc/logging.c index 7ea24068..e0c8863a 100644 --- a/kernel/misc/logging.c +++ b/kernel/misc/logging.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * Kernel Logging Facility * @@ -9,11 +9,12 @@ * told not to). */ -#include -#include -#include +#include +#include +#include + #include -#include +#include log_type_t debug_level = NOTICE; void * debug_file = NULL; diff --git a/kernel/misc/multiboot.c b/kernel/misc/multiboot.c index 1a3770a5..917cbd5f 100644 --- a/kernel/misc/multiboot.c +++ b/kernel/misc/multiboot.c @@ -1,13 +1,13 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * Multiboot (GRUB) handler */ -#include -#include -#include +#include +#include +#include char * ramdisk = NULL; struct multiboot * mboot_ptr = NULL; diff --git a/kernel/misc/tokenize.c b/kernel/misc/tokenize.c index 1861197a..1dde37f5 100644 --- a/kernel/misc/tokenize.c +++ b/kernel/misc/tokenize.c @@ -1,11 +1,11 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange + * Copyright (C) 2013-2018 K. Lange */ -#include -#include -#include +#include +#include +#include int tokenize(char * str, char * sep, char **buf) { char * pch_i; diff --git a/kernel/misc/ubsan.c b/kernel/misc/ubsan.c index be8c9a08..515ee658 100644 --- a/kernel/misc/ubsan.c +++ b/kernel/misc/ubsan.c @@ -1,9 +1,10 @@ -#include -#include +#include +#include +#include +#include +#include + #include -#include -#include -#include #define EARLY_LOG_DEVICE 0x3F8 static uint32_t _ubsan_log_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { @@ -29,6 +30,7 @@ void __ubsan_handle_sub_overflow(struct OverflowData * data, unsigned long lhs, } void __ubsan_handle_mul_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { + ubsan_debug(&data->location); fprintf(&_ubsan_log, "Overflow in mul: %d %d\n", lhs, rhs); } @@ -60,7 +62,7 @@ void __ubsan_handle_shift_out_of_bounds(struct ShiftOutOfBoundsData * data, unsi #define IS_ALIGNED(a, b) (((a) & ((__typeof__(a))(b)-1)) == 0) void __ubsan_handle_type_mismatch(struct TypeMismatchData * data, unsigned long ptr) { - return; + return; /* Unaligned reads are valid on x86, and we have some very ugly code where this goes poorly. */ ubsan_debug(&data->location); if (data->alignment && !IS_ALIGNED(ptr, data->alignment)) { fprintf(&_ubsan_log, "bad alignment in read at 0x%x (wanted %d)\n", ptr, data->alignment); diff --git a/kernel/spin.c b/kernel/spin.c index 456ac2ad..102a9191 100644 --- a/kernel/spin.c +++ b/kernel/spin.c @@ -6,7 +6,7 @@ * Spin locks with waiters * */ -#include +#include static inline int arch_atomic_swap(volatile int * x, int v) { asm("xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) : "memory"); diff --git a/kernel/sys/module.c b/kernel/sys/module.c index 5bb80165..4e91e94e 100644 --- a/kernel/sys/module.c +++ b/kernel/sys/module.c @@ -1,14 +1,15 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + +#include #define SYMBOLTABLE_HASHMAP_SIZE 10 #define MODULE_HASHMAP_SIZE 10 diff --git a/kernel/sys/panic.c b/kernel/sys/panic.c index c8ca91b8..05cf1f07 100644 --- a/kernel/sys/panic.c +++ b/kernel/sys/panic.c @@ -1,14 +1,14 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * Panic functions */ -#include -#include -#include -#include +#include +#include +#include +#include void halt_and_catch_fire(char * error_message, const char * file, int line, struct regs * regs) { IRQ_OFF; @@ -26,8 +26,7 @@ void halt_and_catch_fire(char * error_message, const char * file, int line, stru debug_print(ERROR, "User ESP: 0x%x", regs->useresp); debug_print(ERROR, "eip=0x%x", regs->eip); } - debug_print(ERROR, "This process has been descheduled."); - kexit(1); + send_signal(current_process->id, SIGILL, 1); } char * probable_function_name(uintptr_t ip, uintptr_t * out_addr) { diff --git a/kernel/sys/process.c b/kernel/sys/process.c index b38ed760..c6ac9f38 100644 --- a/kernel/sys/process.c +++ b/kernel/sys/process.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * Copyright (C) 2012 Markus Schober * Copyright (C) 2015 Dale Weiler * @@ -10,14 +10,15 @@ * Internal format format for a process and functions to spawn * new processes and manage the process tree. */ -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include + +#include +#include tree_t * process_tree; /* Parent->Children tree */ list_t * process_list; /* Flat storage */ @@ -774,10 +775,13 @@ void reap_process(process_t * proc) { } static int wait_candidate(process_t * parent, int pid, int options, process_t * proc) { - (void)options; /* there is only one option that affects candidacy, and we don't support it yet */ - if (!proc) return 0; + if (options & 0x10) { + /* Skip kernel processes */ + if (proc->is_tasklet) return 0; + } + if (pid < -1) { if (proc->group == -pid || proc->id == -pid) return 1; } else if (pid == 0) { diff --git a/kernel/sys/signal.c b/kernel/sys/signal.c index 3c39fe5e..a9bfb80a 100644 --- a/kernel/sys/signal.c +++ b/kernel/sys/signal.c @@ -1,14 +1,14 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2014 Kevin Lange + * Copyright (C) 2012-2018 K. Lange * * Signal Handling */ -#include -#include -#include +#include +#include +#include void enter_signal_handler(uintptr_t location, int signum, uintptr_t stack) { IRQ_OFF; @@ -97,7 +97,7 @@ void handle_signal(process_t * proc, signal_t * sig) { char dowhat = isdeadly[signum]; if (dowhat == 1 || dowhat == 2) { debug_print(WARNING, "Process %d killed by unhandled signal (%d)", proc->id, signum); - kexit(128 + signum); + kexit(((128 + signum) << 8) | signum); __builtin_unreachable(); } else { debug_print(WARNING, "Ignoring signal %d by default in pid %d", signum, proc->id); @@ -111,7 +111,7 @@ void handle_signal(process_t * proc, signal_t * sig) { return; } - debug_print(NOTICE, "handling signal in process %d (%d)", proc->id, signum); + debug_print(NOTICE, "handling signal in process %d (%d) (0x%x)", proc->id, signum, handler); uintptr_t stack = 0xFFFF0000; if (proc->syscall_registers->useresp < 0x10000100) { @@ -129,7 +129,7 @@ list_t * rets_from_sig; void return_from_signal_handler(void) { #if 0 - debug_print(INFO, "Return From Signal for process %d", current_process->id); + debug_print(ERROR, "Return From Signal for process %d", current_process->id); #endif if (__builtin_expect(!rets_from_sig, 0)) { @@ -163,9 +163,14 @@ void fix_signal_stacks(void) { p->thread.esp = p->signal_state.esp; p->thread.eip = p->signal_state.eip; p->thread.ebp = p->signal_state.ebp; - memcpy((void *)(p->image.stack - KERNEL_STACK_SIZE), p->signal_kstack, KERNEL_STACK_SIZE); - free(p->signal_kstack); - p->signal_kstack = NULL; + if (!p->signal_kstack) { + debug_print(ERROR, "Cannot restore signal stack for pid=%d - unset?", p->id); + } else { + debug_print(ERROR, "Restoring signal stack for pid=%d", p->id); + memcpy((void *)(p->image.stack - KERNEL_STACK_SIZE), p->signal_kstack, KERNEL_STACK_SIZE); + free(p->signal_kstack); + p->signal_kstack = NULL; + } make_process_ready(p); } spin_unlock(sig_lock_b); @@ -178,7 +183,7 @@ void fix_signal_stacks(void) { } } -int send_signal(pid_t process, uint32_t signal) { +int send_signal(pid_t process, uint32_t signal, int force_root) { process_t * receiver = process_from_pid(process); if (!receiver) { @@ -186,7 +191,7 @@ int send_signal(pid_t process, uint32_t signal) { return 1; } - if (receiver->user != current_process->user && current_process->user != USER_ROOT_UID) { + if (!force_root && receiver->user != current_process->user && current_process->user != USER_ROOT_UID) { /* No way in hell. */ return 1; } @@ -215,13 +220,21 @@ int send_signal(pid_t process, uint32_t signal) { if (receiver->node_waits) { process_awaken_from_fswait(receiver, -1); } - if (!process_is_ready(receiver)) { make_process_ready(receiver); } list_insert(receiver->signal_queue, sig); + if (receiver == current_process) { + /* Forces us to be rescheduled and enter signal handler */ + if (receiver->signal_kstack) { + switch_next(); + } else { + switch_task(0); + } + } + return 0; } diff --git a/kernel/sys/syscall.c b/kernel/sys/syscall.c index b5e24e8b..84d73586 100644 --- a/kernel/sys/syscall.c +++ b/kernel/sys/syscall.c @@ -1,22 +1,23 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * Copyright (C) 2012 Markus Schober * * Syscall Tables * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include static char hostname[256]; @@ -52,7 +53,7 @@ void validate(void * ptr) { */ static int __attribute__((noreturn)) sys_exit(int retval) { /* Deschedule the current task */ - task_exit(retval); + task_exit((retval & 0xFF) << 8); for (;;) ; } @@ -65,7 +66,7 @@ static int sys_read(int fd, char * ptr, int len) { node->offset += out; return (int)out; } - return -1; + return -EBADF; } static int sys_ioctl(int fd, int request, void * argp) { @@ -73,7 +74,7 @@ static int sys_ioctl(int fd, int request, void * argp) { PTR_VALIDATE(argp); return ioctl_fs(FD_ENTRY(fd), request, argp); } - return -1; + return -EBADF; } static int sys_readdir(int fd, int index, struct dirent * entry) { @@ -83,12 +84,12 @@ static int sys_readdir(int fd, int index, struct dirent * entry) { if (kentry) { memcpy(entry, kentry, sizeof *entry); free(kentry); - return 0; - } else { return 1; + } else { + return 0; } } - return -1; + return -EBADF; } static int sys_write(int fd, char * ptr, int len) { @@ -103,7 +104,7 @@ static int sys_write(int fd, char * ptr, int len) { node->offset += out; return out; } - return -1; + return -EBADF; } static int sys_waitpid(int pid, int * status, int options) { @@ -120,11 +121,13 @@ static int sys_open(const char * file, int flags, int mode) { if (node && !has_permission(node, 04)) { debug_print(WARNING, "access denied (read, sys_open, file=%s)", file); + close_fs(node); return -EACCES; } - if (node && ((flags & O_RDWR) || (flags & O_APPEND) || (flags & O_WRONLY))) { + if (node && ((flags & O_RDWR) || (flags & O_APPEND) || (flags & O_WRONLY) || (flags & O_TRUNC))) { if (!has_permission(node, 02)) { debug_print(WARNING, "access denied (write, sys_open, file=%s)", file); + close_fs(node); return -EACCES; } } @@ -142,9 +145,13 @@ static int sys_open(const char * file, int flags, int mode) { } if (!node) { debug_print(NOTICE, "File does not exist; someone should be setting errno?"); - return -1; + return -ENOENT; + } + if (flags & O_APPEND) { + node->offset = node->length; + } else { + node->offset = 0; } - node->offset = 0; int fd = process_append_fd((process_t *)current_process, node); debug_print(INFO, "[open] pid=%d %s -> %d", getpid(), file, fd); return fd; @@ -154,7 +161,7 @@ static int sys_access(const char * file, int flags) { PTR_VALIDATE(file); debug_print(INFO, "access(%s, 0x%x) from pid=%d", file, flags, getpid()); fs_node_t * node = kopen((char *)file, 0); - if (!node) return -1; + if (!node) return -ENOENT; close_fs(node); return 0; } @@ -165,7 +172,7 @@ static int sys_close(int fd) { FD_ENTRY(fd) = NULL; return 0; } - return -1; + return -EBADF; } static int sys_sbrk(int size) { @@ -250,8 +257,7 @@ static int sys_execve(const char * filename, char *const argv[], char *const env debug_print(INFO,"Executing..."); /* Discard envp */ - exec((char *)filename, argc, (char **)argv_, (char **)envp_); - return -1; + return exec((char *)filename, argc, (char **)argv_, (char **)envp_); } static int sys_seek(int fd, int offset, int whence) { @@ -272,7 +278,7 @@ static int sys_seek(int fd, int offset, int whence) { } return FD_ENTRY(fd)->offset; } - return -1; + return -EBADF; } static int stat_node(fs_node_t * fn, uintptr_t st) { @@ -332,11 +338,16 @@ static int sys_chmod(char * file, int mode) { PTR_VALIDATE(file); fs_node_t * fn = kopen(file, 0); if (fn) { + /* Can group members change bits? I think it's only owners. */ + if (current_process->user != 0 && current_process->user != fn->uid) { + close_fs(fn); + return -EACCES; + } result = chmod_fs(fn, mode); close_fs(fn); return result; } else { - return -1; + return -ENOENT; } } @@ -345,11 +356,16 @@ static int sys_chown(char * file, int uid, int gid) { PTR_VALIDATE(file); fs_node_t * fn = kopen(file, 0); if (fn) { + /* TODO: Owners can change groups... */ + if (current_process->user != 0) { + close_fs(fn); + return -EACCES; + } result = chown_fs(fn, uid, gid); close_fs(fn); return result; } else { - return -1; + return -ENOENT; } } @@ -359,7 +375,7 @@ static int sys_stat(int fd, uintptr_t st) { if (FD_CHECK(fd)) { return stat_node(FD_ENTRY(fd), st); } - return -1; + return -EBADF; } static int sys_mkpipe(void) { @@ -381,7 +397,7 @@ static int sys_setuid(user_t new_uid) { current_process->user = new_uid; return 0; } - return -1; + return -EPERM; } static int sys_uname(struct utsname * name) { @@ -408,7 +424,7 @@ static int sys_uname(struct utsname * name) { static int sys_signal(uint32_t signum, uintptr_t handler) { if (signum > NUMSIGNALS) { - return -1; + return -EINVAL; } uintptr_t old = current_process->signals.functions[signum]; current_process->signals.functions[signum] = handler; @@ -422,14 +438,22 @@ static void inspect_memory (uintptr_t vaddr) { } */ +extern void idt_load(uint32_t *); + static int sys_reboot(void) { debug_print(NOTICE, "[kernel] Reboot requested from process %d by user #%d", current_process->id, current_process->user); if (current_process->user != USER_ROOT_UID) { - return -1; + return -EPERM; } else { - debug_print(NOTICE, "[kernel] Good bye!"); + debug_print(ERROR, "[kernel] Good bye!"); /* Goodbye, cruel world */ IRQ_OFF; + uintptr_t phys; + uint32_t * virt = (void*)kvmalloc_p(0x1000, &phys); + virt[0] = 0; + virt[1] = 0; + virt[2] = 0; + idt_load(virt); uint8_t out = 0x02; while ((out & 0x02) != 0) { out = inportb(0x64); @@ -447,7 +471,7 @@ static int sys_chdir(char * newdir) { if (chd) { if ((chd->flags & FS_DIRECTORY) == 0) { close_fs(chd); - return -1; + return -ENOTDIR; } close_fs(chd); free(current_process->wd_name); @@ -455,7 +479,7 @@ static int sys_chdir(char * newdir) { memcpy(current_process->wd_name, path, strlen(path) + 1); return 0; } else { - return -1; + return -ENOENT; } } @@ -473,13 +497,13 @@ static int sys_sethostname(char * new_hostname) { PTR_VALIDATE(new_hostname); size_t len = strlen(new_hostname) + 1; if (len > 256) { - return 1; + return -ENAMETOOLONG; } hostname_len = len; memcpy(hostname, new_hostname, hostname_len); return 0; } else { - return 1; + return -EPERM; } } @@ -492,7 +516,7 @@ static int sys_gethostname(char * buffer) { extern int mkdir_fs(char *name, uint16_t permission); static int sys_mkdir(char * path, uint32_t mode) { - return mkdir_fs(path, 0777); + return mkdir_fs(path, mode); } /* @@ -519,7 +543,7 @@ static int sys_sysfunc(int fn, char ** args) { /* Request kernel output to file descriptor in arg0*/ debug_print(NOTICE, "Setting output to file object in process %d's fd=%d!", getpid(), (int)args); debug_file = current_process->fds->entries[(int)args]; - break; + return 0; case 5: { char *arg; @@ -535,7 +559,7 @@ static int sys_sysfunc(int fn, char ** args) { FD_ENTRY(1) = repdev; FD_ENTRY(2) = repdev; } - break; + return 0; case 6: debug_print(WARNING, "writing contents of file %s to sdb", args[0]); { @@ -543,7 +567,7 @@ static int sys_sysfunc(int fn, char ** args) { PTR_VALIDATE(args[0]); fs_node_t * file = kopen((char *)args[0], 0); if (!file) { - return -1; + return -EINVAL; } size_t length = file->length; uint8_t * buffer = malloc(length); @@ -567,7 +591,7 @@ static int sys_sysfunc(int fn, char ** args) { fs_node_t * tty = FD_ENTRY(0); return create_kernel_tasklet(debug_hook, "[kttydebug]", tty); } else { - return -1; + return -EINVAL; } case 8: debug_print(NOTICE, "Loading module %s.", args[0]); @@ -614,6 +638,9 @@ static int sys_sysfunc(int fn, char ** args) { { /* Load pages to fit region. */ uintptr_t address = (uintptr_t)args[0]; + /* TODO: These virtual address bounds should be in a header somewhere */ + if (address < 0x20000000) return -EINVAL; + /* TODO: Upper bounds */ size_t size = (size_t)args[1]; /* TODO: Other arguments for read/write? */ @@ -674,7 +701,6 @@ static int sys_sysfunc(int fn, char ** args) { debug_print(WARNING, "0x%x 0x%x 0x%x 0x%x", args[0], args[1], args[2], args[3]); _debug_print(args[0], (uintptr_t)args[1], (uint32_t)args[2], args[3] ? args[3] : "(null)"); return 0; - break; case 13: /* @@ -693,7 +719,7 @@ static int sys_sysfunc(int fn, char ** args) { debug_print(ERROR, "Bad system function %d", fn); break; } - return -1; /* Bad system function or access failure */ + return -EINVAL; /* Bad system function or access failure */ } static int sys_sleepabs(unsigned long seconds, unsigned long subseconds) { @@ -731,8 +757,8 @@ static int sys_fork(void) { } static int sys_clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) { - if (!new_stack || !PTR_INRANGE(new_stack)) return -1; - if (!thread_func || !PTR_INRANGE(thread_func)) return -1; + if (!new_stack || !PTR_INRANGE(new_stack)) return -EINVAL; + if (!thread_func || !PTR_INRANGE(thread_func)) return -EINVAL; return (int)clone(new_stack, thread_func, arg); } @@ -750,7 +776,7 @@ static int sys_shm_release(char * path) { } static int sys_kill(pid_t process, uint32_t signal) { - return send_signal(process, signal); + return send_signal(process, signal, 0); } static int sys_gettimeofday(struct timeval * tv, void * tz) { @@ -762,10 +788,10 @@ static int sys_gettimeofday(struct timeval * tv, void * tz) { static int sys_openpty(int * master, int * slave, char * name, void * _ign0, void * size) { /* We require a place to put these when we are done. */ - if (!master || !slave) return -1; - if (master && !PTR_INRANGE(master)) return -1; - if (slave && !PTR_INRANGE(slave)) return -1; - if (size && !PTR_INRANGE(size)) return -1; + if (!master || !slave) return -EINVAL; + if (master && !PTR_INRANGE(master)) return -EINVAL; + if (slave && !PTR_INRANGE(slave)) return -EINVAL; + if (size && !PTR_INRANGE(size)) return -EINVAL; /* Create a new pseudo terminal */ fs_node_t * fs_master; @@ -849,7 +875,7 @@ static int sys_lstat(char * file, uintptr_t st) { static int sys_fswait(int c, int fds[]) { PTR_VALIDATE(fds); for (int i = 0; i < c; ++i) { - if (!FD_CHECK(fds[i])) return -1; + if (!FD_CHECK(fds[i])) return -EBADF; } fs_node_t ** nodes = malloc(sizeof(fs_node_t *)*(c+1)); for (int i = 0; i < c; ++i) { @@ -865,7 +891,7 @@ static int sys_fswait(int c, int fds[]) { static int sys_fswait_timeout(int c, int fds[], int timeout) { PTR_VALIDATE(fds); for (int i = 0; i < c; ++i) { - if (!FD_CHECK(fds[i])) return -1; + if (!FD_CHECK(fds[i])) return -EBADF; } fs_node_t ** nodes = malloc(sizeof(fs_node_t *)*(c+1)); for (int i = 0; i < c; ++i) { diff --git a/kernel/sys/system.c b/kernel/sys/system.c index 124deeef..1bd2725d 100644 --- a/kernel/sys/system.c +++ b/kernel/sys/system.c @@ -1,12 +1,12 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2013 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * System Functions * */ -#include +#include char * boot_arg = NULL; char * boot_arg_extra = NULL; diff --git a/kernel/sys/task.c b/kernel/sys/task.c index d3599306..c36a22eb 100644 --- a/kernel/sys/task.c +++ b/kernel/sys/task.c @@ -1,17 +1,17 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * Copyright (C) 2012 Markus Schober * * Task Switching and Management Functions * */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #define TASK_MAGIC 0xDEADBEEF diff --git a/kernel/sys/version.c b/kernel/sys/version.c index c13dd5f3..0d4c3329 100644 --- a/kernel/sys/version.c +++ b/kernel/sys/version.c @@ -1,10 +1,10 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2017 Kevin Lange + * Copyright (C) 2011-2018 K. Lange */ -#include +#include /* Kernel name. If you change this, you're not * my friend any more. */ @@ -17,8 +17,8 @@ char * __kernel_version_format = "%d.%d.%d-%s"; /* Version numbers X.Y.Z */ int __kernel_version_major = 1; -int __kernel_version_minor = 2; -int __kernel_version_lower = 2; +int __kernel_version_minor = 5; +int __kernel_version_lower = 3; /* Kernel build suffix, which doesn't necessarily * mean anything, but can be used to distinguish @@ -34,7 +34,7 @@ int __kernel_version_lower = 2; char * __kernel_version_suffix = KERNEL_VERSION_SUFFIX; /* The release codename. */ -char * __kernel_version_codename = "touma"; +char * __kernel_version_codename = "nih"; /* Build architecture (should probably not be * here as a string, but rather some sort of diff --git a/userspace/lib/toaru_auth.c b/lib/auth.c similarity index 83% rename from userspace/lib/toaru_auth.c rename to lib/auth.c index fc36ead5..588fa82f 100644 --- a/userspace/lib/toaru_auth.c +++ b/lib/auth.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2018 K. Lange * * Authentication methods * @@ -12,7 +12,6 @@ #include #include #include -#include "lib/sha2.h" #ifndef fgetpwent extern struct passwd *fgetpwent(FILE *stream); @@ -22,9 +21,7 @@ extern struct passwd *fgetpwent(FILE *stream); int toaru_auth_check_pass(char * user, char * pass) { - /* Generate SHA512 */ - char hash[SHA512_DIGEST_STRING_LENGTH]; - SHA512_Data(pass, strlen(pass), hash); + /* XXX DO something useful */ /* Open up /etc/master.passwd */ @@ -32,7 +29,7 @@ int toaru_auth_check_pass(char * user, char * pass) { struct passwd * p; while ((p = fgetpwent(master))) { - if (!strcmp(p->pw_name, user) && !strcmp(p->pw_passwd, hash)) { + if (!strcmp(p->pw_name, user) && !strcmp(p->pw_passwd, pass)) { fclose(master); return p->pw_uid; } diff --git a/userspace/lib/confreader.c b/lib/confreader.c similarity index 68% rename from userspace/lib/confreader.c rename to lib/confreader.c index 4803e41e..8bb4384e 100644 --- a/userspace/lib/confreader.c +++ b/lib/confreader.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Kevin Lange + * Copyright (C) 2018 K. Lange * * Configuration File Reader * @@ -12,10 +12,12 @@ * - [sections] */ #include +#include +#include -#include "confreader.h" - -#include "lib/hashmap.h" +#define TRACE_APP_NAME "confreader" +#define TRACE(...) +//#include static void free_hashmap(void * h) { hashmap_free(h); @@ -42,37 +44,67 @@ confreader_t * confreader_load(const char * file) { char tmp[1024]; char tmp2[1024]; - char eq[2]; while (!feof(f)) { char c = fgetc(f); tmp[0] = '\0'; - eq[0] = '\0'; tmp2[0] = '\0'; if (c == ';') { - fscanf(f, " %[^\n]", tmp); + TRACE("Comment"); while (!feof(f) && fgetc(f) != '\n'); + TRACE("Done"); } else if (c == '\n' || c == EOF) { + TRACE("blank line or EOF: %d", c); continue; } else if (c == '[') { - fscanf(f, " %[^]] ", tmp); + TRACE("section"); + char * foo = tmp; + int i; + while ((i = fgetc(f)) >= 0) { + if (i == ']') break; + *foo = i; + foo++; + *foo = '\0'; + } while (!feof(f) && fgetc(f) != '\n'); current_section = hashmap_create(10); + TRACE("adding section %s", tmp); hashmap_set(out->sections, tmp, current_section); + TRACE("section is over"); } else { - ungetc(c, f); - fscanf(f, " %[^=]%1[=]%[^=\n]", tmp, eq, tmp2); - while (!feof(f) && fgetc(f) != '\n'); - if (strcmp(eq, "=")) { + TRACE("value"); + char * foo = tmp; + *foo = c; + foo++; + int i; + while ((i = fgetc(f)) >= 0) { + if (i == '=') break; + *foo = i; + foo++; + *foo = '\0'; + } + if (i != '=') { + TRACE("no equals sign"); + while (!feof(f) && fgetc(f) != '\n'); continue; } - + TRACE("="); + foo = tmp2; + while ((i = fgetc(f)) >= 0) { + if (i == '\n') break; + *foo = i; + foo++; + *foo = '\0'; + } + TRACE("setting value %s to %s", tmp, tmp2); hashmap_set(current_section, tmp, strdup(tmp2)); } } fclose(f); + TRACE("done reading"); + return out; } @@ -86,7 +118,10 @@ char * confreader_get(confreader_t * ctx, char * section, char * value) { hashmap_t * s = hashmap_get(ctx->sections, section); - if (!s) return NULL; + if (!s) { + TRACE("section doesn't exist: %s", section); + return NULL; + } return hashmap_get(s, value); } diff --git a/lib/decor-fancy.c b/lib/decor-fancy.c new file mode 100644 index 00000000..706c9135 --- /dev/null +++ b/lib/decor-fancy.c @@ -0,0 +1,217 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016-2018 K. Lange + * + * The default "fancy" decorations theme. + * + * Based on an old gtk-window-decorator theme I used to use many, + * many years ago. + */ +#include +#include + +#include +#include +#include +#include + +#define INACTIVE 10 + +#define TTK_FANCY_PATH "/usr/share/ttk/" + +static int u_height = 33; +static int ul_width = 10; +static int ur_width = 10; +static int mr_width = 6; +static int l_height = 9; +static int ll_width = 9; +static int lr_width = 9; + +static sprite_t * sprites[20]; + +#define TEXT_OFFSET ((window->decorator_flags & DECOR_FLAG_TILED) ? 5 : 10) +#define BUTTON_OFFSET ((window->decorator_flags & DECOR_FLAG_TILED) ? 5 : 0) + +static int _have_freetype = 0; +static void (*freetype_set_font_face)(int face) = NULL; +static void (*freetype_set_font_size)(int size) = NULL; +static int (*freetype_draw_string)(gfx_context_t * ctx, int x, int y, uint32_t fg, const char * s) = NULL; +static int (*freetype_draw_string_width)(char * s) = NULL; + +static void init_sprite(int id, char * path) { + sprites[id] = malloc(sizeof(sprite_t)); + load_sprite(sprites[id], path); + sprites[id]->alpha = ALPHA_EMBEDDED; +} + +static int get_bounds_fancy(yutani_window_t * window, struct decor_bounds * bounds) { + if (window == NULL || !(window->decorator_flags & DECOR_FLAG_TILED)) { + bounds->top_height = 33; + bounds->bottom_height = 6; + bounds->left_width = 6; + bounds->right_width = 6; + } else { + /* TODO: Window type */ + bounds->top_height = 28; + bounds->bottom_height = 1; + bounds->left_width = 1; + bounds->right_width = 1; + } + + bounds->width = bounds->left_width + bounds->right_width; + bounds->height = bounds->top_height + bounds->bottom_height; + return 0; +} + +static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * ctx, char * title, int decors_active) { + int width = window->width; + int height = window->height; + + struct decor_bounds bounds; + get_bounds_fancy(window, &bounds); + + for (int j = 0; j < (int)bounds.top_height; ++j) { + for (int i = 0; i < width; ++i) { + GFX(ctx,i,j) = 0; + } + } + + uint32_t clear_color = ((window->decorator_flags & DECOR_FLAG_TILED) ? rgb(62,62,62) : 0); + + for (int j = (int)bounds.top_height; j < height - (int)bounds.bottom_height; ++j) { + for (int i = 0; i < (int)bounds.left_width; ++i) { + GFX(ctx,i,j) = clear_color; + } + for (int i = width - (int)bounds.right_width; i < width; ++i) { + GFX(ctx,i,j) = clear_color; + } + } + + for (int j = height - (int)bounds.bottom_height; j < height; ++j) { + for (int i = 0; i < width; ++i) { + GFX(ctx,i,j) = clear_color; + } + } + + if (decors_active == DECOR_INACTIVE) decors_active = INACTIVE; + + if ((window->decorator_flags & DECOR_FLAG_TILED)) { + draw_sprite(ctx, sprites[decors_active + 0], -5, -5); + for (int i = 0; i < width - 10; ++i) { + draw_sprite(ctx, sprites[decors_active + 1], i + 5, -5); + } + draw_sprite(ctx, sprites[decors_active + 2], width - 5, -5); + } else { + + draw_sprite(ctx, sprites[decors_active + 0], 0, 0); + for (int i = 0; i < width - (ul_width + ur_width); ++i) { + draw_sprite(ctx, sprites[decors_active + 1], i + ul_width, 0); + } + draw_sprite(ctx, sprites[decors_active + 2], width - ur_width, 0); + for (int i = 0; i < height - (u_height + l_height); ++i) { + draw_sprite(ctx, sprites[decors_active + 3], 0, i + u_height); + draw_sprite(ctx, sprites[decors_active + 4], width - mr_width, i + u_height); + } + draw_sprite(ctx, sprites[decors_active + 5], 0, height - l_height); + for (int i = 0; i < width - (ll_width + lr_width); ++i) { + draw_sprite(ctx, sprites[decors_active + 6], i + ll_width, height - l_height); + } + draw_sprite(ctx, sprites[decors_active + 7], width - lr_width, height - l_height); + } + + char * tmp_title = strdup(title); + int t_l = strlen(tmp_title); + +#define EXTRA_SPACE 120 + + uint32_t title_color = (decors_active == 0) ? rgb(226,226,226) : rgb(147,147,147); + if (_have_freetype) { + freetype_set_font_face(1); /* regular non-monospace */ + freetype_set_font_size(12); + if (freetype_draw_string_width(tmp_title) + EXTRA_SPACE > width) { + while (t_l >= 0 && (freetype_draw_string_width(tmp_title) + EXTRA_SPACE > width)) { + tmp_title[t_l] = '\0'; + t_l--; + } + } + if (*tmp_title) { + int title_offset = (width / 2) - (freetype_draw_string_width(tmp_title) / 2); + freetype_draw_string(ctx, title_offset, TEXT_OFFSET + 14, title_color, tmp_title); + } + } else { + if (draw_sdf_string_width(tmp_title, 18, SDF_FONT_BOLD) + EXTRA_SPACE > width) { + while (t_l >= 0 && (draw_sdf_string_width(tmp_title, 18, SDF_FONT_BOLD) + EXTRA_SPACE > width)) { + tmp_title[t_l] = '\0'; + t_l--; + } + } + + if (*tmp_title) { + int title_offset = (width / 2) - (draw_sdf_string_width(tmp_title, 18, SDF_FONT_BOLD) / 2); + draw_sdf_string(ctx, title_offset, TEXT_OFFSET, tmp_title, 18, title_color, SDF_FONT_BOLD); + } + } + + free(tmp_title); + + /* Buttons */ + draw_sprite(ctx, sprites[decors_active + 8], width - 28 + BUTTON_OFFSET, 16 - BUTTON_OFFSET); + if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) { + draw_sprite(ctx, sprites[decors_active + 9], width - 50 + BUTTON_OFFSET, 16 - BUTTON_OFFSET); + } +} + +static int check_button_press_fancy(yutani_window_t * window, int x, int y) { + if (x >= (int)window->width - 28 + BUTTON_OFFSET && x <= (int)window->width - 18 + BUTTON_OFFSET && + y >= 16 && y <= 26) { + return DECOR_CLOSE; + } + + if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) { + if (x >= (int)window->width - 50 + BUTTON_OFFSET && x <= (int)window->width - 40 + BUTTON_OFFSET && + y >= 16 && y <= 26) { + return DECOR_MAXIMIZE; + } + } + + return 0; +} + +void decor_init() { + init_sprite(0, TTK_FANCY_PATH "active/ul.bmp"); + init_sprite(1, TTK_FANCY_PATH "active/um.bmp"); + init_sprite(2, TTK_FANCY_PATH "active/ur.bmp"); + init_sprite(3, TTK_FANCY_PATH "active/ml.bmp"); + init_sprite(4, TTK_FANCY_PATH "active/mr.bmp"); + init_sprite(5, TTK_FANCY_PATH "active/ll.bmp"); + init_sprite(6, TTK_FANCY_PATH "active/lm.bmp"); + init_sprite(7, TTK_FANCY_PATH "active/lr.bmp"); + init_sprite(8, TTK_FANCY_PATH "active/button-close.bmp"); + init_sprite(9, TTK_FANCY_PATH "active/button-maximize.bmp"); + + init_sprite(INACTIVE + 0, TTK_FANCY_PATH "inactive/ul.bmp"); + init_sprite(INACTIVE + 1, TTK_FANCY_PATH "inactive/um.bmp"); + init_sprite(INACTIVE + 2, TTK_FANCY_PATH "inactive/ur.bmp"); + init_sprite(INACTIVE + 3, TTK_FANCY_PATH "inactive/ml.bmp"); + init_sprite(INACTIVE + 4, TTK_FANCY_PATH "inactive/mr.bmp"); + init_sprite(INACTIVE + 5, TTK_FANCY_PATH "inactive/ll.bmp"); + init_sprite(INACTIVE + 6, TTK_FANCY_PATH "inactive/lm.bmp"); + init_sprite(INACTIVE + 7, TTK_FANCY_PATH "inactive/lr.bmp"); + init_sprite(INACTIVE + 8, TTK_FANCY_PATH "inactive/button-close.bmp"); + init_sprite(INACTIVE + 9, TTK_FANCY_PATH "inactive/button-maximize.bmp"); + + decor_render_decorations = render_decorations_fancy; + decor_check_button_press = check_button_press_fancy; + decor_get_bounds = get_bounds_fancy; + + void * freetype = dlopen("libtoaru_ext_freetype_fonts.so", 0); + if (freetype) { + _have_freetype = 1; + freetype_set_font_face = dlsym(freetype, "freetype_set_font_face"); + freetype_set_font_size = dlsym(freetype, "freetype_set_font_size"); + freetype_draw_string = dlsym(freetype, "freetype_draw_string"); + freetype_draw_string_width = dlsym(freetype, "freetype_draw_string_width"); + } +} + diff --git a/userspace/lib/decorations.c b/lib/decorations.c similarity index 57% rename from userspace/lib/decorations.c rename to lib/decorations.c index 903119a0..cb49c431 100644 --- a/userspace/lib/decorations.c +++ b/lib/decorations.c @@ -1,39 +1,36 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2017 Kevin Lange + * Copyright (C) 2012-2018 K. Lange * * Client-side Window Decoration library */ #include #include -#include "lib/graphics.h" -#include "lib/yutani.h" -#include "lib/shmemfonts.h" -#include "lib/dlfcn.h" +#include -#include "decorations.h" - -uint32_t decor_top_height = 33; -uint32_t decor_bottom_height = 6; -uint32_t decor_left_width = 6; -uint32_t decor_right_width = 6; +#include +#include +#include +#include +#include #define TEXT_OFFSET_X 10 -#define TEXT_OFFSET_Y 16 +#define TEXT_OFFSET_Y 3 -#define BORDERCOLOR rgb(60,60,60) +#define BORDERCOLOR rgb(59,59,59) #define BORDERCOLOR_INACTIVE rgb(30,30,30) -#define BACKCOLOR rgb(20,20,20) #define TEXTCOLOR rgb(230,230,230) #define TEXTCOLOR_INACTIVE rgb(140,140,140) void (*decor_render_decorations)(yutani_window_t *, gfx_context_t *, char *, int) = NULL; int (*decor_check_button_press)(yutani_window_t *, int x, int y) = NULL; +int (*decor_get_bounds)(yutani_window_t *, struct decor_bounds *) = NULL; static void (*callback_close)(yutani_window_t *) = NULL; static void (*callback_resize)(yutani_window_t *) = NULL; +static void (*callback_maximize)(yutani_window_t *) = NULL; static int close_enough(struct yutani_msg_window_mouse_event * me) { return (me->command == YUTANI_MOUSE_EVENT_RAISE && @@ -47,70 +44,130 @@ static void render_decorations_simple(yutani_window_t * window, gfx_context_t * color = BORDERCOLOR_INACTIVE; } - for (uint32_t i = 0; i < window->height; ++i) { + + for (int i = 0; i < (int)window->height; ++i) { GFX(ctx, 0, i) = color; GFX(ctx, window->width - 1, i) = color; } - for (uint32_t i = 1; i < decor_top_height; ++i) { - for (uint32_t j = 1; j < window->width - 1; ++j) { - GFX(ctx, j, i) = BACKCOLOR; + for (int i = 1; i < (int)24; ++i) { + for (int j = 1; j < (int)window->width - 1; ++j) { + GFX(ctx, j, i) = color; } } if (decors_active == DECOR_INACTIVE) { - draw_string(ctx, TEXT_OFFSET_X, TEXT_OFFSET_Y, TEXTCOLOR_INACTIVE, title); - draw_string(ctx, window->width - 20, TEXT_OFFSET_Y, TEXTCOLOR_INACTIVE, "✕"); + draw_sdf_string(ctx, TEXT_OFFSET_X, TEXT_OFFSET_Y, title, 14, TEXTCOLOR_INACTIVE, SDF_FONT_THIN); + draw_sdf_string(ctx, window->width - 20, TEXT_OFFSET_Y, "x", 14, TEXTCOLOR_INACTIVE, SDF_FONT_THIN); } else { - draw_string(ctx, TEXT_OFFSET_X, TEXT_OFFSET_Y, TEXTCOLOR, title); - draw_string(ctx, window->width - 20, TEXT_OFFSET_Y, TEXTCOLOR, "✕"); + draw_sdf_string(ctx, TEXT_OFFSET_X, TEXT_OFFSET_Y, title, 14, TEXTCOLOR, SDF_FONT_THIN); + draw_sdf_string(ctx, window->width - 20, TEXT_OFFSET_Y, "x", 14, TEXTCOLOR, SDF_FONT_THIN); } for (uint32_t i = 0; i < window->width; ++i) { GFX(ctx, i, 0) = color; - GFX(ctx, i, decor_top_height - 1) = color; + GFX(ctx, i, 24 - 1) = color; GFX(ctx, i, window->height - 1) = color; } } static int check_button_press_simple(yutani_window_t * window, int x, int y) { - if (x >= window->width - 20 && x <= window->width - 2 && y >= 2) { + if (x >= (int)window->width - 20 && x <= (int)window->width - 2 && y >= 2) { return DECOR_CLOSE; } return 0; } -static void initialize_simple() { - decor_top_height = 24; - decor_bottom_height = 1; - decor_left_width = 1; - decor_right_width = 1; +static int get_bounds_simple(yutani_window_t * window, struct decor_bounds * bounds) { + /* Does not change with window state */ + bounds->top_height = 24; + bounds->bottom_height = 1; + bounds->left_width = 1; + bounds->right_width = 1; + bounds->width = bounds->left_width + bounds->right_width; + bounds->height = bounds->top_height + bounds->bottom_height; + + return 0; +} + +static void initialize_simple() { decor_render_decorations = render_decorations_simple; decor_check_button_press = check_button_press_simple; + decor_get_bounds = get_bounds_simple; } void render_decorations(yutani_window_t * window, gfx_context_t * ctx, char * title) { if (!window) return; - if (!window->focused) { - decor_render_decorations(window, ctx, title, DECOR_INACTIVE); - } else { + window->decorator_flags |= DECOR_FLAG_DECORATED; + if (window->focused || !hashmap_is_empty(menu_get_windows_hash())) { decor_render_decorations(window, ctx, title, DECOR_ACTIVE); + } else { + decor_render_decorations(window, ctx, title, DECOR_INACTIVE); } } void render_decorations_inactive(yutani_window_t * window, gfx_context_t * ctx, char * title) { if (!window) return; + window->decorator_flags |= DECOR_FLAG_DECORATED; decor_render_decorations(window, ctx, title, DECOR_INACTIVE); } -void init_decorations() { - init_shmemfonts(); +static void _decor_maximize(yutani_t * yctx, yutani_window_t * window) { + if (callback_maximize) { + callback_maximize(window); + } else { + yutani_special_request(yctx, window, YUTANI_SPECIAL_REQUEST_MAXIMIZE); + } +} +static yutani_window_t * _decor_menu_owner_window = NULL; +static struct MenuList * _decor_menu = NULL; + +static void _decor_start_move(struct MenuEntry * self) { + if (!_decor_menu_owner_window) + return; + yutani_focus_window(_decor_menu_owner_window->ctx, _decor_menu_owner_window->wid); + yutani_window_drag_start(_decor_menu_owner_window->ctx, _decor_menu_owner_window); +} + +static void _decor_start_maximize(struct MenuEntry * self) { + if (!_decor_menu_owner_window) + return; + _decor_maximize(_decor_menu_owner_window->ctx, _decor_menu_owner_window); + yutani_focus_window(_decor_menu_owner_window->ctx, _decor_menu_owner_window->wid); +} + +static void _decor_close(struct MenuEntry * self) { + if (!_decor_menu_owner_window) + return; + + yutani_special_request(_decor_menu_owner_window->ctx, _decor_menu_owner_window, YUTANI_SPECIAL_REQUEST_PLEASE_CLOSE); +} + +yutani_window_t * decor_show_default_menu(yutani_window_t * window, int x, int y) { + if (_decor_menu->window) return NULL; + _decor_menu_owner_window = window; + menu_show(_decor_menu, window->ctx); + if (x + _decor_menu->window->width > window->ctx->display_width) { + yutani_window_move(window->ctx, _decor_menu->window, x - _decor_menu->window->width, y); + } else { + yutani_window_move(window->ctx, _decor_menu->window, x, y); + } + return _decor_menu->window; +} + +void init_decorations() { char * tmp = getenv("WM_THEME"); char * theme = tmp ? strdup(tmp) : NULL; + _decor_menu = menu_create(); + menu_insert(_decor_menu, menu_create_normal(NULL, NULL, "Maximize", _decor_start_maximize)); + menu_insert(_decor_menu, menu_create_normal(NULL, NULL, "Move", _decor_start_move)); + menu_insert(_decor_menu, menu_create_separator()); + menu_insert(_decor_menu, menu_create_normal(NULL, NULL, "Close", _decor_close)); + if (!theme || !strcmp(theme, "simple")) { initialize_simple(); } else { @@ -120,7 +177,7 @@ void init_decorations() { options++; } char lib_name[100]; - sprintf(lib_name, "libtoaru-decor-%s.so", theme); + sprintf(lib_name, "libtoaru_decor-%s.so", theme); void * theme_lib = dlopen(lib_name, 0); if (!theme_lib) { goto _theme_error; @@ -138,14 +195,6 @@ _theme_error: } } -uint32_t decor_width() { - return decor_left_width + decor_right_width; -} - -uint32_t decor_height() { - return decor_top_height + decor_bottom_height; -} - void decor_set_close_callback(void (*callback)(yutani_window_t *)) { callback_close = callback; } @@ -154,19 +203,29 @@ void decor_set_resize_callback(void (*callback)(yutani_window_t *)) { callback_resize = callback; } +void decor_set_maximize_callback(void (*callback)(yutani_window_t *)) { + callback_maximize = callback; +} + static int within_decors(yutani_window_t * window, int x, int y) { - if ((x <= decor_left_width || x >= window->width - decor_right_width) && (x > 0 && x < window->width)) return 1; - if ((y <= decor_top_height || y >= window->height - decor_bottom_height) && (y > 0 && y < window->height)) return 1; + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); + + if ((x <= (int)bounds.left_width || x >= (int)window->width - (int)bounds.right_width) && (x > 0 && x < (int)window->width)) return 1; + if ((y <= (int)bounds.top_height || y >= (int)window->height - (int)bounds.bottom_height) && (y > 0 && y < (int)window->height)) return 1; return 0; } -#define LEFT_SIDE (me->new_x <= decor_left_width) -#define RIGHT_SIDE (me->new_x >= window->width - decor_right_width) -#define TOP_SIDE (me->new_y <= decor_top_height) -#define BOTTOM_SIDE (me->new_y >= window->height - decor_bottom_height) +#define LEFT_SIDE (me->new_x <= (int)bounds.left_width) +#define RIGHT_SIDE (me->new_x >= (int)window->width - (int)bounds.right_width) +#define TOP_SIDE (me->new_y <= (int)bounds.top_height) +#define BOTTOM_SIDE (me->new_y >= (int)window->height - (int)bounds.bottom_height) static yutani_scale_direction_t check_resize_direction(struct yutani_msg_window_mouse_event * me, yutani_window_t * window) { + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); yutani_scale_direction_t resize_direction = SCALE_NONE; + if (LEFT_SIDE && !TOP_SIDE && !BOTTOM_SIDE) { resize_direction = SCALE_LEFT; } else if (RIGHT_SIDE && !TOP_SIDE && !BOTTOM_SIDE) { @@ -187,7 +246,7 @@ static yutani_scale_direction_t check_resize_direction(struct yutani_msg_window_ return resize_direction; } -static int old_resize_direction = SCALE_NONE; +static yutani_scale_direction_t old_resize_direction = SCALE_NONE; int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { if (m) { @@ -196,7 +255,10 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { { struct yutani_msg_window_mouse_event * me = (void*)m->data; yutani_window_t * window = hashmap_get(yctx->windows, (void*)me->wid); + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); if (!window) return 0; + if (!(window->decorator_flags & DECOR_FLAG_DECORATED)) return 0; if (within_decors(window, me->new_x, me->new_y)) { int button = decor_check_button_press(window, me->new_x, me->new_y); if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { @@ -208,12 +270,15 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { yutani_window_resize_start(yctx, window, resize_direction); } - if (me->new_y < decor_top_height && resize_direction == SCALE_NONE) { + if (me->new_y < (int)bounds.top_height && resize_direction == SCALE_NONE) { yutani_window_drag_start(yctx, window); } return DECOR_OTHER; } } + if (!button && (me->buttons & YUTANI_MOUSE_BUTTON_RIGHT)) { + return DECOR_RIGHT; + } if (me->command == YUTANI_MOUSE_EVENT_MOVE) { if (!button) { /* Resize edges */ @@ -239,6 +304,9 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { case SCALE_UP_RIGHT: yutani_window_show_mouse(yctx, window, YUTANI_CURSOR_TYPE_RESIZE_DOWN_UP); break; + case SCALE_AUTO: + case SCALE_NONE: + break; } } old_resize_direction = resize_direction; @@ -254,6 +322,9 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { case DECOR_RESIZE: if (callback_resize) callback_resize(window); break; + case DECOR_MAXIMIZE: + _decor_maximize(yctx, window); + break; default: break; } diff --git a/userspace/lib/graphics.c b/lib/graphics.c similarity index 53% rename from userspace/lib/graphics.c rename to lib/graphics.c index 499e12c1..8e21beb4 100644 --- a/userspace/lib/graphics.c +++ b/lib/graphics.c @@ -1,24 +1,25 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2014 Kevin Lange - * - * Guassian context blurring: - * Copyright (C) 2008 Kristian Høgsberg - * Copyright (C) 2009 Chris Wilson + * Copyright (C) 2012-2018 K. Lange * * Generic Graphics library for ToaruOS */ -#include #include +#include +#include #include #include -#include -#include "graphics.h" -#include "../../kernel/include/video.h" -#define PNG_DEBUG 3 -#include +#include + +#include +#include + +#include + +#include static inline int32_t min(int32_t a, int32_t b) { return (a < b) ? a : b; @@ -37,10 +38,50 @@ static inline uint16_t max16(uint16_t a, uint16_t b) { } +static int _is_in_clip(gfx_context_t * ctx, int32_t y) { + if (!ctx->clips) return 1; + if (y < 0 || y >= ctx->clips_size) return 1; + return ctx->clips[y]; +} + + +void gfx_add_clip(gfx_context_t * ctx, int32_t x, int32_t y, int32_t w, int32_t h) { + (void)x; + (void)w; // TODO Horizontal clipping + if (!ctx->clips) { + ctx->clips = malloc(ctx->height); + memset(ctx->clips, 0, ctx->height); + ctx->clips_size = ctx->height; + } + for (int i = max(y,0); i < min(y+h,ctx->clips_size); ++i) { + ctx->clips[i] = 1; + } +} + +void gfx_clear_clip(gfx_context_t * ctx) { + if (ctx->clips) { + memset(ctx->clips, 0, ctx->clips_size); + } +} + +void gfx_no_clip(gfx_context_t * ctx) { + void * tmp = ctx->clips; + if (!tmp) return; + ctx->clips = NULL; + free(tmp); +} /* Pointer to graphics memory */ void flip(gfx_context_t * ctx) { - memcpy(ctx->buffer, ctx->backbuffer, ctx->size); + if (ctx->clips) { + for (size_t i = 0; i < ctx->height; ++i) { + if (_is_in_clip(ctx,i)) { + memcpy(&ctx->buffer[i*GFX_S(ctx)], &ctx->backbuffer[i*GFX_S(ctx)], 4 * ctx->width); + } + } + } else { + memcpy(ctx->buffer, ctx->backbuffer, ctx->size); + } } void clearbuffer(gfx_context_t * ctx) { @@ -51,9 +92,10 @@ void clearbuffer(gfx_context_t * ctx) { static int framebuffer_fd = 0; gfx_context_t * init_graphics_fullscreen() { gfx_context_t * out = malloc(sizeof(gfx_context_t)); + out->clips = NULL; if (!framebuffer_fd) { - framebuffer_fd = open("/dev/fb0", O_RDONLY); + framebuffer_fd = open("/dev/fb0", 0, 0); } if (framebuffer_fd < 0) { /* oh shit */ @@ -64,10 +106,11 @@ gfx_context_t * init_graphics_fullscreen() { ioctl(framebuffer_fd, IO_VID_WIDTH, &out->width); ioctl(framebuffer_fd, IO_VID_HEIGHT, &out->height); ioctl(framebuffer_fd, IO_VID_DEPTH, &out->depth); + ioctl(framebuffer_fd, IO_VID_STRIDE, &out->stride); ioctl(framebuffer_fd, IO_VID_ADDR, &out->buffer); ioctl(framebuffer_fd, IO_VID_SIGNAL, NULL); - out->size = GFX_H(out) * GFX_W(out) * GFX_B(out); + out->size = GFX_H(out) * GFX_S(out); out->backbuffer = out->buffer; return out; } @@ -81,7 +124,7 @@ uint32_t framebuffer_stride(void) { gfx_context_t * init_graphics_fullscreen_double_buffer() { gfx_context_t * out = init_graphics_fullscreen(); if (!out) return NULL; - out->backbuffer = malloc(sizeof(uint32_t) * GFX_W(out) * GFX_H(out)); + out->backbuffer = malloc(GFX_S(out) * GFX_H(out)); return out; } @@ -90,12 +133,19 @@ void reinit_graphics_fullscreen(gfx_context_t * out) { ioctl(framebuffer_fd, IO_VID_WIDTH, &out->width); ioctl(framebuffer_fd, IO_VID_HEIGHT, &out->height); ioctl(framebuffer_fd, IO_VID_DEPTH, &out->depth); + ioctl(framebuffer_fd, IO_VID_STRIDE, &out->stride); - out->size = GFX_H(out) * GFX_W(out) * GFX_B(out); + out->size = GFX_H(out) * GFX_S(out); + + if (out->clips && out->clips_size != out->height) { + free(out->clips); + out->clips = NULL; + out->clips_size = 0; + } if (out->buffer != out->backbuffer) { ioctl(framebuffer_fd, IO_VID_ADDR, &out->buffer); - out->backbuffer = realloc(out->backbuffer, sizeof(uint32_t) * GFX_W(out) * GFX_H(out)); + out->backbuffer = realloc(out->backbuffer, GFX_S(out) * GFX_H(out)); } else { ioctl(framebuffer_fd, IO_VID_ADDR, &out->buffer); out->backbuffer = out->buffer; @@ -105,8 +155,10 @@ void reinit_graphics_fullscreen(gfx_context_t * out) { gfx_context_t * init_graphics_sprite(sprite_t * sprite) { gfx_context_t * out = malloc(sizeof(gfx_context_t)); + out->clips = NULL; out->width = sprite->width; + out->stride = sprite->width * sizeof(uint32_t); out->height = sprite->height; out->depth = 32; out->size = GFX_H(out) * GFX_W(out) * GFX_B(out); @@ -203,144 +255,6 @@ uint32_t premultiply(uint32_t color) { return rgba(r,g,b,a); } -#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) - -void blur_context(gfx_context_t * _dst, gfx_context_t * _src, double amount) { - int width, height; - int x, y, z, w, i, j, k; - uint32_t *s, *d, a, p; - uint8_t * src, * dst; - uint8_t kernel[17]; - const int size = ARRAY_LENGTH(kernel); - const int half = size / 2; - - width = _src->width; - height = _src->height; - - src = _src->backbuffer; - dst = _dst->backbuffer; - - a = 0; - for (i = 0; i < size; ++i) { - double f = i - half; - a += kernel[i] = exp (- f * f / amount) * 80; - } - - for (i = 0; i < height; ++i) { - s = (uint32_t *) (src + i * (_src->width * 4)); - d = (uint32_t *) (dst + i * (_dst->width * 4)); - for (j = 0; j < width; ++j) { - x = y = z = w = 0; - for (k = 0; k < size; ++k) { - if (j - half + k < 0 || j - half + k >= width) - continue; - p = s[j - half + k]; - - x += ((p >> 24) & 0xFF) * kernel[k]; - y += ((p >> 16) & 0xFF) * kernel[k]; - z += ((p >> 8) & 0xFF) * kernel[k]; - w += ((p >> 0) & 0xFF) * kernel[k]; - } - - d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; - } - } - - for (i = 0; i < height; ++i) { - s = (uint32_t *) (src + i * (_src->width * 4)); - d = (uint32_t *) (dst + i * (_dst->width * 4)); - for (j = 0; j < width; ++j) { - x = y = z = w = 0; - for (k = 0; k < size; ++k) { - if (i - half + k < 0 || i - half + k >= height) - continue; - - s = (uint32_t *) (dst + (i - half + k) * (_dst->width * 4)); - p = s[j]; - - x += ((p >> 24) & 0xFF) * kernel[k]; - y += ((p >> 16) & 0xFF) * kernel[k]; - z += ((p >> 8) & 0xFF) * kernel[k]; - w += ((p >> 0) & 0xFF) * kernel[k]; - } - - d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; - } - } -} - -void blur_context_no_vignette(gfx_context_t * _dst, gfx_context_t * _src, double amount) { - int width, height; - int x, y, z, w, i, j, k; - uint32_t *s, *d, a, p; - uint8_t * src, * dst; - uint8_t kernel[17]; - const int size = ARRAY_LENGTH(kernel); - const int half = size / 2; - - width = _src->width; - height = _src->height; - - src = _src->backbuffer; - dst = _dst->backbuffer; - - a = 0; - for (i = 0; i < size; ++i) { - double f = i - half; - a += kernel[i] = exp (- f * f / amount) * 80; - } - - for (i = 0; i < height; ++i) { - s = (uint32_t *) (src + i * (_src->width * 4)); - d = (uint32_t *) (dst + i * (_dst->width * 4)); - for (j = 0; j < width; ++j) { - x = y = z = w = 0; - for (k = 0; k < size; ++k) { - int j_ = j; - if (j_ - half + k < 0) { - j_ = half - k; - } else if (j_ - half + k >= width) { - j_ = width - k + half - 1; - } - p = s[j_ - half + k]; - - x += ((p >> 24) & 0xFF) * kernel[k]; - y += ((p >> 16) & 0xFF) * kernel[k]; - z += ((p >> 8) & 0xFF) * kernel[k]; - w += ((p >> 0) & 0xFF) * kernel[k]; - } - - d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; - } - } - - for (i = 0; i < height; ++i) { - s = (uint32_t *) (src + i * (_src->width * 4)); - d = (uint32_t *) (dst + i * (_dst->width * 4)); - for (j = 0; j < width; ++j) { - x = y = z = w = 0; - for (k = 0; k < size; ++k) { - int i_ = i; - if (i_ - half + k < 0) { - i_ = half - k; - } else if (i_ - half + k >= height) { - i_ = height - k + half - 1; - } - - s = (uint32_t *) (dst + (i_ - half + k) * (_dst->width * 4)); - p = s[j]; - - x += ((p >> 24) & 0xFF) * kernel[k]; - y += ((p >> 16) & 0xFF) * kernel[k]; - z += ((p >> 8) & 0xFF) * kernel[k]; - w += ((p >> 0) & 0xFF) * kernel[k]; - } - - d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a; - } - } -} - static int clamp(int a, int l, int h) { return a < l ? l : (a > h ? h : a); } @@ -498,12 +412,19 @@ void load_sprite(sprite_t * sprite, char * filename) { if (bpp == 24) { color = (bufferb[i + 3 * x] & 0xFF) + (bufferb[i+1 + 3 * x] & 0xFF) * 0x100 + - (bufferb[i+2 + 3 * x] & 0xFF) * 0x10000; + (bufferb[i+2 + 3 * x] & 0xFF) * 0x10000 + 0xFF000000; } else if (bpp == 32) { - color = (bufferb[i + 4 * x] & 0xFF) * 0x1000000 + - (bufferb[i+1 + 4 * x] & 0xFF) * 0x100 + - (bufferb[i+2 + 4 * x] & 0xFF) * 0x10000 + - (bufferb[i+3 + 4 * x] & 0xFF) * 0x1; + if (bufferb[i + 4 * x] == 0) { + color = 0x000000; + } else { + color = (bufferb[i + 4 * x] & 0xFF) * 0x1000000 + + (bufferb[i+1 + 4 * x] & 0xFF) * 0x1 + + (bufferb[i+2 + 4 * x] & 0xFF) * 0x100 + + (bufferb[i+3 + 4 * x] & 0xFF) * 0x10000; + color = premultiply(color); + } + } else { + color = rgb(bufferb[i + x],bufferb[i + x],bufferb[i + x]); /* Unsupported */ } /* Set our point */ sprite->bitmap[(height - y - 1) * width + x] = color; @@ -516,159 +437,141 @@ _cleanup_sprite: free(bufferb); } -int load_sprite_png(sprite_t * sprite, char * file) { - png_structp png_ptr; - png_infop info_ptr; - int number_of_passes; - png_bytep * row_pointers; - int x, y; - png_uint_32 width, height; - int color_type; - int bit_depth; +static __m128i mask00ff; +static __m128i mask0080; +static __m128i mask0101; - char header[8]; - - FILE *fp = fopen(file, "rb"); - if (!fp) { - return 1; - } - fread(header, 1, 8, fp); - if (png_sig_cmp(header, 0, 8)) { - fclose(fp); - return 1; - } - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { - fclose(fp); - return 1; - } - info_ptr = png_create_info_struct(png_ptr); - - png_init_io(png_ptr, fp); - png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); - - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - - row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); - for (y = 0; y < height; ++y) { - row_pointers[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); - } - png_read_image(png_ptr, row_pointers); - fclose(fp); - - sprite->width = width; - sprite->height = height; - sprite->bitmap = malloc(sizeof(uint32_t) * width * height); - sprite->alpha = 0; - sprite->blank = 0; - - if (color_type == 2) { - sprite->alpha = ALPHA_OPAQUE; - for (y = 0; y < height; ++y) { - png_byte* row = row_pointers[y]; - for (x = 0; x < width; ++x) { - png_byte * ptr = &(row[x*3]); - sprite->bitmap[(y) * width + x] = rgb(ptr[0], ptr[1], ptr[2]); - } - } - } else if (color_type == 6) { - sprite->alpha = ALPHA_EMBEDDED; - for (y = 0; y < height; ++y) { - png_byte* row = row_pointers[y]; - for (x = 0; x < width; ++x) { - png_byte * ptr = &(row[x*4]); - sprite->bitmap[(y) * width + x] = premultiply(rgba(ptr[0], ptr[1], ptr[2], ptr[3])); - } - } - - } else { - printf("XXX: UNKNOWN COLOR TYPE: %d!\n", color_type); - } - - for (y = 0; y < height; ++y) { - free(row_pointers[y]); - } - free(row_pointers); - - png_destroy_read_struct(&png_ptr,&info_ptr,NULL); - - return 0; +__attribute__((constructor)) static void _masks(void) { + mask00ff = _mm_set1_epi16(0x00FF); + mask0080 = _mm_set1_epi16(0x0080); + mask0101 = _mm_set1_epi16(0x0101); } - -void context_to_png(FILE * file, gfx_context_t * ctx) { - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - int32_t x, y; - - png_byte ** row_pointers = NULL; - - int status = -1; - int depth = 8; - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - info_ptr = png_create_info_struct(png_ptr); - - if (setjmp(png_jmpbuf(png_ptr))) { - goto png_write_failure; - } - - png_set_IHDR(png_ptr, info_ptr, - ctx->width, ctx->height, depth, - PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - row_pointers = png_malloc(png_ptr, ctx->height * sizeof(png_byte *)); - for (y = 0; y < ctx->height; ++y) { - png_byte * row = png_malloc(png_ptr, sizeof(uint8_t) * ctx->width * sizeof(uint32_t)); - row_pointers[y] = row; - for (x = 0; x < ctx->width; ++x) { - uint32_t pixel = GFX(ctx, x, y); - *row++ = _RED(pixel); - *row++ = _GRE(pixel); - *row++ = _BLU(pixel); - *row++ = _ALP(pixel); - } - } - - png_init_io(png_ptr, file); - png_set_rows(png_ptr, info_ptr, row_pointers); - png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); - - for (y = 0; y < ctx->height; y++) { - png_free(png_ptr, row_pointers[y]); - } - png_free(png_ptr, row_pointers); - - fprintf(stderr, "Done writing PNG.\n"); - return; - - png_write_failure: - fprintf(stderr, "There was an exception while trying to write out a PNG file :(\n"); - return; -} - - +__attribute__((__force_align_arg_pointer__)) void draw_sprite(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y) { + int32_t _left = max(x, 0); int32_t _top = max(y, 0); int32_t _right = min(x + sprite->width, ctx->width - 1); int32_t _bottom = min(y + sprite->height, ctx->height - 1); - for (uint16_t _y = 0; _y < sprite->height; ++_y) { - for (uint16_t _x = 0; _x < sprite->width; ++_x) { - if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) - continue; - if (sprite->alpha == ALPHA_MASK) { + if (sprite->alpha == ALPHA_MASK) { + for (uint16_t _y = 0; _y < sprite->height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; + for (uint16_t _x = 0; _x < sprite->width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; GFX(ctx, x + _x, y + _y) = alpha_blend(GFX(ctx, x + _x, y + _y), SPRITE(sprite, _x, _y), SMASKS(sprite, _x, _y)); - } else if (sprite->alpha == ALPHA_EMBEDDED) { + } + } + } else if (sprite->alpha == ALPHA_EMBEDDED) { + /* Alpha embedded is the most important step. */ + for (uint16_t _y = 0; _y < sprite->height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; +#if 0 + for (uint16_t _x = 0; _x < sprite->width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; GFX(ctx, x + _x, y + _y) = alpha_blend_rgba(GFX(ctx, x + _x, y + _y), SPRITE(sprite, _x, _y)); - } else if (sprite->alpha == ALPHA_INDEXED) { + } +#else + uint16_t _x = 0; + + /* Ensure alignment */ + for (; _x < sprite->width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; + if (!((uintptr_t)&GFX(ctx, x + _x, y + _y) & 15)) + break; + GFX(ctx, x + _x, y + _y) = alpha_blend_rgba(GFX(ctx, x + _x, y + _y), SPRITE(sprite, _x, _y)); + } + for (; _x < sprite->width - 3; _x += 4) { + if (x + _x < _left || y + _y < _top || y + _y > _bottom) { + continue; + } + if (x + _x + 3 > _right) + break; + + __m128i d = _mm_load_si128((void *)&GFX(ctx, x + _x, y + _y)); + __m128i s = _mm_loadu_si128((void *)&SPRITE(sprite, _x, _y)); + + // clear + if (_mm_movemask_epi8(_mm_cmpeq_epi8(s, _mm_setzero_si128())) == 0xFFFF) + continue; + + // opaque + if ((_mm_movemask_epi8(_mm_cmpeq_epi8(s, _mm_cmpeq_epi8(s,s))) & 0x8888) == 0x8888) + _mm_storeu_si128((void*)&GFX(ctx, x + _x, y + _y), s); + + __m128i d_l, d_h; + __m128i s_l, s_h; + + // unpack destination + d_l = _mm_unpacklo_epi8(d, _mm_setzero_si128()); + d_h = _mm_unpackhi_epi8(d, _mm_setzero_si128()); + + // unpack source + s_l = _mm_unpacklo_epi8(s, _mm_setzero_si128()); + s_h = _mm_unpackhi_epi8(s, _mm_setzero_si128()); + + __m128i a_l, a_h; + __m128i t_l, t_h; + + // extract source alpha RGBA → AAAA + a_l = _mm_shufflehi_epi16(_mm_shufflelo_epi16(s_l, _MM_SHUFFLE(3,3,3,3)), _MM_SHUFFLE(3,3,3,3)); + a_h = _mm_shufflehi_epi16(_mm_shufflelo_epi16(s_h, _MM_SHUFFLE(3,3,3,3)), _MM_SHUFFLE(3,3,3,3)); + + // negate source alpha + t_l = _mm_xor_si128(a_l, mask00ff); + t_h = _mm_xor_si128(a_h, mask00ff); + + // apply source alpha to destination + d_l = _mm_mulhi_epu16(_mm_adds_epu16(_mm_mullo_epi16(d_l,t_l),mask0080),mask0101); + d_h = _mm_mulhi_epu16(_mm_adds_epu16(_mm_mullo_epi16(d_h,t_h),mask0080),mask0101); + + // combine source and destination + d_l = _mm_adds_epu8(s_l,d_l); + d_h = _mm_adds_epu8(s_h,d_h); + + // pack low + high and write back to memory + _mm_storeu_si128((void*)&GFX(ctx, x + _x, y + _y), _mm_packus_epi16(d_l,d_h)); + } + for (; _x < sprite->width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; + GFX(ctx, x + _x, y + _y) = alpha_blend_rgba(GFX(ctx, x + _x, y + _y), SPRITE(sprite, _x, _y)); + } +#endif + } + } else if (sprite->alpha == ALPHA_INDEXED) { + for (uint16_t _y = 0; _y < sprite->height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; + for (uint16_t _x = 0; _x < sprite->width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; if (SPRITE(sprite, _x, _y) != sprite->blank) { GFX(ctx, x + _x, y + _y) = SPRITE(sprite, _x, _y) | 0xFF000000; } - } else { + } + } + } else if (sprite->alpha == ALPHA_FORCE_SLOW_EMBEDDED) { + for (uint16_t _y = 0; _y < sprite->height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; + for (uint16_t _x = 0; _x < sprite->width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; +#if 1 + GFX(ctx, x + _x, y + _y) = alpha_blend_rgba(GFX(ctx, x + _x, y + _y), SPRITE(sprite, _x, _y)); +#else + GFX(ctx, x + _x, y + _y) = alpha_blend_rgba(rgba(255,255,0,255), SPRITE(sprite, _x, _y)); +#endif + } + } + } else { + for (uint16_t _y = 0; _y < sprite->height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; + for (uint16_t _x = 0; _x < sprite->width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; GFX(ctx, x + _x, y + _y) = SPRITE(sprite, _x, _y) | 0xFF000000; } } @@ -742,6 +645,8 @@ uint32_t getBilinearFilteredPixelColor(sprite_t * tex, double u, double v) { int y = floor(v); if (x >= tex->width) return 0; if (y >= tex->height) return 0; + if (x <= 0) return 0; + if (y <= 0) return 0; double u_ratio = u - x; double v_ratio = v - y; double u_o = 1 - u_ratio; @@ -768,6 +673,7 @@ void draw_sprite_scaled(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32 int32_t _right = min(x + width, ctx->width - 1); int32_t _bottom = min(y + height, ctx->height - 1); for (uint16_t _y = 0; _y < height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; for (uint16_t _x = 0; _x < width; ++_x) { if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) continue; @@ -788,6 +694,7 @@ void draw_sprite_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_ int32_t _right = min(x + sprite->width, ctx->width - 1); int32_t _bottom = min(y + sprite->height, ctx->height - 1); for (uint16_t _y = 0; _y < sprite->height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; for (uint16_t _x = 0; _x < sprite->width; ++_x) { if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) continue; @@ -798,6 +705,22 @@ void draw_sprite_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_ } } +void draw_sprite_alpha_paint(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, float alpha, uint32_t c) { + int32_t _left = max(x, 0); + int32_t _top = max(y, 0); + int32_t _right = min(x + sprite->width, ctx->width - 1); + int32_t _bottom = min(y + sprite->height, ctx->height - 1); + for (uint16_t _y = 0; _y < sprite->height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; + for (uint16_t _x = 0; _x < sprite->width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; + uint32_t n_color = SPRITE(sprite, _x, _y); + uint32_t f_color = rgb(_ALP(n_color) * alpha, 0, 0); + GFX(ctx, x + _x, y + _y) = alpha_blend(GFX(ctx, x + _x, y + _y), c, f_color); + } + } +} void draw_sprite_scaled_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, uint16_t width, uint16_t height, float alpha) { int32_t _left = max(x, 0); @@ -805,6 +728,7 @@ void draw_sprite_scaled_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t _right = min(x + width, ctx->width - 1); int32_t _bottom = min(y + height, ctx->height - 1); for (uint16_t _y = 0; _y < height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; for (uint16_t _x = 0; _x < width; ++_x) { if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) continue; @@ -815,3 +739,194 @@ void draw_sprite_scaled_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, } } + +uint32_t interp_colors(uint32_t bottom, uint32_t top, uint8_t interp) { + uint8_t red = (_RED(bottom) * (255 - interp) + _RED(top) * interp) / 255; + uint8_t gre = (_GRE(bottom) * (255 - interp) + _GRE(top) * interp) / 255; + uint8_t blu = (_BLU(bottom) * (255 - interp) + _BLU(top) * interp) / 255; + uint8_t alp = (_ALP(bottom) * (255 - interp) + _ALP(top) * interp) / 255; + return rgba(red,gre,blu, alp); +} + +void draw_rectangle(gfx_context_t * ctx, int32_t x, int32_t y, uint16_t width, uint16_t height, uint32_t color) { + int32_t _left = max(x, 0); + int32_t _top = max(y, 0); + int32_t _right = min(x + width, ctx->width - 1); + int32_t _bottom = min(y + height, ctx->height - 1); + for (uint16_t _y = 0; _y < height; ++_y) { + if (!_is_in_clip(ctx, y + _y)) continue; + for (uint16_t _x = 0; _x < width; ++_x) { + if (x + _x < _left || x + _x > _right || y + _y < _top || y + _y > _bottom) + continue; + GFX(ctx, x + _x, y + _y) = alpha_blend_rgba(GFX(ctx, x + _x, y + _y), color); + } + } + +} + +void draw_rounded_rectangle(gfx_context_t * ctx, int32_t x, int32_t y, uint16_t width, uint16_t height, int radius, uint32_t color) { + /* Draw a rounded rectangle */ + + if (radius > width / 2) { + radius = width / 2; + } + + if (radius > height / 2) { + radius = height / 2; + } + + uint32_t c = premultiply(color); + for (int row = y; row < y + height; row++){ + for (int col = x; col < x + width; col++) { + if ((col < x + radius || col > x + width - radius - 1) && + (row < y + radius || row > y + height - radius - 1)) { + continue; + } + GFX(ctx, col, row) = alpha_blend_rgba(GFX(ctx, col, row), c); + } + } + + /* draw the actual rounding */ + for (int i = 0; i < radius; ++i) { + long r2 = radius * radius; + long i2 = i * i; + long j2 = r2 - i2; + double j_max = sqrt((double)j2); + + for (int j = 0; j <= (int)j_max; ++j) { + int _x = x + width - radius + i; + int _y = y + height - radius + j; + int _z = y + radius - j - 1; + + uint32_t c = color; + if (j == (int)j_max) { + c = premultiply(rgba(_RED(c),_GRE(c),_BLU(c),(int)((double)_ALP(c) * (j_max - (double)j)))); + } + + GFX(ctx, _x, _y) = alpha_blend_rgba(GFX(ctx, _x, _y), c); + GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), c); + _x = x + radius - i - 1; + GFX(ctx, _x, _y) = alpha_blend_rgba(GFX(ctx, _x, _y), c); + GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), c); + } + } +} + +float gfx_point_distance(struct gfx_point * a, struct gfx_point * b) { + return sqrt((a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y)); +} + +float gfx_point_distance_squared(struct gfx_point * a, struct gfx_point * b) { + return (a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y); +} + +float gfx_point_dot(struct gfx_point * a, struct gfx_point * b) { + return (a->x * b->x) + (a->y * b->y); +} + +struct gfx_point gfx_point_sub(struct gfx_point * a, struct gfx_point * b) { + struct gfx_point p = {a->x - b->x, a->y - b->y}; + return p; +} + +struct gfx_point gfx_point_add(struct gfx_point * a, struct gfx_point * b) { + struct gfx_point p = {a->x + b->x, a->y + b->y}; + return p; +} + +#define fmax(a,b) ((a) > (b) ? (a) : (b)) +#define fmin(a,b) ((a) < (b) ? (a) : (b)) + +float gfx_line_distance(struct gfx_point * p, struct gfx_point * v, struct gfx_point * w) { + float lengthlength = gfx_point_distance_squared(v,w); + + if (lengthlength == 0.0) return gfx_point_distance(p, v); /* point */ + + struct gfx_point p_v = gfx_point_sub(p,v); + struct gfx_point w_v = gfx_point_sub(w,v); + float tmp = gfx_point_dot(&p_v,&w_v) / lengthlength; + tmp = fmin(1.0,tmp); + float t = fmax(0.0, tmp); + + w_v.x *= t; + w_v.y *= t; + + struct gfx_point v_t = gfx_point_add(v, &w_v); + return gfx_point_distance(p, &v_t); +} + +/** + * This is slow, but it works... + * + * Maybe acceptable for baked UI elements? + */ +void draw_line_aa(gfx_context_t * ctx, int x_1, int x_2, int y_1, int y_2, uint32_t color, float thickness) { + struct gfx_point v = {(float)x_1, (float)y_1}; + struct gfx_point w = {(float)x_2, (float)y_2}; + + for (int y = 0; y < ctx->height; ++y) { + for (int x = 0; x < ctx->width; ++x) { + struct gfx_point p = {x,y}; + float d = gfx_line_distance(&p,&v,&w); + if (d < thickness + 0.5) { + if (d < thickness - 0.5) { + GFX(ctx,x,y) = color; + } else { + uint32_t f_color = rgb(255 * (1.0 - (d - thickness + 0.5)), 0, 0); + GFX(ctx,x,y) = alpha_blend(GFX(ctx,x,y), color, f_color); + } + } + } + } +} + +static void calc_rotation(double x, double y, double px, double py, double rotation, double * u, double * v) { + double s = sin(rotation); + double c = cos(rotation); + + /* Translate to pivot */ + x -= px; + y -= py; + + *u = (x * c - y * s) + px; + *v = (x * s + y * c) + py; +} + +void draw_sprite_rotate(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, float rotation, float alpha) { + + double originx = (double)sprite->width / 2.0; + double originy = (double)sprite->height / 2.0; + + /* Calculate corners */ + double ul_x, ul_y; + double ll_x, ll_y; + double ur_x, ur_y; + double lr_x, lr_y; + + calc_rotation(-sprite->width/2, -sprite->height/2, 0, 0, rotation, &ul_x, &ul_y); + calc_rotation(-sprite->width/2, sprite->height/2, 0, 0, rotation, &ll_x, &ll_y); + calc_rotation(sprite->width/2, -sprite->height/2, 0, 0, rotation, &ur_x, &ur_y); + calc_rotation(sprite->width/2, sprite->height/2, 0, 0, rotation, &lr_x, &lr_y); + + /* Calculate bounds */ + int32_t _left = min(min(ul_x, ll_x), min(ur_x, lr_x)); + int32_t _top = min(min(ul_y, ll_y), min(ur_y, lr_y)); + int32_t _right = max(max(ul_x, ll_x), max(ur_x, lr_x)); + int32_t _bottom = max(max(ul_y, ll_y), max(ur_y, lr_y)); + + for (int32_t _y = _top; _y < _bottom; ++_y) { + if (_y + y < 0) continue; + if (_y + y >= ctx->height) break; + if (!_is_in_clip(ctx, y + _y)) continue; + for (int32_t _x = _left; _x < _right; ++_x) { + if (_x + x < 0) continue; + if (_x + x >= ctx->width) break; + double u, v; + calc_rotation(_x + originx, _y + originy, originx, originy, -rotation, &u, &v); + uint32_t n_color = getBilinearFilteredPixelColor(sprite, u / (double)sprite->width, v/(double)sprite->height); + uint32_t f_color = rgb(_ALP(n_color) * alpha, 0, 0); + GFX(ctx, x + _x, y + _y) = alpha_blend(GFX(ctx, x + _x, y + _y), n_color, f_color); + } + } +} + diff --git a/lib/hashmap.c b/lib/hashmap.c new file mode 100644 index 00000000..5307efa3 --- /dev/null +++ b/lib/hashmap.c @@ -0,0 +1,226 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2018 K. Lange + */ + +#include +#include + +unsigned int hashmap_string_hash(void * _key) { + unsigned int hash = 0; + char * key = (char *)_key; + int c; + /* This is the so-called "sdbm" hash. It comes from a piece of + * public domain code from a clone of ndbm. */ + while ((c = *key++)) { + hash = c + (hash << 6) + (hash << 16) - hash; + } + return hash; +} + +int hashmap_string_comp(void * a, void * b) { + return !strcmp(a,b); +} + +void * hashmap_string_dupe(void * key) { + return strdup(key); +} + +unsigned int hashmap_int_hash(void * key) { + return (unsigned int)key; +} + +int hashmap_int_comp(void * a, void * b) { + return (int)a == (int)b; +} + +void * hashmap_int_dupe(void * key) { + return key; +} + +static void hashmap_int_free(void * ptr) { + (void)ptr; + return; +} + + +hashmap_t * hashmap_create(int size) { + hashmap_t * map = malloc(sizeof(hashmap_t)); + + map->hash_func = &hashmap_string_hash; + map->hash_comp = &hashmap_string_comp; + map->hash_key_dup = &hashmap_string_dupe; + map->hash_key_free = &free; + map->hash_val_free = &free; + + map->size = size; + map->entries = malloc(sizeof(hashmap_entry_t *) * size); + memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size); + + return map; +} + +hashmap_t * hashmap_create_int(int size) { + hashmap_t * map = malloc(sizeof(hashmap_t)); + + map->hash_func = &hashmap_int_hash; + map->hash_comp = &hashmap_int_comp; + map->hash_key_dup = &hashmap_int_dupe; + map->hash_key_free = &hashmap_int_free; + map->hash_val_free = &free; + + map->size = size; + map->entries = malloc(sizeof(hashmap_entry_t *) * size); + memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size); + + return map; +} + +void * hashmap_set(hashmap_t * map, void * key, void * value) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t)); + e->key = map->hash_key_dup(key); + e->value = value; + e->next = NULL; + map->entries[hash] = e; + return NULL; + } else { + hashmap_entry_t * p = NULL; + do { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + x->value = value; + return out; + } else { + p = x; + x = x->next; + } + } while (x); + hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t)); + e->key = map->hash_key_dup(key); + e->value = value; + e->next = NULL; + + p->next = e; + return NULL; + } +} + +void * hashmap_get(hashmap_t * map, void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return NULL; + } else { + do { + if (map->hash_comp(x->key, key)) { + return x->value; + } + x = x->next; + } while (x); + return NULL; + } +} + +void * hashmap_remove(hashmap_t * map, void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return NULL; + } else { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + map->entries[hash] = x->next; + map->hash_key_free(x->key); + map->hash_val_free(x); + return out; + } else { + hashmap_entry_t * p = x; + x = x->next; + do { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + p->next = x->next; + map->hash_key_free(x->key); + map->hash_val_free(x); + return out; + } + p = x; + x = x->next; + } while (x); + } + return NULL; + } +} + +int hashmap_has(hashmap_t * map, void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return 0; + } else { + do { + if (map->hash_comp(x->key, key)) { + return 1; + } + x = x->next; + } while (x); + return 0; + } + +} + +list_t * hashmap_keys(hashmap_t * map) { + list_t * l = list_create(); + + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i]; + while (x) { + list_insert(l, x->key); + x = x->next; + } + } + + return l; +} + +list_t * hashmap_values(hashmap_t * map) { + list_t * l = list_create(); + + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i]; + while (x) { + list_insert(l, x->value); + x = x->next; + } + } + + return l; +} + +void hashmap_free(hashmap_t * map) { + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i], * p; + while (x) { + p = x; + x = x->next; + map->hash_key_free(p->key); + map->hash_val_free(p); + } + } + free(map->entries); +} + +int hashmap_is_empty(hashmap_t * map) { + for (unsigned int i = 0; i < map->size; ++i) { + if (map->entries[i]) return 0; + } + return 1; +} diff --git a/lib/icon_cache.c b/lib/icon_cache.c new file mode 100644 index 00000000..82286f6d --- /dev/null +++ b/lib/icon_cache.c @@ -0,0 +1,103 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * icon_cache - caches icons + * + * Used be a few different applications. + * Probably needs scaling? + */ +#include +#include +#include +#include + +#include +#include + +static hashmap_t * icon_cache_16; +static hashmap_t * icon_cache_48; + +static char * icon_directories_16[] = { + "/usr/share/icons/16", + "/usr/share/icons/24", + "/usr/share/icons/48", + "/usr/share/icons", + "/usr/share/icons/external", + NULL +}; + +static char * icon_directories_48[] = { + "/usr/share/icons/48", + "/usr/share/icons/24", + "/usr/share/icons/16", + "/usr/share/icons", + "/usr/share/icons/external", + NULL +}; + +__attribute__((constructor)) +static void _init_caches(void) { + icon_cache_16 = hashmap_create(10); + { /* Generic fallback icon */ + sprite_t * app_icon = malloc(sizeof(sprite_t)); + load_sprite(app_icon, "/usr/share/icons/16/applications-generic.bmp"); + app_icon->alpha = ALPHA_EMBEDDED; + hashmap_set(icon_cache_16, "generic", app_icon); + } + + icon_cache_48 = hashmap_create(10); + { /* Generic fallback icon */ + sprite_t * app_icon = malloc(sizeof(sprite_t)); + load_sprite(app_icon, "/usr/share/icons/48/applications-generic.bmp"); + app_icon->alpha = ALPHA_EMBEDDED; + hashmap_set(icon_cache_48, "generic", app_icon); + } +} + + +static sprite_t * icon_get_int(const char * name, hashmap_t * icon_cache, char ** icon_directories) { + + if (!strcmp(name,"")) { + /* If a window doesn't have an icon set, return the generic icon */ + return hashmap_get(icon_cache, "generic"); + } + + /* Check the icon cache */ + sprite_t * icon = hashmap_get(icon_cache, (void*)name); + + if (!icon) { + /* We don't have an icon cached for this identifier, try search */ + int i = 0; + char path[100]; + while (icon_directories[i]) { + /* Check each path... */ + sprintf(path, "%s/%s.bmp", icon_directories[i], name); + if (access(path, R_OK) == 0) { + /* And if we find one, cache it */ + icon = malloc(sizeof(sprite_t)); + load_sprite(icon, path); + icon->alpha = ALPHA_EMBEDDED; + hashmap_set(icon_cache, (void*)name, icon); + return icon; + } + i++; + } + + /* If we've exhausted our search paths, just return the generic icon */ + icon = hashmap_get(icon_cache, "generic"); + hashmap_set(icon_cache, (void*)name, icon); + } + + /* We have an icon, return it */ + return icon; +} + +sprite_t * icon_get_16(const char * name) { + return icon_get_int(name, icon_cache_16, icon_directories_16); +} + +sprite_t * icon_get_48(const char * name) { + return icon_get_int(name, icon_cache_48, icon_directories_48); +} diff --git a/userspace/lib/kbd.c b/lib/kbd.c similarity index 82% rename from userspace/lib/kbd.c rename to lib/kbd.c index e775b6bf..63f7b15a 100644 --- a/userspace/lib/kbd.c +++ b/lib/kbd.c @@ -1,8 +1,8 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2014 Kevin Lange - */ -/* + * Copyright (C) 2012-2018 K. Lange + * * General-purpose keyboard conversion library. * * This provides similar functionality to xkb: @@ -11,7 +11,8 @@ * - It translates incoming keys to escape sequences */ -#include "kbd.h" +#include +#include #define DEBUG_SCANCODES 0 @@ -150,6 +151,18 @@ kbd_key_t kbd_key(key_event_state_t * state, unsigned char c) { } case KBD_ESC_O: switch (c) { + case 0x41: + state->kbd_state = KBD_NORMAL; + return KEY_ARROW_UP; + case 0x42: + state->kbd_state = KBD_NORMAL; + return KEY_ARROW_DOWN; + case 0x43: + state->kbd_state = KBD_NORMAL; + return KEY_ARROW_RIGHT; + case 0x44: + state->kbd_state = KBD_NORMAL; + return KEY_ARROW_LEFT; case 'H': state->kbd_state = KBD_NORMAL; return KEY_HOME; @@ -174,6 +187,13 @@ kbd_key_t kbd_key(key_event_state_t * state, unsigned char c) { case 0x44: state->kbd_state = KBD_NORMAL; return KEY_ARROW_LEFT; + case 'H': + state->kbd_state = KBD_NORMAL; + return KEY_HOME; + case 'F': + state->kbd_state = KBD_NORMAL; + return KEY_END; + case '1': case '2': case '3': case '4': @@ -253,6 +273,12 @@ kbd_key_t kbd_key(key_event_state_t * state, unsigned char c) { default: return c; } + case ';': + /* We don't produce multiple-argument escapes ourself, but + * we should handle them anyway because other terminals + * definitely do make them... */ + state->kbd_state = KBD_ESC_B; + return KEY_NONE; default: return c; } @@ -351,6 +377,58 @@ int kbd_scancode(key_event_state_t * state, unsigned char c, key_event_t * event event->keycode = KEY_LEFT_ALT; SET_UNSET(event->modifiers, KEY_MOD_LEFT_ALT, down); break; + case KEY_SCANCODE_NUM_0: + event->keycode = KEY_NUM_0; + event->key = '0'; + break; + case KEY_SCANCODE_NUM_1: + event->keycode = KEY_NUM_1; + event->key = '1'; + break; + case KEY_SCANCODE_NUM_2: + event->keycode = KEY_NUM_2; + event->key = '2'; + break; + case KEY_SCANCODE_NUM_3: + event->keycode = KEY_NUM_3; + event->key = '3'; + break; + case KEY_SCANCODE_NUM_4: + event->keycode = KEY_NUM_4; + event->key = '4'; + break; + case KEY_SCANCODE_NUM_5: + event->keycode = KEY_NUM_5; + event->key = '5'; + break; + case KEY_SCANCODE_NUM_6: + event->keycode = KEY_NUM_6; + event->key = '6'; + break; + case KEY_SCANCODE_NUM_7: + event->keycode = KEY_NUM_7; + event->key = '7'; + break; + case KEY_SCANCODE_NUM_8: + event->keycode = KEY_NUM_8; + event->key = '8'; + break; + case KEY_SCANCODE_NUM_9: + event->keycode = KEY_NUM_9; + event->key = '9'; + break; + case KEY_SCANCODE_NUM_DOT: + event->keycode = KEY_NUM_DOT; + event->key = '.'; + break; + case KEY_SCANCODE_NUM_MIN: + event->keycode = KEY_NUM_MINUS; + event->key = '-'; + break; + case KEY_SCANCODE_NUM_ADD: + event->keycode = KEY_NUM_PLUS; + event->key = '+'; + break; default: break; } @@ -469,6 +547,14 @@ int kbd_scancode(key_event_state_t * state, unsigned char c, key_event_t * event case 0x53: event->keycode = KEY_DEL; break; + case 0x35: + event->keycode = KEY_NUM_DIV; + event->key = '/'; + break; + case 0x1C: + event->keycode = KEY_NUM_ENTER; + event->key = '\n'; + break; default: break; } diff --git a/lib/list.c b/lib/list.c new file mode 100644 index 00000000..b76da626 --- /dev/null +++ b/lib/list.c @@ -0,0 +1,248 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2018 K. Lange + * + * General-purpose list implementations. + */ + +#ifdef _KERNEL_ +# include +#else +# include +# include +#endif + +#include + +void list_destroy(list_t * list) { + /* Free all of the contents of a list */ + node_t * n = list->head; + while (n) { + free(n->value); + n = n->next; + } +} + +void list_free(list_t * list) { + /* Free the actual structure of a list */ + node_t * n = list->head; + while (n) { + node_t * s = n->next; + free(n); + n = s; + } +} + +void list_append(list_t * list, node_t * node) { + assert(!(node->next || node->prev) && "Node is already in a list."); + node->next = NULL; + /* Insert a node onto the end of a list */ + node->owner = list; + if (!list->length) { + list->head = node; + list->tail = node; + node->prev = NULL; + node->next = NULL; + list->length++; + return; + } + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + list->length++; +} + +node_t * list_insert(list_t * list, void * item) { + /* Insert an item into a list */ + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append(list, node); + + return node; +} + +void list_append_after(list_t * list, node_t * before, node_t * node) { + assert(!(node->next || node->prev) && "Node is already in a list."); + node->owner = list; + if (!list->length) { + list_append(list, node); + return; + } + if (before == NULL) { + node->next = list->head; + node->prev = NULL; + list->head->prev = node; + list->head = node; + list->length++; + return; + } + if (before == list->tail) { + list->tail = node; + } else { + before->next->prev = node; + node->next = before->next; + } + node->prev = before; + before->next = node; + list->length++; +} + +node_t * list_insert_after(list_t * list, node_t * before, void * item) { + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append_after(list, before, node); + return node; +} + +void list_append_before(list_t * list, node_t * after, node_t * node) { + assert(!(node->next || node->prev) && "Node is already in a list."); + node->owner = list; + if (!list->length) { + list_append(list, node); + return; + } + if (after == NULL) { + node->next = NULL; + node->prev = list->tail; + list->tail->next = node; + list->tail = node; + list->length++; + return; + } + if (after == list->head) { + list->head = node; + } else { + after->prev->next = node; + node->prev = after->prev; + } + node->next = after; + after->prev = node; + list->length++; +} + +node_t * list_insert_before(list_t * list, node_t * after, void * item) { + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append_before(list, after, node); + return node; +} + +list_t * list_create(void) { + /* Create a fresh list */ + list_t * out = malloc(sizeof(list_t)); + out->head = NULL; + out->tail = NULL; + out->length = 0; + return out; +} + +node_t * list_find(list_t * list, void * value) { + foreach(item, list) { + if (item->value == value) { + return item; + } + } + return NULL; +} + +int list_index_of(list_t * list, void * value) { + int i = 0; + foreach(item, list) { + if (item->value == value) { + return i; + } + i++; + } + return -1; /* not find */ +} + +void list_remove(list_t * list, size_t index) { + /* remove index from the list */ + if (index > list->length) return; + size_t i = 0; + node_t * n = list->head; + while (i < index) { + n = n->next; + i++; + } + list_delete(list, n); +} + +void list_delete(list_t * list, node_t * node) { + /* remove node from the list */ + assert(node->owner == list && "Tried to remove a list node from a list it does not belong to."); + if (node == list->head) { + list->head = node->next; + } + if (node == list->tail) { + list->tail = node->prev; + } + if (node->prev) { + node->prev->next = node->next; + } + if (node->next) { + node->next->prev = node->prev; + } + node->prev = NULL; + node->next = NULL; + node->owner = NULL; + list->length--; +} + +node_t * list_pop(list_t * list) { + /* Remove and return the last value in the list + * If you don't need it, you still probably want to free it! + * Try free(list_pop(list)); ! + * */ + if (!list->tail) return NULL; + node_t * out = list->tail; + list_delete(list, out); + return out; +} + +node_t * list_dequeue(list_t * list) { + if (!list->head) return NULL; + node_t * out = list->head; + list_delete(list, out); + return out; +} + +list_t * list_copy(list_t * original) { + /* Create a new copy of original */ + list_t * out = list_create(); + node_t * node = original->head; + while (node) { + list_insert(out, node->value); + } + return out; +} + +void list_merge(list_t * target, list_t * source) { + /* Destructively merges source into target */ + foreach(node, source) { + node->owner = target; + } + if (source->head) { + source->head->prev = target->tail; + } + if (target->tail) { + target->tail->next = source->head; + } else { + target->head = source->head; + } + if (source->tail) { + target->tail = source->tail; + } + target->length += source->length; + free(source); +} diff --git a/lib/menu.c b/lib/menu.c new file mode 100644 index 00000000..d2a87bb9 --- /dev/null +++ b/lib/menu.c @@ -0,0 +1,955 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * menu - Provides menus. + * + * C reimplementation of the original Python menu library. + * Used to provide menu bars and the applications menu. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define MENU_ENTRY_HEIGHT 20 +#define MENU_BACKGROUND rgb(239,238,232) +#define MENU_ICON_SIZE 16 + +#define HILIGHT_BORDER_TOP rgb(54,128,205) +#define HILIGHT_GRADIENT_TOP rgb(93,163,236) +#define HILIGHT_GRADIENT_BOTTOM rgb(56,137,220) +#define HILIGHT_BORDER_BOTTOM rgb(47,106,167) + +static hashmap_t * menu_windows = NULL; +static yutani_t * my_yctx = NULL; + +static struct MenuList * hovered_menu = NULL; + +int menu_definitely_close(struct MenuList * menu); + +/** Freetype extension renderer functions */ +static int _have_freetype = 0; +static void (*freetype_set_font_face)(int face) = NULL; +static void (*freetype_set_font_size)(int size) = NULL; +static int (*freetype_draw_string)(gfx_context_t * ctx, int x, int y, uint32_t fg, const char * s) = NULL; +static int (*freetype_draw_string_width)(char * s) = NULL; + +__attribute__((constructor)) +static void _init_menus(void) { + menu_windows = hashmap_create_int(10); + void * freetype = dlopen("libtoaru_ext_freetype_fonts.so", 0); + if (freetype) { + _have_freetype = 1; + freetype_set_font_face = dlsym(freetype, "freetype_set_font_face"); + freetype_set_font_size = dlsym(freetype, "freetype_set_font_size"); + freetype_draw_string = dlsym(freetype, "freetype_draw_string"); + freetype_draw_string_width = dlsym(freetype, "freetype_draw_string_width"); + } +} + +hashmap_t * menu_get_windows_hash(void) { + return menu_windows; +} + +static int string_width(const char * s) { + if (_have_freetype) { + freetype_set_font_face(0); /* regular non-monospace */ + freetype_set_font_size(13); + return freetype_draw_string_width((char *)s); + } else { + return draw_sdf_string_width((char *)s, 16, SDF_FONT_THIN); + } +} + +static int draw_string(gfx_context_t * ctx, int x, int y, uint32_t color, const char * s) { + if (_have_freetype) { + freetype_set_font_face(0); /* regular non-monospace */ + freetype_set_font_size(13); + return freetype_draw_string(ctx, x+2, y + 13 /* I think? */, color, s); + } else { + return draw_sdf_string(ctx, x, y, s, 16, color, SDF_FONT_THIN); + } +} + +void _menu_draw_MenuEntry_Normal(gfx_context_t * ctx, struct MenuEntry * self, int offset) { + struct MenuEntry_Normal * _self = (struct MenuEntry_Normal *)self; + + _self->offset = offset; + + /* Background gradient */ + if (_self->hilight) { + draw_line(ctx, 1, _self->width-2, offset, offset, HILIGHT_BORDER_TOP); + draw_line(ctx, 1, _self->width-2, offset + _self->height - 1, offset + _self->height - 1, HILIGHT_BORDER_BOTTOM); + for (int i = 1; i < self->height-1; ++i) { + int thing = ((i - 1) * 256) / (_self->height - 2); + if (thing > 255) thing = 255; + if (thing < 0) thing = 0; + uint32_t c = interp_colors(HILIGHT_GRADIENT_TOP, HILIGHT_GRADIENT_BOTTOM, thing); + draw_line(ctx, 1, self->width-2, offset + i, offset + i, c); + } + } + + /* Icon */ + if (_self->icon) { + sprite_t * icon = icon_get_16(_self->icon); + if (icon->width == MENU_ICON_SIZE) { + draw_sprite(ctx, icon, 4, offset + 2); + } else { + draw_sprite_scaled(ctx, icon, 4, offset + 2, MENU_ICON_SIZE, MENU_ICON_SIZE); + } + } + + /* Foreground text color */ + uint32_t color = _self->hilight ? rgb(255,255,255) : rgb(0,0,0); + + /* Draw title */ + draw_string(ctx, 22, offset + 1, color, _self->title); +} + +void _menu_focus_MenuEntry_Normal(struct MenuEntry * self, int focused) { + if (focused) { + if (self->_owner && self->_owner->child) { + menu_definitely_close(self->_owner->child); + self->_owner->child = NULL; + } + } +} + +void _menu_activate_MenuEntry_Normal(struct MenuEntry * self, int flags) { + struct MenuEntry_Normal * _self = (struct MenuEntry_Normal *)self; + + list_t * menu_keys = hashmap_keys(menu_windows); + hovered_menu = NULL; + foreach(_key, menu_keys) { + yutani_window_t * window = hashmap_get(menu_windows, (void*)_key->value); + if (window) { + struct MenuList * menu = window->user_data; + menu_definitely_close(menu); + if (menu->parent && menu->parent->child == menu) { + menu->parent->child = NULL; + } + } + } + + list_free(menu_keys); + free(menu_keys); + + if (_self->callback) { + _self->callback(_self); + } +} + +struct MenuEntry * menu_create_normal(const char * icon, const char * action, const char * title, void (*callback)(struct MenuEntry *)) { + struct MenuEntry_Normal * out = malloc(sizeof(struct MenuEntry_Normal)); + + out->_type = MenuEntry_Normal; + out->height = MENU_ENTRY_HEIGHT; + out->hilight = 0; + out->renderer = _menu_draw_MenuEntry_Normal; + out->focus_change = _menu_focus_MenuEntry_Normal; + out->activate = _menu_activate_MenuEntry_Normal; + out->icon = icon ? strdup(icon) : NULL; + out->title = strdup(title); + out->action = action ? strdup(action) : NULL; + out->callback = callback; + + out->rwidth = 50 + string_width(out->title); + + return (struct MenuEntry *)out; +} + +void _menu_draw_MenuEntry_Submenu(gfx_context_t * ctx, struct MenuEntry * self, int offset) { + + struct MenuEntry_Submenu * _self = (struct MenuEntry_Submenu *)self; + int h = _self->hilight; + if (_self->_owner && _self->_my_child && _self->_owner->child == _self->_my_child) { + _self->hilight = 1; + } + _menu_draw_MenuEntry_Normal(ctx,self,offset); + + /* Draw the tick on the right side to indicate this is a submenu */ + uint32_t color = _self->hilight ? rgb(255,255,255) : rgb(0,0,0); + sprite_t * tick = icon_get_16("menu-tick"); + draw_sprite_alpha_paint(ctx, tick, _self->width - 16, offset + 2, 1.0, color); + _self->hilight = h; +} + +void _menu_focus_MenuEntry_Submenu(struct MenuEntry * self, int focused) { + if (focused) { + self->activate(self, focused); + } +} + +void _menu_activate_MenuEntry_Submenu(struct MenuEntry * self, int focused) { + struct MenuEntry_Submenu * _self = (struct MenuEntry_Submenu *)self; + + if (_self->_owner && _self->_owner->set) { + /* Show a menu */ + struct MenuList * new_menu = menu_set_get_menu(_self->_owner->set, (char *)_self->action); + if (_self->_owner->child && _self->_owner->child != new_menu) { + menu_definitely_close(_self->_owner->child); + _self->_owner->child = NULL; + } + new_menu->parent = _self->_owner; + new_menu->parent->child = new_menu; + _self->_my_child = new_menu; + if (new_menu->closed) { + menu_show(new_menu, _self->_owner->window->ctx); + if (_self->_owner->window->width + _self->_owner->window->x - 2 + new_menu->window->width > _self->_owner->window->ctx->display_width) { + yutani_window_move(_self->_owner->window->ctx, new_menu->window, _self->_owner->window->x + 2 - new_menu->window->width, _self->_owner->window->y + _self->offset - 4); + } else { + yutani_window_move(_self->_owner->window->ctx, new_menu->window, _self->_owner->window->width + _self->_owner->window->x - 2, _self->_owner->window->y + _self->offset - 4); + } + } + } + +} + +struct MenuEntry * menu_create_submenu(const char * icon, const char * action, const char * title) { + struct MenuEntry_Submenu * out = malloc(sizeof(struct MenuEntry_Submenu)); + + out->_type = MenuEntry_Submenu; + out->height = MENU_ENTRY_HEIGHT; + out->hilight = 0; + out->renderer = _menu_draw_MenuEntry_Submenu; + out->focus_change = _menu_focus_MenuEntry_Submenu; + out->activate = _menu_activate_MenuEntry_Submenu; + out->icon = icon ? strdup(icon) : NULL; + out->title = strdup(title); + out->action = action ? strdup(action) : NULL; + + out->rwidth = 50 + string_width(out->title); + + return (struct MenuEntry *)out; +} + +void _menu_draw_MenuEntry_Separator(gfx_context_t * ctx, struct MenuEntry * self, int offset) { + self->offset = offset; + draw_line(ctx, 2, self->width-4, offset+3, offset+3, rgb(178,178,178)); + draw_line(ctx, 2, self->width-5, offset+4, offset+4, rgb(250,250,250)); +} + +void _menu_focus_MenuEntry_Separator(struct MenuEntry * self, int focused) { + if (focused) { + if (self->_owner && self->_owner->child) { + menu_definitely_close(self->_owner->child); + self->_owner->child = NULL; + } + } +} + +void _menu_activate_MenuEntry_Separator(struct MenuEntry * self, int focused) { + +} + +struct MenuEntry * menu_create_separator(void) { + struct MenuEntry_Separator * out = malloc(sizeof(struct MenuEntry_Separator)); + + out->_type = MenuEntry_Separator; + out->height = 6; + out->hilight = 0; + out->renderer = _menu_draw_MenuEntry_Separator; + out->focus_change = _menu_focus_MenuEntry_Separator; + out->rwidth = 10; /* at least a bit please */ + out->activate = _menu_activate_MenuEntry_Separator; + + return (struct MenuEntry *)out; +} + +void menu_update_title(struct MenuEntry * self, char * new_title) { + + if (self->_type == MenuEntry_Normal) { + struct MenuEntry_Normal * _self = (struct MenuEntry_Normal *)self; + if (_self->title) { + free((void*)_self->title); + } + _self->title = strdup(new_title); + _self->rwidth = 50 + string_width(_self->title); + } else if (self->_type == MenuEntry_Submenu) { + struct MenuEntry_Submenu * _self = (struct MenuEntry_Submenu *)self; + if (_self->title) { + free((void*)_self->title); + } + _self->title = strdup(new_title); + _self->rwidth = 50 + string_width(_self->title); + } +} + +static int _close_enough(struct yutani_msg_window_mouse_event * me) { + if (me->command == YUTANI_MOUSE_EVENT_RAISE && sqrt(pow(me->new_x - me->old_x, 2) + pow(me->new_y - me->old_y, 2)) < 10) { + return 1; + } + return 0; +} + +static char read_buf[1024]; +static size_t available = 0; +static size_t offset = 0; +static size_t read_from = 0; +static char * read_line(FILE * f, char * out, ssize_t len) { + while (len > 0) { + if (available == 0) { + if (offset == 1024) { + offset = 0; + } + size_t r = read(fileno(f), &read_buf[offset], 1024 - offset); + read_from = offset; + available = r; + offset += available; + } + + if (available == 0) { + *out = '\0'; + return out; + } + + while (read_from < offset && len > 0) { + *out = read_buf[read_from]; + len--; + read_from++; + available--; + if (*out == '\n') { + return out; + } + out++; + } + } + + return out; +} + +static void _menu_calculate_dimensions(struct MenuList * menu, int * height, int * width) { + list_t * list = menu->entries; + *width = 0; + *height = 8; /* TODO top and height */ + foreach(node, list) { + struct MenuEntry * entry = node->value; + *height += entry->height; + if (*width < entry->rwidth) { + *width = entry->rwidth; + } + } + /* Go back through and update actual widths */ + foreach(node, list) { + struct MenuEntry * entry = node->value; + entry->width = *width; + } +} + +struct MenuList * menu_set_get_root(struct MenuSet * menu) { + return (void*)hashmap_get(menu->_menus,"_"); +} + +struct MenuList * menu_set_get_menu(struct MenuSet * menu, char * submenu) { + return (void*)hashmap_get(menu->_menus, submenu); +} + +void menu_insert(struct MenuList * menu, struct MenuEntry * entry) { + list_insert(menu->entries, entry); + entry->_owner = menu; +} + +struct MenuList * menu_create(void) { + struct MenuList * p = malloc(sizeof(struct MenuList)); + p->entries = list_create(); + p->ctx = NULL; + p->window = NULL; + p->set = NULL; + p->child = NULL; + p->_bar = NULL; + p->parent = NULL; + p->closed = 1; + return p; +} + +struct MenuSet * menu_set_create(void) { + struct MenuSet * _out = malloc(sizeof(struct MenuSet)); + _out->_menus = hashmap_create(10); + return _out; +} + +void menu_set_insert(struct MenuSet * set, char * action, struct MenuList * menu) { + hashmap_set(set->_menus, action, menu); + menu->set = set; +} + +struct MenuSet * menu_set_from_description(const char * path, void (*callback)(struct MenuEntry *)) { + FILE * f; + if (!strcmp(path,"-")) { + f = stdin; + } else { + f = fopen(path,"r"); + } + + if (!f) { + return NULL; + } + + struct MenuSet * _out = malloc(sizeof(struct MenuSet)); + hashmap_t * out = hashmap_create(10); + _out->_menus = out; + + struct MenuList * current_menu = NULL; + + /* Read through the file */ + char line[256]; + while (1) { + memset(line, 0, 256); + read_line(f, line, 256); + if (!*line) break; + + if (line[strlen(line)-1] == '\n') { + line[strlen(line)-1] = '\0'; + } + + if (!*line) continue; /* skip blank */ + + if (*line == ':') { + /* New menu */ + struct MenuList * p = malloc(sizeof(struct MenuList)); + p->entries = list_create(); + p->ctx = NULL; + p->window = NULL; + p->set = _out; + p->child = NULL; + p->_bar = NULL; + p->parent = NULL; + p->closed = 1; + hashmap_set(out, line+1, p); + current_menu = p; + } else if (*line == '#') { + /* Comment */ + continue; + } else if (*line == '-') { + if (!current_menu) { + fprintf(stderr, "Tried to add separator with no active menu.\n"); + goto failure; + } + menu_insert(current_menu, menu_create_separator()); + } else if (*line == '&') { + if (!current_menu) { + fprintf(stderr, "Tried to add submenu with no active menu.\n"); + goto failure; + } + char * action = line+1; + char * icon = strstr(action,","); + if (!icon) { + fprintf(stderr, "Malformed line in submenu: no icon\n"); + goto failure; + } + *icon = '\0'; + icon++; + char * title = strstr(icon,","); + if (!title) { + fprintf(stderr, "Malformed line in submenu: no title\n"); + goto failure; + } + *title = '\0'; + title++; + menu_insert(current_menu, menu_create_submenu(icon,action,title)); + } else { + if (!current_menu) { + fprintf(stderr, "Tried to add item with no active menu.\n"); + goto failure; + } + char * action = line; + char * icon = strstr(action,","); + if (!icon) { + fprintf(stderr, "Malformed line in action: no icon\n"); + goto failure; + } + *icon = '\0'; + icon++; + char * title = strstr(icon,","); + if (!title) { + fprintf(stderr, "Malformed line in action: no title\n"); + goto failure; + } + *title = '\0'; + title++; + menu_insert(current_menu, menu_create_normal(icon,action,title,callback)); + } + } + + return _out; + +failure: + fprintf(stderr, "malformed description file\n"); + if (f != stdin) { + fclose(f); + } + free(out); + return NULL; +} + +static void _menu_redraw(yutani_window_t * menu_window, yutani_t * yctx, struct MenuList * menu) { + + gfx_context_t * ctx = menu->ctx; + list_t * entries = menu->entries; + /* Window background */ + draw_fill(ctx, MENU_BACKGROUND); + + /* Window border */ + draw_line(ctx, 0, ctx->width-1, 0, 0, rgb(109,111,112)); + draw_line(ctx, 0, 0, 0, ctx->height-1, rgb(109,111,112)); + draw_line(ctx, ctx->width-1, ctx->width-1, 0, ctx->height-1, rgb(109,111,112)); + draw_line(ctx, 0, ctx->width-1, ctx->height-1, ctx->height-1, rgb(109,111,112)); + + /* Draw menu entries */ + int offset = 4; + foreach(node, entries) { + struct MenuEntry * entry = node->value; + if (entry->renderer) { + entry->renderer(ctx, entry, offset); + } + + offset += entry->height; + } + + /* Expose menu */ + flip(ctx); + yutani_flip(yctx, menu_window); +} + +void menu_show(struct MenuList * menu, yutani_t * yctx) { + /* Calculate window dimensions */ + int height, width; + _menu_calculate_dimensions(menu,&height, &width); + + my_yctx = yctx; + + menu->closed = 0; + + /* Create window */ + yutani_window_t * menu_window = yutani_window_create_flags(yctx, width, height, YUTANI_WINDOW_FLAG_ALT_ANIMATION); + if (menu->ctx) { + reinit_graphics_yutani(menu->ctx, menu_window); + } else { + menu->ctx = init_graphics_yutani_double_buffer(menu_window); + } + + menu_window->user_data = menu; + menu->window = menu_window; + + _menu_redraw(menu_window, yctx, menu); + + hashmap_set(menu_windows, (void*)menu_window->wid, menu_window); +} + +int menu_has_eventual_child(struct MenuList * root, struct MenuList * child) { + + if (!child) return 0; + if (root == child) return 1; + + struct MenuList * candidate = root->child; + + while (candidate && candidate != child) { + if (candidate == root->child) { + root->child = NULL; + return 1; + } + candidate = root->child; + } + + return (candidate == child); +} + +int menu_definitely_close(struct MenuList * menu) { + + if (menu->child) { + menu_definitely_close(menu->child); + menu->child = NULL; + } + + if (menu->closed) { + return 0; + } + + /* if focused_widget, leave focus on widget */ + foreach(node, menu->entries) { + struct MenuEntry * entry = node->value; + entry->hilight = 0; + } + menu->closed = 1; + yutani_wid_t wid = menu->window->wid; + yutani_close(menu->window->ctx, menu->window); + menu->window = NULL; + hashmap_remove(menu_windows, (void*)wid); + + return 0; +} + +int menu_leave(struct MenuList * menu) { + + if (!hovered_menu) { + while (menu->parent) { + menu = menu->parent; + } + menu_definitely_close(menu); + return 0; + } + + if (!menu_has_eventual_child(menu, hovered_menu)) { + /* Get all menus */ + list_t * menu_keys = hashmap_keys(menu_windows); + foreach(_key, menu_keys) { + yutani_window_t * window = hashmap_get(menu_windows, (void *)_key->value); + if (window) { + struct MenuList * menu = window->user_data; + if (!hovered_menu || (menu != hovered_menu->child && !menu_has_eventual_child(menu, hovered_menu))) { + menu_definitely_close(menu); + if (menu->parent && menu->parent->child == menu) { + menu->parent->child = NULL; + } + } + } + } + + list_free(menu_keys); + free(menu_keys); + } + + return 0; +} + +void menu_key_action(struct MenuList * menu, struct yutani_msg_key_event * me) { + if (me->event.action != KEY_ACTION_DOWN) return; + + yutani_window_t * window = menu->window; + yutani_t * yctx = window->ctx; + + hovered_menu = menu; + + /* Find hilighted entry */ + struct MenuEntry * hilighted = NULL; + struct MenuEntry * previous = NULL; + struct MenuEntry * next = NULL; + int got_it = 0; + foreach(node, menu->entries) { + struct MenuEntry * entry = node->value; + if (entry->hilight) { + hilighted = entry; + got_it = 1; + continue; + } + if (got_it) { + next = entry; + break; + } + previous = entry; + } + + if (me->event.keycode == KEY_ARROW_DOWN) { + if (hilighted) { + hilighted->hilight = 0; + hilighted = next; + } + if (!hilighted) { + /* Use the first entry */ + hilighted = menu->entries->head->value; + } + hilighted->hilight = 1; + _menu_redraw(window,yctx,menu); + } else if (me->event.keycode == KEY_ARROW_UP) { + if (hilighted) { + hilighted->hilight = 0; + hilighted = previous; + } + if (!hilighted) { + /* Use the last entry */ + hilighted = menu->entries->tail->value; + } + hilighted->hilight = 1; + _menu_redraw(window,yctx,menu); + } else if (me->event.keycode == KEY_ARROW_RIGHT) { + if (!hilighted) { + hilighted = menu->entries->head->value; + } + if (hilighted) { + hilighted->hilight = 1; + if (hilighted->_type == MenuEntry_Submenu) { + hilighted->activate(hilighted, 0); + _menu_redraw(window,yctx,menu); + } else { + struct menu_bar * bar = NULL; + struct MenuList * p = menu; + do { + if (p->_bar) { + bar = p->_bar; + break; + } + } while ((p = p->parent)); + if (bar) { + menu_definitely_close(p); + int active = (bar->active_entry_idx + 1 + bar->num_entries) % (bar->num_entries); + bar->active_entry = &bar->entries[active]; + if (bar->redraw_callback) { + bar->redraw_callback(); + } + menu_bar_show_menu(yctx, bar->window, bar, -1, bar->active_entry); + } else { + _menu_redraw(window,yctx,menu); + } + } + } + } else if (me->event.key == '\n') { + if (!hilighted) { + hilighted = menu->entries->head->value; + } + if (hilighted) { + hilighted->hilight = 1; + hilighted->activate(hilighted, 0); + } + } else if (me->event.keycode == KEY_ARROW_LEFT) { + if (menu->parent) { + hovered_menu = menu->parent; + } /* else previous from menu bar? */ + menu_definitely_close(menu); + if (menu->_bar) { + int active = (menu->_bar->active_entry_idx - 1 + menu->_bar->num_entries) % (menu->_bar->num_entries); + menu->_bar->active_entry = &menu->_bar->entries[active]; + if (menu->_bar->redraw_callback) { + menu->_bar->redraw_callback(); + } + menu_bar_show_menu(yctx, menu->_bar->window, menu->_bar, -1, menu->_bar->active_entry); + } else if (menu->parent && menu->parent->window) { + yutani_focus_window(yctx, menu->parent->window->wid); + } + } else if (me->event.keycode == KEY_ESCAPE) { + hovered_menu = NULL; + menu_leave(menu); + } +} + +void menu_mouse_action(struct MenuList * menu, struct yutani_msg_window_mouse_event * me) { + yutani_window_t * window = menu->window; + yutani_t * yctx = window->ctx; + + int offset = 4; + int changed = 0; + foreach(node, menu->entries) { + struct MenuEntry * entry = node->value; + if (me->new_y >= offset && me->new_y < offset + entry->height && + me->new_x >= 0 && me->new_x < entry->width) { + if (!entry->hilight) { + changed = 1; + entry->hilight = 1; + entry->focus_change(entry, 1); + } + if (me->command == YUTANI_MOUSE_EVENT_CLICK || _close_enough(me)) { + if (entry->activate) { + entry->activate(entry, 0); + } + } + } else { + if (entry->hilight) { + changed = 1; + entry->hilight = 0; + entry->focus_change(entry, 0); + } + } + offset += entry->height; + } + if (changed) { + _menu_redraw(window,yctx,menu); + } +} + +struct MenuList * menu_any_contains(int x, int y) { + struct MenuList * out = NULL; + list_t * menu_keys = hashmap_keys(menu_windows); + foreach(_key, menu_keys) { + yutani_window_t * window = hashmap_get(menu_windows, (void*)_key->value); + if (window) { + if (x >= (int)window->x && x < (int)window->x + (int)window->width && y >= (int)window->y && y < (int)window->y + (int)window->height) { + out = window->user_data; + break; + + } + } + } + + list_free(menu_keys); + free(menu_keys); + + return out; +} + +int menu_process_event(yutani_t * yctx, yutani_msg_t * m) { + if (m) { + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * me = (void*)m->data; + if (hashmap_has(menu_windows, (void*)me->wid)) { + yutani_window_t * window = hashmap_get(menu_windows, (void *)me->wid); + struct MenuList * menu = window->user_data; + menu_key_action(menu, me); + } + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + if (hashmap_has(menu_windows, (void*)me->wid)) { + yutani_window_t * window = hashmap_get(menu_windows, (void *)me->wid); + struct MenuList * menu = window->user_data; + if (me->new_x >= 0 && me->new_x < (int)window->width && me->new_y >= 0 && me->new_y < (int)window->height) { + if (hovered_menu != menu) { + hovered_menu = menu; + } + } else { + if (hovered_menu) { + struct MenuList * t = menu_any_contains(me->new_x + window->x, me->new_y + window->y); + if (t) { + hovered_menu = t; + } else { + hovered_menu = NULL; + } + } + } + menu_mouse_action(menu, me); + + } + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * me = (void*)m->data; + if (hashmap_has(menu_windows, (void*)me->wid)) { + yutani_window_t * window = hashmap_get(menu_windows, (void *)me->wid); + struct MenuList * menu = window->user_data; + if (!me->focused) { + /* XXX leave menu */ + menu_leave(menu); + /* if root and not window.root.menus and window.root.focused */ + return 1; + } else { + window->focused = me->focused; + /* Redraw? */ + } + } + } + break; + default: + break; + } + } + return 0; +} + +void menu_bar_render(struct menu_bar * self, gfx_context_t * ctx) { + int _x = self->x; + int _y = self->y; + int width = self->width; + + uint32_t menu_bar_color = rgb(59,59,59); + for (int y = 0; y < MENU_BAR_HEIGHT; ++y) { + for (int x = 0; x < width; ++x) { + GFX(ctx, x+_x,y+_y) = menu_bar_color; + } + } + + /* for each menu entry */ + int offset = _x; + struct menu_bar_entries * _entries = self->entries; + + if (!self->num_entries) { + while (_entries->title) { + _entries++; + self->num_entries++; + } + _entries = self->entries; + } + while (_entries->title) { + int w = string_width(_entries->title) + 10; + if ((self->active_menu && hashmap_has(menu_get_windows_hash(), (void*)self->active_menu_wid)) && _entries == self->active_entry) { + for (int y = _y; y < _y + MENU_BAR_HEIGHT; ++y) { + for (int x = offset + 2; x < offset + 2 + w; ++x) { + GFX(ctx, x, y) = rgb(93,163,236); + } + } + } + offset += draw_string(ctx, offset + 4, _y + 2, 0xFFFFFFFF, _entries->title) + 10; + _entries++; + } +} + +void menu_bar_show_menu(yutani_t * yctx, yutani_window_t * window, struct menu_bar * self, int offset, struct menu_bar_entries * _entries) { + struct MenuList * new_menu = menu_set_get_menu(self->set, _entries->action); + int i = 0; + + if (offset == -1) { + /* Must calculate */ + offset = self->x; + struct menu_bar_entries * e = self->entries; + while (e->title) { + if (e == _entries) break; + offset += string_width(e->title) + 10; + e++; + i++; + } + } else { + struct menu_bar_entries * e = self->entries; + while (e->title) { + if (e == _entries) break; + e++; + i++; + } + } + + menu_show(new_menu, yctx); + yutani_window_move(yctx, new_menu->window, window->x + offset, window->y + self->y + MENU_BAR_HEIGHT); + self->active_menu = new_menu; + self->active_menu->_bar = self; + self->active_menu_wid = new_menu->window->wid; + self->active_entry = _entries; + self->active_entry_idx = i; + if (self->redraw_callback) { + self->redraw_callback(); + } +} + +int menu_bar_mouse_event(yutani_t * yctx, yutani_window_t * window, struct menu_bar * self, struct yutani_msg_window_mouse_event * me, int x, int y) { + if (x < self->x || x >= self->x + self->width || y < self->y || y >= self->y + 24 /* base height */) { + return 0; + } + + int offset = self->x; + + struct menu_bar_entries * _entries = self->entries; + + while (_entries->title) { + int w = string_width(_entries->title) + 10; + if (x >= offset && x < offset + w) { + if (me->command == YUTANI_MOUSE_EVENT_CLICK || _close_enough(me)) { + menu_bar_show_menu(yctx, window, self,offset,_entries); + } else if (self->active_menu && hashmap_has(menu_get_windows_hash(), (void*)self->active_menu_wid) && _entries != self->active_entry) { + menu_definitely_close(self->active_menu); + menu_bar_show_menu(yctx, window, self,offset,_entries); + } + } + + offset += w; + _entries++; + } + + if (x >= offset && me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { + yutani_window_drag_start(yctx, window); + } + + return 0; +} diff --git a/userspace/lib/pex.c b/lib/pex.c similarity index 77% rename from userspace/lib/pex.c rename to lib/pex.c index 3efad792..dd0f526c 100644 --- a/userspace/lib/pex.c +++ b/lib/pex.c @@ -1,6 +1,12 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange + * + * pex - Packet EXchange client library + * + * Provides a friendly interface to the "Packet Exchange" + * functionality provided by the packetfs kernel module. */ #include #include @@ -11,7 +17,7 @@ #include #include -#include "pex.h" +#include size_t pex_send(FILE * sock, unsigned int rcpt, size_t size, char * blob) { assert(size <= MAX_PACKET_SIZE); @@ -44,7 +50,9 @@ FILE * pex_connect(char * target) { char tmp[100]; sprintf(tmp, "/dev/pex/%s", target); FILE * out = fopen(tmp, "r+"); - setbuf(out, NULL); + if (out) { + setbuf(out, NULL); + } return out; } @@ -52,7 +60,9 @@ FILE * pex_bind(char * target) { char tmp[100]; sprintf(tmp, "/dev/pex/%s", target); FILE * out = fopen(tmp, "a+"); - setbuf(out, NULL); + if (out) { + setbuf(out, NULL); + } return out; } diff --git a/userspace/lib/rline.c b/lib/rline.c similarity index 92% rename from userspace/lib/rline.c rename to lib/rline.c index 07910eda..32fc8268 100644 --- a/userspace/lib/rline.c +++ b/lib/rline.c @@ -1,17 +1,25 @@ -/* +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015-2018 K. Lange + * * rline - a line reading library. + * + * Implements an interface similar to readline, providing more + * complex line editing than what the raw tty interface supplies. */ -#include +#define _POSIX_C_SOURCE 1 +#define _XOPEN_SOURCE 500 #include -#include + +#include #include +#include #include -#include "lib/kbd.h" - -#include "rline.h" - +#include +#include static struct termios old; @@ -28,6 +36,7 @@ static void set_buffered() { void rline_redraw(rline_context_t * context) { + if (context->quiet) return; printf("\033[u%s\033[K", context->buffer); for (int i = context->offset; i < context->collected; ++i) { printf("\033[D"); @@ -36,6 +45,7 @@ void rline_redraw(rline_context_t * context) { } void rline_redraw_clean(rline_context_t * context) { + if (context->quiet) return; printf("\033[u%s", context->buffer); for (int i = context->offset; i < context->collected; ++i) { printf("\033[D"); @@ -94,12 +104,12 @@ char * rline_history_prev(int item) { return rline_history_get(rline_history_count - item); } -static void rline_reverse_search(rline_context_t * context) { +void rline_reverse_search(rline_context_t * context) { char input[512] = {0}; int collected = 0; int start_at = 0; int changed = 0; - fprintf(stderr, "\033[G\033[s"); + fprintf(stderr, "\033[G\033[0m\033[s"); fflush(stderr); key_event_state_t kbd_state = {0}; char * match = ""; @@ -161,13 +171,13 @@ try_rev_search_again: memcpy(context->buffer, match, strlen(match) + 1); context->collected = strlen(match); context->offset = context->collected; - if (context->callbacks->redraw_prompt) { + if (!context->quiet && context->callbacks->redraw_prompt) { fprintf(stderr, "\033[G\033[K"); context->callbacks->redraw_prompt(context); } fprintf(stderr, "\033[s"); rline_redraw_clean(context); - if (key_sym == '\n') { + if (key_sym == '\n' && !context->quiet) { fprintf(stderr, "\n"); } return; @@ -190,7 +200,7 @@ static void history_previous(rline_context_t * context) { } if (rline_scroll < rline_history_count) { rline_scroll++; - for (int i = 0; i < strlen(context->buffer); ++i) { + for (int i = 0; i < (int)strlen(context->buffer); ++i) { printf("\010 \010"); } char * h = rline_history_prev(rline_scroll); @@ -205,7 +215,7 @@ static void history_previous(rline_context_t * context) { static void history_next(rline_context_t * context) { if (rline_scroll > 1) { rline_scroll--; - for (int i = 0; i < strlen(context->buffer); ++i) { + for (int i = 0; i < (int)strlen(context->buffer); ++i) { printf("\010 \010"); } char * h = rline_history_prev(rline_scroll); @@ -213,7 +223,7 @@ static void history_next(rline_context_t * context) { printf("%s", h); fflush(stdout); } else if (rline_scroll == 1) { - for (int i = 0; i < strlen(context->buffer); ++i) { + for (int i = 0; i < (int)strlen(context->buffer); ++i) { printf("\010 \010"); } rline_scroll = 0; @@ -232,7 +242,7 @@ static void history_next(rline_context_t * context) { void rline_insert(rline_context_t * context, const char * what) { size_t insertion_length = strlen(what); - if (context->collected + insertion_length > context->requested) { + if (context->collected + (int)insertion_length > context->requested) { insertion_length = context->requested - context->collected; } @@ -243,6 +253,8 @@ void rline_insert(rline_context_t * context, const char * what) { context->offset += insertion_length; } +static rline_callbacks_t _rline_null_callbacks = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + int rline(char * buffer, int buf_size, rline_callbacks_t * callbacks) { /* Initialize context */ rline_context_t context = { @@ -254,8 +266,13 @@ int rline(char * buffer, int buf_size, rline_callbacks_t * callbacks) { 0, 0, 0, + 0, }; + if (!callbacks) { + callbacks = &_rline_null_callbacks; + } + set_unbuffered(); printf("\033[s"); diff --git a/lib/rline_exp.c b/lib/rline_exp.c new file mode 100644 index 00000000..ea0c1e62 --- /dev/null +++ b/lib/rline_exp.c @@ -0,0 +1,1608 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * Experimental rline replacement with syntax highlighting, based + * on bim's highlighting and line editing. + * + */ +#define _XOPEN_SOURCE +#define _DEFAULT_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define ENTER_KEY '\n' +#define BACKSPACE_KEY 0x08 +#define DELETE_KEY 0x7F + +/** + * Same structures as in bim. + * A single character has: + * - A codepoint (Unicode) of up to 21 bits. + * - Flags for syntax highlighting. + * - A display width for rendering. + */ +typedef struct { + uint32_t display_width:4; + uint32_t flags:7; + uint32_t codepoint:21; +} __attribute__((packed)) char_t; + +/** + * We generally only have the one line, + * but this matches bim for compatibility reasons. + */ +typedef struct { + int available; + int actual; + int istate; + char_t text[0]; +} line_t; + +/** + * We operate on a single line of text. + * Maybe we can expand this in the future + * for continuations of edits such as when + * a quote is unclosed? + */ +static line_t * the_line = NULL; + +/** + * Line editor state + */ +static int loading = 0; +static int column = 0; +static int offset = 0; +static int width = 0; +static int buf_size_max = 0; + +/** + * Prompt strings. + * Defaults to just a "> " prompt with no right side. + * Support for right side prompts is important + * for the ToaruOS shell. + */ +static int prompt_width = 2; +static char * prompt = "> "; +static int prompt_right_width = 0; +static char * prompt_right = ""; + +int rline_exp_set_prompts(char * left, char * right, int left_width, int right_width) { + prompt = left; + prompt_right = right; + prompt_width = left_width; + prompt_right_width = right_width; + return 0; +} + +/** + * Extra shell commands to highlight as keywords. + * These are basically just copied from the + * shell's tab completion database on startup. + */ +static char ** shell_commands = {0}; +static int shell_commands_len = 0; + +int rline_exp_set_shell_commands(char ** cmds, int len) { + shell_commands = cmds; + shell_commands_len = len; + return 0; +} + +/** + * Tab completion callback. + * Compatible with the original rline version. + */ +static rline_callback_t tab_complete_func = NULL; + +int rline_exp_set_tab_complete_func(rline_callback_t func) { + tab_complete_func = func; + return 0; +} + +static int _unget = -1; +static void _ungetc(int c) { + _unget = c; +} + +static int getch(int immediate) { + if (_unget != -1) { + int out = _unget; + _unget = -1; + return out; + } + if (immediate) { + return getc(stdin); + } + struct pollfd fds[1]; + fds[0].fd = STDIN_FILENO; + fds[0].events = POLLIN; + int ret = poll(fds,1,10); + if (ret > 0 && fds[0].revents & POLLIN) { + unsigned char buf[1]; + read(STDIN_FILENO, buf, 1); + return buf[0]; + } else { + return -1; + } +} + +/** + * Convert from Unicode string to utf-8. + */ +static int to_eight(uint32_t codepoint, char * out) { + memset(out, 0x00, 7); + + if (codepoint < 0x0080) { + out[0] = (char)codepoint; + } else if (codepoint < 0x0800) { + out[0] = 0xC0 | (codepoint >> 6); + out[1] = 0x80 | (codepoint & 0x3F); + } else if (codepoint < 0x10000) { + out[0] = 0xE0 | (codepoint >> 12); + out[1] = 0x80 | ((codepoint >> 6) & 0x3F); + out[2] = 0x80 | (codepoint & 0x3F); + } else if (codepoint < 0x200000) { + out[0] = 0xF0 | (codepoint >> 18); + out[1] = 0x80 | ((codepoint >> 12) & 0x3F); + out[2] = 0x80 | ((codepoint >> 6) & 0x3F); + out[3] = 0x80 | ((codepoint) & 0x3F); + } else if (codepoint < 0x4000000) { + out[0] = 0xF8 | (codepoint >> 24); + out[1] = 0x80 | (codepoint >> 18); + out[2] = 0x80 | ((codepoint >> 12) & 0x3F); + out[3] = 0x80 | ((codepoint >> 6) & 0x3F); + out[4] = 0x80 | ((codepoint) & 0x3F); + } else { + out[0] = 0xF8 | (codepoint >> 30); + out[1] = 0x80 | ((codepoint >> 24) & 0x3F); + out[2] = 0x80 | ((codepoint >> 18) & 0x3F); + out[3] = 0x80 | ((codepoint >> 12) & 0x3F); + out[4] = 0x80 | ((codepoint >> 6) & 0x3F); + out[5] = 0x80 | ((codepoint) & 0x3F); + } + + return strlen(out); +} + +/** + * Obtain codepoint display width. + * + * This is copied from bim. Supports a few useful + * things like rendering escapes as codepoints. + */ +static int codepoint_width(wchar_t codepoint) { + if (codepoint == '\t') { + return 1; /* Recalculate later */ + } + if (codepoint < 32) { + /* We render these as ^@ */ + return 2; + } + if (codepoint == 0x7F) { + /* Renders as ^? */ + return 2; + } + if (codepoint > 0x7f && codepoint < 0xa0) { + /* Upper control bytes */ + return 4; + } + if (codepoint == 0xa0) { + /* Non-breaking space _ */ + return 1; + } + /* Skip wcwidth for anything under 256 */ + if (codepoint > 256) { + /* Higher codepoints may be wider (eg. Japanese) */ + int out = wcwidth(codepoint); + if (out >= 1) return out; + /* Invalid character, render as [U+ABCD] or [U+ABCDEF] */ + return (codepoint < 0x10000) ? 8 : 10; + } + return 1; +} + +void recalculate_tabs(line_t * line) { + int j = 0; + for (int i = 0; i < line->actual; ++i) { + if (line->text[i].codepoint == '\t') { + line->text[i].display_width = 4 - (j % 4); + } + j += line->text[i].display_width; + } +} + + +/** + * Color themes have also been copied from bim. + * + * Slimmed down to only the ones we use for syntax + * highlighting; the UI colors have been removed. + */ +static const char * COLOR_FG = "@9"; +static const char * COLOR_BG = "@9"; +static const char * COLOR_ALT_FG = "@5"; +static const char * COLOR_ALT_BG = "@9"; +static const char * COLOR_KEYWORD = "@4"; +static const char * COLOR_STRING = "@2"; +static const char * COLOR_COMMENT = "@5"; +static const char * COLOR_TYPE = "@3"; +static const char * COLOR_PRAGMA = "@1"; +static const char * COLOR_NUMERAL = "@1"; +static const char * COLOR_RED = "@1"; +static const char * COLOR_GREEN = "@2"; + +/** + * Themes are selected from the $RLINE_THEME + * environment variable. + */ +static void rline_exp_load_colorscheme_default(void) { + COLOR_FG = "@9"; + COLOR_BG = "@9"; + COLOR_ALT_FG = "@10"; + COLOR_ALT_BG = "@9"; + COLOR_KEYWORD = "@14"; + COLOR_STRING = "@2"; + COLOR_COMMENT = "@10"; + COLOR_TYPE = "@3"; + COLOR_PRAGMA = "@1"; + COLOR_NUMERAL = "@1"; + COLOR_RED = "@1"; + COLOR_GREEN = "@2"; +} + +static void rline_exp_load_colorscheme_sunsmoke(void) { + COLOR_FG = "2;230;230;230"; + COLOR_BG = "@9"; + COLOR_ALT_FG = "2;122;122;122"; + COLOR_ALT_BG = "2;46;43;46"; + COLOR_KEYWORD = "2;51;162;230"; + COLOR_STRING = "2;72;176;72"; + COLOR_COMMENT = "2;158;153;129;3"; + COLOR_TYPE = "2;230;206;110"; + COLOR_PRAGMA = "2;194;70;54"; + COLOR_NUMERAL = "2;230;43;127"; + COLOR_RED = "2;222;53;53"; + COLOR_GREEN = "2;55;167;0"; +} +/** + * Syntax highlighting flags. + */ +#define FLAG_NONE 0 +#define FLAG_KEYWORD 1 +#define FLAG_STRING 2 +#define FLAG_COMMENT 3 +#define FLAG_TYPE 4 +#define FLAG_PRAGMA 5 +#define FLAG_NUMERAL 6 +#define FLAG_SELECT 7 +#define FLAG_STRING2 8 +#define FLAG_DIFFPLUS 9 +#define FLAG_DIFFMINUS 10 + +#define FLAG_CONTINUES (1 << 6) + +/** + * Syntax definition for ToaruOS shell + */ +static char * syn_sh_keywords[] = { + "cd","exit","export","help","history","if", + "empty?","equals?","return","export-cmd", + "source","exec","not","while","then","else", + NULL, +}; + +static int variable_char(uint8_t c) { + if (c >= 'A' && c <= 'Z') return 1; + if (c >= 'a' && c <= 'z') return 1; + if (c >= '0' && c <= '9') return 1; + if (c == '_') return 1; + if (c == '?') return 1; + return 0; +} + +static int syn_sh_extended(line_t * line, int i, int c, int last, int * out_left) { + (void)last; + + if (c == '#' && last != '\\') { + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT; + } + + if (line->text[i].codepoint == '\'' && last != '\\') { + int last = 0; + for (int j = i+1; j < line->actual + 1; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '\'') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + if (line->text[i].codepoint == '$' && last != '\\') { + if (i < line->actual - 1 && line->text[i+1].codepoint == '{') { + int j = i + 2; + for (; j < line->actual+1; ++j) { + if (line->text[j].codepoint == '}') break; + } + *out_left = (j - i); + return FLAG_NUMERAL; + } + int j = i + 1; + for (; j < line->actual + 1; ++j) { + if (!variable_char(line->text[j].codepoint)) break; + } + *out_left = (j - i) - 1; + return FLAG_NUMERAL; + } + + if (line->text[i].codepoint == '"' && last != '\\') { + int last = 0; + for (int j = i+1; j < line->actual + 1; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '"') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + return 0; +} + +static int syn_sh_iskeywordchar(int c) { + if (isalnum(c)) return 1; + if (c == '-') return 1; + if (c == '_') return 1; + if (c == '?') return 1; + return 0; +} + +static char * syn_py_keywords[] = { + "class","def","return","del","if","else","elif", + "for","while","continue","break","assert", + "as","and","or","except","finally","from", + "global","import","in","is","lambda","with", + "nonlocal","not","pass","raise","try","yield", + NULL +}; + +static char * syn_py_types[] = { + "True","False","None", + "object","set","dict","int","str","bytes", + NULL +}; + +int syn_c_iskeywordchar(int c) { + if (isalnum(c)) return 1; + if (c == '_') return 1; + return 0; +} + +static int syn_py_extended(line_t * line, int i, int c, int last, int * out_left) { + + if (i == 0 && c == 'i') { + /* Check for import */ + char * import = "import "; + for (int j = 0; j < line->actual + 1; ++j) { + if (import[j] == '\0') { + *out_left = j - 2; + return FLAG_PRAGMA; + } + if (line->text[j].codepoint != import[j]) break; + } + } + + if (c == '#') { + *out_left = (line->actual + 1) - i; + return FLAG_COMMENT; + } + + if (c == '@') { + for (int j = i+1; j < line->actual + 1; ++j) { + if (!syn_c_iskeywordchar(line->text[j].codepoint)) { + *out_left = j - i - 1; + return FLAG_PRAGMA; + } + *out_left = (line->actual + 1) - i; + return FLAG_PRAGMA; + } + } + + if ((!last || !syn_c_iskeywordchar(last)) && isdigit(c)) { + if (c == '0' && i < line->actual - 1 && line->text[i+1].codepoint == 'x') { + int j = 2; + for (; i + j < line->actual && isxdigit(line->text[i+j].codepoint); ++j); + if (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) { + return FLAG_NONE; + } + *out_left = j - 1; + return FLAG_NUMERAL; + } else { + int j = 1; + while (i + j < line->actual && isdigit(line->text[i+j].codepoint)) { + j++; + } + if (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) { + return FLAG_NONE; + } + *out_left = j - 1; + return FLAG_NUMERAL; + } + } + + if (line->text[i].codepoint == '\'') { + if (i + 2 < line->actual && line->text[i+1].codepoint == '\'' && line->text[i+2].codepoint == '\'') { + /* Begin multiline */ + for (int j = i + 3; j < line->actual - 2; ++j) { + if (line->text[j].codepoint == '\'' && + line->text[j+1].codepoint == '\'' && + line->text[j+2].codepoint == '\'') { + *out_left = (j+2) - i; + return FLAG_STRING; + } + } + return FLAG_STRING | FLAG_CONTINUES; + } + + int last = 0; + for (int j = i+1; j < line->actual; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '\'') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + if (line->text[i].codepoint == '"') { + if (i + 2 < line->actual && line->text[i+1].codepoint == '"' && line->text[i+2].codepoint == '"') { + /* Begin multiline */ + for (int j = i + 3; j < line->actual - 2; ++j) { + if (line->text[j].codepoint == '"' && + line->text[j+1].codepoint == '"' && + line->text[j+2].codepoint == '"') { + *out_left = (j+2) - i; + return FLAG_STRING; + } + } + return FLAG_STRING2 | FLAG_CONTINUES; + } + + int last = 0; + for (int j = i+1; j < line->actual; ++j) { + int c = line->text[j].codepoint; + if (last != '\\' && c == '"') { + *out_left = j - i; + return FLAG_STRING; + } + if (last == '\\' && c == '\\') { + last = 0; + } + last = c; + } + *out_left = (line->actual + 1) - i; /* unterminated string */ + return FLAG_STRING; + } + + return 0; +} + +static int syn_py_finish(line_t * line, int * left, int state) { + /* TODO support multiline quotes */ + if (state == (FLAG_STRING | FLAG_CONTINUES)) { + for (int j = 0; j < line->actual - 2; ++j) { + if (line->text[j].codepoint == '\'' && + line->text[j+1].codepoint == '\'' && + line->text[j+2].codepoint == '\'') { + *left = (j+3); + return FLAG_STRING; + } + } + return FLAG_STRING | FLAG_CONTINUES; + } + if (state == (FLAG_STRING2 | FLAG_CONTINUES)) { + for (int j = 0; j < line->actual - 2; ++j) { + if (line->text[j].codepoint == '"' && + line->text[j+1].codepoint == '"' && + line->text[j+2].codepoint == '"') { + *left = (j+3); + return FLAG_STRING2; + } + } + return FLAG_STRING2 | FLAG_CONTINUES; + } + return 0; +} + +/** + * Convert syntax hilighting flag to color code + */ +static const char * flag_to_color(int _flag) { + int flag = _flag & 0x3F; + switch (flag) { + case FLAG_KEYWORD: + return COLOR_KEYWORD; + case FLAG_STRING: + case FLAG_STRING2: /* allows python to differentiate " and ' */ + return COLOR_STRING; + case FLAG_COMMENT: + return COLOR_COMMENT; + case FLAG_TYPE: + return COLOR_TYPE; + case FLAG_NUMERAL: + return COLOR_NUMERAL; + case FLAG_PRAGMA: + return COLOR_PRAGMA; + case FLAG_DIFFPLUS: + return COLOR_GREEN; + case FLAG_DIFFMINUS: + return COLOR_RED; + case FLAG_SELECT: + return COLOR_FG; + default: + return COLOR_FG; + } +} + +static struct syntax_definition { + char * name; + char ** keywords; + char ** types; + int (*extended)(line_t *, int, int, int, int *); + int (*iskwchar)(int); + int (*finishml)(line_t *, int *, int); /* TODO: How do we use this here? */ +} syntaxes[] = { + {"python",syn_py_keywords,syn_py_types,syn_py_extended,syn_c_iskeywordchar,syn_py_finish}, + {"esh",syn_sh_keywords,NULL,syn_sh_extended,syn_sh_iskeywordchar,NULL}, + {NULL} +}; + +static struct syntax_definition * syntax; + +int rline_exp_set_syntax(char * name) { + for (struct syntax_definition * s = syntaxes; s->name; ++s) { + if (!strcmp(name,s->name)) { + syntax = s; + return 0; + } + } + return 1; +} + +/** + * Compare a line against a list of keywords + */ +static int check_line(line_t * line, int c, char * str, int last) { + if (syntax->iskwchar(last)) return 0; + for (int i = c; i < line->actual; ++i, ++str) { + if (*str == '\0' && !syntax->iskwchar(line->text[i].codepoint)) return 1; + if (line->text[i].codepoint == *str) continue; + return 0; + } + if (*str == '\0') return 1; + return 0; +} + +/** + * Syntax highlighting + * Slimmed down from the bim implementation a bit, + * but generally compatible with the same definitions. + * + * Type highlighting has been removed as the sh highlighter + * didn't use it. This should be made pluggable again, and + * the bim syntax highlighters should probably be broken + * out into dynamically-loaded libraries? + */ +static void recalculate_syntax(line_t * line) { + + if (!syntax) return; + + /* Start from the line's stored in initial state */ + int state = line->istate; + int left = 0; + int last = 0; + + for (int i = 0; i < line->actual; last = line->text[i++].codepoint) { + if (!left) state = 0; + + if (state) { + /* Currently hilighting, have `left` characters remaining with this state */ + left--; + line->text[i].flags = state; + + if (!left) { + /* Done hilighting this state, go back to parsing on next character */ + state = 0; + } + + /* If we are hilighting something, don't parse */ + continue; + } + + int c = line->text[i].codepoint; + line->text[i].flags = FLAG_NONE; + + /* Language-specific syntax hilighting */ + int s = syntax->extended(line,i,c,last,&left); + if (s) { + state = s; + goto _continue; + } + + /* Keywords */ + if (syntax->keywords) { + for (char ** kw = syntax->keywords; *kw; kw++) { + int c = check_line(line, i, *kw, last); + if (c == 1) { + left = strlen(*kw)-1; + state = FLAG_KEYWORD; + goto _continue; + } + } + } + + for (int s = 0; s < shell_commands_len; ++s) { + int c = check_line(line, i, shell_commands[s], last); + if (c == 1) { + left = strlen(shell_commands[s])-1; + state = FLAG_KEYWORD; + goto _continue; + } + } + + if (syntax->types) { + for (char ** kw = syntax->types; *kw; kw++) { + int c = check_line(line, i, *kw, last); + if (c == 1) { + left = strlen(*kw)-1; + state = FLAG_TYPE; + goto _continue; + } + } + } + +_continue: + line->text[i].flags = state; + } + + state = 0; +} + +/** + * Set colors + */ +static void set_colors(const char * fg, const char * bg) { + printf("\033[22;23;"); + if (*bg == '@') { + int _bg = atoi(bg+1); + if (_bg < 10) { + printf("4%d;", _bg); + } else { + printf("10%d;", _bg-10); + } + } else { + printf("48;%s;", bg); + } + if (*fg == '@') { + int _fg = atoi(fg+1); + if (_fg < 10) { + printf("3%dm", _fg); + } else { + printf("9%dm", _fg-10); + } + } else { + printf("38;%sm", fg); + } + fflush(stdout); +} + +/** + * Set just the foreground color + * + * (See set_colors above) + */ +static void set_fg_color(const char * fg) { + printf("\033[22;23;"); + if (*fg == '@') { + int _fg = atoi(fg+1); + if (_fg < 10) { + printf("3%dm", _fg); + } else { + printf("9%dm", _fg-10); + } + } else { + printf("38;%sm", fg); + } + fflush(stdout); +} + +/** + * Mostly copied from bim, but with some minor + * alterations and removal of selection support. + */ +static void render_line(void) { + printf("\033[?25l"); + printf("\033[0m\r%s", prompt); + + int i = 0; /* Offset in char_t line data entries */ + int j = 0; /* Offset in terminal cells */ + + const char * last_color = NULL; + + /* Set default text colors */ + set_colors(COLOR_FG, COLOR_BG); + + /* + * When we are rendering in the middle of a wide character, + * we render -'s to fill the remaining amount of the + * charater's width + */ + int remainder = 0; + + line_t * line = the_line; + + /* For each character in the line ... */ + while (i < line->actual) { + + /* If there is remaining text... */ + if (remainder) { + + /* If we should be drawing by now... */ + if (j >= offset) { + /* Fill remainder with -'s */ + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("-"); + set_colors(COLOR_FG, COLOR_BG); + } + + /* One less remaining width cell to fill */ + remainder--; + + /* Terminal offset moves forward */ + j++; + + /* + * If this was the last remaining character, move to + * the next codepoint in the line + */ + if (remainder == 0) { + i++; + } + + continue; + } + + /* Get the next character to draw */ + char_t c = line->text[i]; + + /* If we should be drawing by now... */ + if (j >= offset) { + + /* If this character is going to fall off the edge of the screen... */ + if (j - offset + c.display_width >= width - prompt_width) { + /* We draw this with special colors so it isn't ambiguous */ + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + + /* If it's wide, draw ---> as needed */ + while (j - offset < width - prompt_width - 1) { + printf("-"); + j++; + } + + /* End the line with a > to show it overflows */ + printf(">"); + set_colors(COLOR_FG, COLOR_BG); + j++; + break; + } + + /* Syntax hilighting */ + const char * color = flag_to_color(c.flags); + if (!last_color || strcmp(color, last_color)) { + set_fg_color(color); + last_color = color; + } + + /* Render special characters */ + if (c.codepoint == '\t') { + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("»"); + for (int i = 1; i < c.display_width; ++i) { + printf("·"); + } + set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint < 32) { + /* Codepoints under 32 to get converted to ^@ escapes */ + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("^%c", '@' + c.codepoint); + set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint == 0x7f) { + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("^?"); + set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint > 0x7f && c.codepoint < 0xa0) { + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("<%2x>", c.codepoint); + set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint == 0xa0) { + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("_"); + set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.display_width == 8) { + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("[U+%04x]", c.codepoint); + set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.display_width == 10) { + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("[U+%06x]", c.codepoint); + set_colors(last_color ? last_color : COLOR_FG, COLOR_BG); + } else if (c.codepoint == ' ' && i == line->actual - 1) { + /* Special case: space at end of line */ + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("·"); + set_colors(COLOR_FG, COLOR_BG); + } else { + /* Normal characters get output */ + char tmp[7]; /* Max six bytes, use 7 to ensure last is always nil */ + to_eight(c.codepoint, tmp); + printf("%s", tmp); + } + + /* Advance the terminal cell offset by the render width of this character */ + j += c.display_width; + + /* Advance to the next character */ + i++; + } else if (c.display_width > 1) { + /* + * If this is a wide character but we aren't ready to render yet, + * we may need to draw some filler text for the remainder of its + * width to ensure we don't jump around when horizontally scrolling + * past wide characters. + */ + remainder = c.display_width - 1; + j++; + } else { + /* Regular character, not ready to draw, advance without doing anything */ + j++; + i++; + } + } + + /* Fill to end right hand side */ + for (; j < width + offset - prompt_width; ++j) { + printf(" "); + } + + /* Print right hand side */ + printf("\033[0m%s", prompt_right); +} + +/** + * Create a line_t + */ +static line_t * line_create(void) { + line_t * line = malloc(sizeof(line_t) + sizeof(char_t) * 32); + line->available = 32; + line->actual = 0; + line->istate = 0; + return line; +} + +/** + * Insert a character into a line + */ +static line_t * line_insert(line_t * line, char_t c, int offset) { + + /* If there is not enough space... */ + if (line->actual == line->available) { + /* Expand the line buffer */ + line->available *= 2; + line = realloc(line, sizeof(line_t) + sizeof(char_t) * line->available); + } + + /* If this was not the last character, then shift remaining characters forward. */ + if (offset < line->actual) { + memmove(&line->text[offset+1], &line->text[offset], sizeof(char_t) * (line->actual - offset)); + } + + /* Insert the new character */ + line->text[offset] = c; + + /* There is one new character in the line */ + line->actual += 1; + + if (!loading) { + recalculate_tabs(line); + recalculate_syntax(line); + } + + return line; +} + +/** + * Update terminal size + * + * We don't listen for sigwinch for various reasons... + */ +static void get_size(void) { + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + width = w.ws_col - prompt_right_width; +} + +/** + * Place the cursor within the line + */ +static void place_cursor_actual(void) { + int x = prompt_width + 1 - offset; + for (int i = 0; i < column; ++i) { + char_t * c = &the_line->text[i]; + x += c->display_width; + } + + if (x > width - 1) { + /* Adjust the offset appropriately to scroll horizontally */ + int diff = x - (width - 1); + offset += diff; + x -= diff; + render_line(); + } + + /* Same for scrolling horizontally to the left */ + if (x < prompt_width + 1) { + int diff = (prompt_width + 1) - x; + offset -= diff; + x += diff; + render_line(); + } + + printf("\033[?25h\033[%dG", x); + fflush(stdout); +} + +/** + * Delete a character + */ +static void line_delete(line_t * line, int offset) { + + /* Can't delete character before start of line. */ + if (offset == 0) return; + + /* If this isn't the last character, we need to move all subsequent characters backwards */ + if (offset < line->actual) { + memmove(&line->text[offset-1], &line->text[offset], sizeof(char_t) * (line->actual - offset)); + } + + /* The line is one character shorter */ + line->actual -= 1; + + if (!loading) { + recalculate_tabs(line); + recalculate_syntax(line); + } +} + +/** + * Backspace from the cursor position + */ +static void delete_at_cursor(void) { + if (column > 0) { + line_delete(the_line, column); + column--; + if (offset > 0) offset--; + } +} + +/** + * Delete whole word + */ +static void delete_word(void) { + if (!the_line->actual) return; + if (!column) return; + + do { + if (column > 0) { + line_delete(the_line, column); + column--; + if (offset > 0) offset--; + } + } while (column && the_line->text[column-1].codepoint != ' '); +} + +/** + * Insert at cursor position + */ +static void insert_char(uint32_t c) { + char_t _c; + _c.codepoint = c; + _c.flags = 0; + _c.display_width = codepoint_width(c); + + the_line = line_insert(the_line, _c, column); + + column++; +} + +/** + * Move cursor left + */ +static void cursor_left(void) { + if (column > 0) column--; + place_cursor_actual(); +} + +/** + * Move cursor right + */ +static void cursor_right(void) { + if (column < the_line->actual) column++; + place_cursor_actual(); +} + +/** + * Move cursor one whole word left + */ +static void word_left(void) { + if (column == 0) return; + column--; + while (column && the_line->text[column].codepoint == ' ') { + column--; + } + while (column > 0) { + if (the_line->text[column-1].codepoint == ' ') break; + column--; + } + place_cursor_actual(); +} + +/** + * Move cursor one whole word right + */ +static void word_right(void) { + while (column < the_line->actual && the_line->text[column].codepoint == ' ') { + column++; + } + while (column < the_line->actual) { + column++; + if (the_line->text[column].codepoint == ' ') break; + } + place_cursor_actual(); +} + +/** + * Move cursor to start of line + */ +static void cursor_home(void) { + column = 0; + place_cursor_actual(); +} + +/* + * Move cursor to end of line + */ +static void cursor_end(void) { + column = the_line->actual; + place_cursor_actual(); +} + +/** + * Temporary buffer for holding utf-8 data + */ +static char temp_buffer[1024]; + +/** + * Cycle to previous history entry + */ +static void history_previous(void) { + if (rline_scroll == 0) { + /* Convert to temporaary buffer */ + unsigned int off = 0; + memset(temp_buffer, 0, sizeof(temp_buffer)); + for (int j = 0; j < the_line->actual; j++) { + char_t c = the_line->text[j]; + off += to_eight(c.codepoint, &temp_buffer[off]); + } + } + + if (rline_scroll < rline_history_count) { + rline_scroll++; + + /* Copy in from history */ + the_line->actual = 0; + column = 0; + loading = 1; + char * buf = rline_history_prev(rline_scroll); + uint32_t istate = 0, c = 0; + for (unsigned int i = 0; i < strlen(buf); ++i) { + if (!decode(&istate, &c, buf[i])) { + insert_char(c); + } + } + loading = 0; + } + /* Set cursor at end */ + column = the_line->actual; + offset = 0; + recalculate_tabs(the_line); + recalculate_syntax(the_line); + render_line(); + place_cursor_actual(); +} + +/** + * Cycle to next history entry + */ +static void history_next(void) { + if (rline_scroll > 1) { + rline_scroll--; + + /* Copy in from history */ + the_line->actual = 0; + column = 0; + loading = 1; + char * buf = rline_history_prev(rline_scroll); + uint32_t istate = 0, c = 0; + for (unsigned int i = 0; i < strlen(buf); ++i) { + if (!decode(&istate, &c, buf[i])) { + insert_char(c); + } + } + loading = 0; + } else if (rline_scroll == 1) { + /* Copy in from temp */ + rline_scroll = 0; + + the_line->actual = 0; + column = 0; + loading = 1; + char * buf = temp_buffer; + uint32_t istate = 0, c = 0; + for (unsigned int i = 0; i < strlen(buf); ++i) { + if (!decode(&istate, &c, buf[i])) { + insert_char(c); + } + } + loading = 0; + } + /* Set cursor at end */ + column = the_line->actual; + offset = 0; + recalculate_tabs(the_line); + recalculate_syntax(the_line); + render_line(); + place_cursor_actual(); +} + +/** + * Handle escape sequences (arrow keys, etc.) + */ +static int handle_escape(int * this_buf, int * timeout, int c) { + if (*timeout >= 1 && this_buf[*timeout-1] == '\033' && c == '\033') { + this_buf[*timeout] = c; + (*timeout)++; + return 1; + } + if (*timeout >= 1 && this_buf[*timeout-1] == '\033' && c != '[') { + *timeout = 0; + _ungetc(c); + return 1; + } + if (*timeout >= 1 && this_buf[*timeout-1] == '\033' && c == '[') { + *timeout = 1; + this_buf[*timeout] = c; + (*timeout)++; + return 0; + } + if (*timeout >= 2 && this_buf[0] == '\033' && this_buf[1] == '[' && + (isdigit(c) || c == ';')) { + this_buf[*timeout] = c; + (*timeout)++; + return 0; + } + if (*timeout >= 2 && this_buf[0] == '\033' && this_buf[1] == '[') { + switch (c) { + case 'A': // up + history_previous(); + break; + case 'B': // down + history_next(); + break; + case 'C': // right + if (this_buf[*timeout-1] == '5') { + word_right(); + } else { + cursor_right(); + } + break; + case 'D': // left + if (this_buf[*timeout-1] == '5') { + word_left(); + } else { + cursor_left(); + } + break; + case 'H': // home + cursor_home(); + break; + case 'F': // end + cursor_end(); + break; + case '~': + switch (this_buf[*timeout-1]) { + case '1': + cursor_home(); + break; + case '3': + /* Delete forward */ + if (column < the_line->actual) { + line_delete(the_line, column+1); + if (offset > 0) offset--; + } + break; + case '4': + cursor_end(); + break; + } + break; + default: + break; + } + *timeout = 0; + return 0; + } + + *timeout = 0; + return 0; +} + +static unsigned int _INTR, _EOF; +static struct termios old; +static void get_initial_termios(void) { + tcgetattr(STDOUT_FILENO, &old); + _INTR = old.c_cc[VINTR]; + _EOF = old.c_cc[VEOF]; +} + +static void set_unbuffered(void) { + struct termios new = old; + new.c_lflag &= (~ICANON & ~ECHO); + new.c_cc[VINTR] = 0; + tcsetattr(STDOUT_FILENO, TCSAFLUSH, &new); +} + +static void set_buffered(void) { + tcsetattr(STDOUT_FILENO, TCSAFLUSH, &old); +} + +static int tabbed; + +static void dummy_redraw(rline_context_t * context) { + /* Do nothing */ +} + +/** + * Juggle our buffer with an rline context so we can + * call original rline functions such as a tab-completion callback + * or reverse search. + */ +static void call_rline_func(rline_callback_t func, rline_context_t * context) { + /* Unicode parser state */ + uint32_t istate = 0; + uint32_t c; + + /* Don't let rline draw things */ + context->quiet = 1; + + /* Allocate a temporary buffer */ + context->buffer = malloc(buf_size_max); + memset(context->buffer,0,buf_size_max); + + /* Convert current data to utf-8 */ + unsigned int off = 0; + for (int j = 0; j < the_line->actual; j++) { + if (j == column) { + /* Track cursor position */ + context->offset = off; + } + char_t c = the_line->text[j]; + off += to_eight(c.codepoint, &context->buffer[off]); + } + + /* If the cursor was at the end, the loop above didn't catch it */ + if (column == the_line->actual) context->offset = off; + + /* + * Did we just press tab before this? This is actually managed + * by the tab-completion function. + */ + context->tabbed = tabbed; + + /* Empty callbacks */ + rline_callbacks_t tmp = {0}; + /* + * Because some clients expect this to be set... + * (we don't need it, we'll redraw ourselves later) + */ + tmp.redraw_prompt = dummy_redraw; + + /* Setup context */ + context->callbacks = &tmp; + context->collected = off; + context->buffer[off] = '\0'; + context->requested = 1024; + + /* Reset colors (for tab completion candidates, etc. */ + printf("\033[0m"); + + /* Call the function */ + func(context); + + /* Now convert back */ + loading = 1; + int final_column = 0; + the_line->actual = 0; + column = 0; + istate = 0; + for (int i = 0; i < context->collected; ++i) { + if (i == context->offset) { + final_column = column; + } + if (!decode(&istate, &c, context->buffer[i])) { + insert_char(c); + } + } + + free(context->buffer); + + /* Position cursor */ + if (context->offset == context->collected) { + column = the_line->actual; + } else { + column = final_column; + } + tabbed = context->tabbed; + loading = 0; + + /* Recalculate + redraw */ + recalculate_tabs(the_line); + recalculate_syntax(the_line); + render_line(); + place_cursor_actual(); +} + +/** + * Perform actual interactive line editing. + * + * This is mostly a reimplementation of bim's + * INSERT mode, but with some cleanups and fixes + * to work on a single line and to add some new + * key bindings we don't have in bim. + */ +static int read_line(void) { + int cin; + uint32_t c; + int timeout = 0; + int this_buf[20]; + uint32_t istate = 0; + int immediate = 1; + + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + fprintf(stdout, "◄\033[0m"); /* TODO: This could be retrieved from an envvar */ + for (int i = 0; i < width + prompt_right_width - 1; ++i) { + fprintf(stdout, " "); + } + render_line(); + place_cursor_actual(); + + while ((cin = getch(immediate))) { + if (cin == -1) { + immediate = 1; + render_line(); + place_cursor_actual(); + continue; + } + get_size(); + if (!decode(&istate, &c, cin)) { + if (timeout == 0) { + if (c != '\t') tabbed = 0; + if (_INTR && c == _INTR) { + set_colors(COLOR_ALT_FG, COLOR_ALT_BG); + printf("^%c", (int)('@' + c)); + printf("\033[0m"); + loading = 1; + the_line->actual = 0; + column = 0; + insert_char('\n'); + immediate = 0; + raise(SIGINT); + return 1; + } + if (_EOF && c == _EOF) { + if (column == 0 && the_line->actual == 0) { + for (char *_c = rline_exit_string; *_c; ++_c) { + insert_char(*_c); + } + render_line(); + place_cursor_actual(); + return 1; + } else { /* Otherwise act like delete */ + if (column < the_line->actual) { + line_delete(the_line, column+1); + if (offset > 0) offset--; + immediate = 0; + } + continue; + } + } + switch (c) { + case '\033': + if (timeout == 0) { + this_buf[timeout] = c; + timeout++; + } + break; + case DELETE_KEY: + case BACKSPACE_KEY: + delete_at_cursor(); + immediate = 0; + break; + case ENTER_KEY: + /* Finished */ + loading = 1; + column = the_line->actual; + insert_char('\n'); + immediate = 0; + return 1; + case 22: /* ^V */ + /* Don't bother with unicode, just take the next byte */ + place_cursor_actual(); + printf("^\b"); + insert_char(getc(stdin)); + immediate = 0; + break; + case 23: /* ^W */ + delete_word(); + immediate = 0; + break; + case 12: /* ^L - Repaint the whole screen */ + printf("\033[2J\033[H"); + render_line(); + place_cursor_actual(); + break; + case 11: /* ^K - Clear to end */ + the_line->actual = column; + immediate = 0; + break; + case 21: /* ^U - Kill to beginning */ + while (column) { + delete_at_cursor(); + } + immediate = 0; + break; + case '\t': + if (tab_complete_func) { + /* Tab complete */ + rline_context_t context = {0}; + call_rline_func(tab_complete_func, &context); + immediate = 0; + } else { + /* Insert tab character */ + insert_char('\t'); + immediate = 0; + } + break; + case 18: + { + rline_context_t context = {0}; + call_rline_func(rline_reverse_search, &context); + if (!context.cancel) { + return 1; + } + immediate = 0; + } + break; + default: + insert_char(c); + immediate = 0; + break; + } + } else { + if (handle_escape(this_buf,&timeout,c)) { + continue; + } + immediate = 0; + } + } else if (istate == UTF8_REJECT) { + istate = 0; + } + } + return 0; +} + +/** + * Read a line of text with interactive editing. + */ +int rline_experimental(char * buffer, int buf_size) { + get_initial_termios(); + set_unbuffered(); + get_size(); + + column = 0; + offset = 0; + buf_size_max = buf_size; + + char * theme = getenv("RLINE_THEME"); + if (theme && !strcmp(theme,"sunsmoke")) { /* TODO bring back theme tables */ + rline_exp_load_colorscheme_sunsmoke(); + } else { + rline_exp_load_colorscheme_default(); + } + + the_line = line_create(); + loading = 0; + read_line(); + printf("\033[0m\n"); + + unsigned int off = 0; + for (int j = 0; j < the_line->actual; j++) { + char_t c = the_line->text[j]; + off += to_eight(c.codepoint, &buffer[off]); + } + + free(the_line); + + set_buffered(); + + return strlen(buffer); +} + +void * rline_exp_for_python(void * _stdin, void * _stdout, char * prompt) { + + rline_exp_set_prompts(prompt, "", strlen(prompt), 0); + + char * buf = malloc(1024); + memset(buf, 0, 1024); + + rline_exp_set_syntax("python"); + rline_exit_string = ""; + rline_experimental(buf, 1024); + rline_history_insert(strdup(buf)); + rline_scroll = 0; + + return buf; +} diff --git a/lib/sdf.c b/lib/sdf.c new file mode 100644 index 00000000..c5af6e1c --- /dev/null +++ b/lib/sdf.c @@ -0,0 +1,237 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * Signed Distance Field text rasterization library + */ + +#include +#include +#include + +#include +#include +#include +#include + +#define BASE_WIDTH 50 +#define BASE_HEIGHT 50 + +static sprite_t _font_data_thin; +static sprite_t _font_data_bold; +static sprite_t _font_data_mono; +static sprite_t _font_data_mono_bold; +static sprite_t _font_data_mono_oblique; +static sprite_t _font_data_mono_bold_oblique; + +static hashmap_t * _font_cache; + +static volatile int _sdf_lock = 0; +static double gamma = 1.7; + +struct CharData{ + char code; + size_t width_bold; + size_t width_thin; + size_t width_mono; +} _char_data[256]; + +static int loaded = 0; + +static int offset(int ch) { + /* Calculate offset into table above */ + return ch; +} + +static char * _font_data = NULL; +static size_t _font_data_size = 0; + +static void load_font(sprite_t * sprite, int font) { + uint32_t * _font_data_i = (uint32_t*)_font_data; + + sprite->width = _font_data_i[font * 3 + 1]; + sprite->height = _font_data_i[font * 3 + 2]; + + int offset = _font_data_i[font * 3 + 3]; + sprite->bitmap = (uint32_t *)&_font_data[offset]; + sprite->alpha = 0; + sprite->masks = NULL; + sprite->blank = 0; +} + +__attribute__((constructor)) +static void _init_sdf(void) { + /* Load the font. */ + _font_cache = hashmap_create_int(10); + { + char tmp[100]; + char * display = getenv("DISPLAY"); + if (!display) display = "compositor"; + sprintf(tmp, "sys.%s.fonts", display); + _font_data = (char *)syscall_shm_obtain(tmp, &_font_data_size); + } + + if (!_font_data_size) return; + + load_font(&_font_data_thin, SDF_FONT_THIN); + load_font(&_font_data_bold, SDF_FONT_BOLD); + load_font(&_font_data_mono, SDF_FONT_MONO); + load_font(&_font_data_mono_bold, SDF_FONT_MONO_BOLD); + load_font(&_font_data_mono_oblique, SDF_FONT_MONO_OBLIQUE); + load_font(&_font_data_mono_bold_oblique, SDF_FONT_MONO_BOLD_OBLIQUE); + + FILE * fi = fopen("/etc/sdf.conf", "r"); + char tmp[1024]; + char * s = tmp; + for (int i = 0; i < 256; ++i) { + _char_data[i].code = i; + _char_data[i].width_bold = 25; + _char_data[i].width_thin = 20; + _char_data[i].width_mono = 25; + } + while ((s = fgets(tmp, 1024, fi))) { + if (strlen(s) < 1) continue; + int i = offset(*s); + s++; s++; + char t = *s; + s++; s++; + int o = atoi(s); + if (t == 'b') { + _char_data[i].width_bold = o; + } else if (t == 't') { + _char_data[i].width_thin = o; + } else if (t == 'm') { + _char_data[i].width_mono = o; + } + } + fclose(fi); + loaded = 1; +} + +static sprite_t * _select_font(int font) { + switch (font) { + case SDF_FONT_BOLD: + return &_font_data_bold; + case SDF_FONT_MONO: + return &_font_data_mono; + case SDF_FONT_MONO_BOLD: + return &_font_data_mono_bold; + case SDF_FONT_MONO_OBLIQUE: + return &_font_data_mono_oblique; + case SDF_FONT_MONO_BOLD_OBLIQUE: + return &_font_data_mono_bold_oblique; + case SDF_FONT_THIN: + default: + return &_font_data_thin; + } +} + +static int _select_width(char ch, int font) { + switch (font) { + case SDF_FONT_BOLD: + return _char_data[(int)ch].width_bold; + case SDF_FONT_MONO: + case SDF_FONT_MONO_BOLD: + case SDF_FONT_MONO_OBLIQUE: + case SDF_FONT_MONO_BOLD_OBLIQUE: + return _char_data[(int)ch].width_mono; + case SDF_FONT_THIN: + default: + return _char_data[(int)ch].width_thin; + } +} + +static int draw_sdf_character(gfx_context_t * ctx, int32_t x, int32_t y, int ch, int size, uint32_t color, sprite_t * tmp, int font, sprite_t * _font_data) { + if (ch < 0 || ch > 255) return 0; + + double scale = (double)size / 50.0; + int width = _select_width(ch, font) * scale; + int fx = ((BASE_WIDTH * ch) % _font_data->width) * scale; + int fy = (((BASE_WIDTH * ch) / _font_data->width) * BASE_HEIGHT) * scale; + + int height = BASE_HEIGHT * ((double)size / 50.0); + + + /* ignore size */ + for (int j = 0; j < height; ++j) { + if (y + j < 0) continue; + if (y + j >= ctx->height) continue; + if (fy+j >= tmp->height) continue; + for (int i = 0; i < size; ++i) { + /* TODO needs to do bilinear filter */ + if (fx+i >= tmp->width) continue; + if (x + i < 0) continue; + if (x + i >= ctx->width) continue; + uint32_t c = SPRITE((tmp), fx+i, fy+j); + double dist = (double)_RED(c) / 255.0; + double edge0 = 0.75 - gamma * 1.4142 / (double)size; + double edge1 = 0.75 + gamma * 1.4142 / (double)size; + double a = (dist - edge0) / (edge1 - edge0); + if (a < 0.0) a = 0.0; + if (a > 1.0) a = 1.0; + a = a * a * (3 - 2 * a); + GFX(ctx,x+i,y+j) = alpha_blend(GFX(ctx,x+i,y+j), color, rgb(_ALP(color)*a,0,0)); + } + } + + return width; + +} + +int draw_sdf_string_gamma(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font, double _gamma) { + + sprite_t * _font_data = _select_font(font); + + if (!loaded) return 0; + + double scale = (double)size / 50.0; + int scale_height = scale * _font_data->height; + + sprite_t * tmp; + spin_lock(&_sdf_lock); + if (!hashmap_has(_font_cache, (void *)(scale_height | (font << 16)))) { + tmp = create_sprite(scale * _font_data->width, scale * _font_data->height, ALPHA_OPAQUE); + gfx_context_t * t = init_graphics_sprite(tmp); + draw_sprite_scaled(t, _font_data, 0, 0, tmp->width, tmp->height); + free(t); + hashmap_set(_font_cache, (void *)(scale_height | (font << 16)), tmp); + } else { + tmp = hashmap_get(_font_cache, (void *)(scale_height | (font << 16))); + } + + int32_t out_width = 0; + gamma = _gamma; + while (*str) { + int w = draw_sdf_character(ctx,x,y,*((uint8_t *)str),size,color,tmp,font,_font_data); + out_width += w; + x += w; + str++; + } + spin_unlock(&_sdf_lock); + + return out_width; +} + + +int draw_sdf_string(gfx_context_t * ctx, int32_t x, int32_t y, const char * str, int size, uint32_t color, int font) { + return draw_sdf_string_gamma(ctx,x,y,str,size,color,font,1.7); +} + +static int char_width(char ch, int font) { + return _select_width(ch, font); +} + + +int draw_sdf_string_width(const char * str, int size, int font) { + double scale = (double)size / 50.0; + + int32_t out_width = 0; + while (*str) { + int w = char_width(*str,font) * scale; + out_width += w; + str++; + } + + return out_width; +} diff --git a/userspace/gui/terminal/lib/termemu.c b/lib/termemu.c similarity index 97% rename from userspace/gui/terminal/lib/termemu.c rename to lib/termemu.c index d3138a34..2767c946 100644 --- a/userspace/gui/terminal/lib/termemu.c +++ b/lib/termemu.c @@ -1,32 +1,36 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * Portable library for terminal emulation. */ -#include "termemu.h" - #ifdef _KERNEL_ -# include -# include -# include +# include +# include +# include static void _spin_lock(volatile int * foo) { return; } static void _spin_unlock(volatile int * foo) { return; } # define rgba(r,g,b,a) (((uint32_t)a * 0x1000000) + ((uint32_t)r * 0x10000) + ((uint32_t)g * 0x100) + ((uint32_t)b * 0x1)) # define rgb(r,g,b) rgba(r,g,b,0xFF) +# define atof(i) (0.0f) +#include #else #include + #include -#include -#include "lib/spinlock.h" -#include "lib/graphics.h" +#include +#include + +#include +#include + +#include #define _spin_lock spin_lock #define _spin_unlock spin_unlock #endif - #define MAX_ARGS 1024 static wchar_t box_chars[] = L"▒␉␌␍␊°±␤␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥"; @@ -174,13 +178,6 @@ static void _ansi_put(term_state_t * s, char c) { case 1: callbacks->redraw_cursor(); break; -#ifndef _KERNEL_ - case 1555: - if (argc > 1) { - callbacks->set_font_size(atof(argv[1])); - } - break; -#endif default: break; } @@ -314,8 +311,7 @@ static void _ansi_put(term_state_t * s, char c) { case ANSI_SHOW: if (argc > 0) { if (!strcmp(argv[0], "?1049")) { - callbacks->cls(2); - callbacks->set_csr(0,0); + if (callbacks->switch_buffer) callbacks->switch_buffer(1); } else if (!strcmp(argv[0], "?1000")) { s->mouse_on = 1; } else if (!strcmp(argv[0], "?1002")) { @@ -328,7 +324,7 @@ static void _ansi_put(term_state_t * s, char c) { case ANSI_HIDE: if (argc > 0) { if (!strcmp(argv[0], "?1049")) { - /* TODO: Unimplemented */ + if (callbacks->switch_buffer) callbacks->switch_buffer(0); } else if (!strcmp(argv[0], "?1000")) { s->mouse_on = 0; } else if (!strcmp(argv[0], "?1002")) { diff --git a/lib/textregion.c b/lib/textregion.c new file mode 100644 index 00000000..be08db3e --- /dev/null +++ b/lib/textregion.c @@ -0,0 +1,85 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * TODO: This is a work in progress + * + * Port of the original ToaruOS Python text_region library to C. + * + * Allows for the display of rich text with multiple varied formats, + * as well as carat positioning, reflow, links, images, and so on. + */ + +#include +#include +#include + +int tr_font_get_width(struct TR_Font * font, char * string) { + return draw_sdf_string_width(string, font->size, font->typeface); +} + +int tr_font_write(struct TR_Font * font, gfx_context_t * ctx, int x, int y, char * string) { + return draw_sdf_string(ctx, x, y, string, font->size, font->color, font->typeface); +} + +void tr_textunit_set_tag_group(struct TR_TextUnit * self, list_t * tag_group) { + if (!self->tag_group) { + self->tag_group = tag_group; + list_insert(tag_group, self); + } else { + /* Already in a tag group, this is wrong */ + } +} + +void tr_textunit_set_font(struct TR_TextUnit * self, struct TR_Font * font) { + self->font = font; + self->width = tr_font_get_width(font, self->string); +} + +void tr_textunit_set_extra(struct TR_TextUnit * self, char * key, void * data) { + if (!self->extra) { + self->extra = hashmap_create(10); + } + hashmap_set(self->extra, key, data); +} + +void tr_textregion_set_alignment(struct TR_TextRegion * self, int align) { + self->align = align; +} + +void tr_textregion_set_valignment(struct TR_TextRegion * self, int align) { + self->valign = align; +} + +void tr_textregion_set_max_lines(struct TR_TextRegion * self, int max_lines) { + self->max_lines = max_lines; + tr_textregion_reflow(self); +} + +int tr_textregion_get_visible_lines(struct TR_TextRegion * self) { + return self->height / self->line_height; +} + +void tr_textregion_reflow(struct TR_TextRegion * self) { + if (self->lines) { + fprintf(stderr, "Need to clean out lines\n"); +#if 0 + list_destroy(self->lines); + list_free(self->lines); + free(self->lines); +#endif + } + +#if 0 + self->lines = list_create(); + + int current_width = 0; + list_t * current_units = list_create(); + struct TR_TextUnit * leftover = NULL; + + int i = 0; + while (i < self->text_units +#endif + +} diff --git a/lib/tree.c b/lib/tree.c new file mode 100644 index 00000000..fd29c59a --- /dev/null +++ b/lib/tree.c @@ -0,0 +1,192 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2018 K. Lange + * + * General-purpose tree implementation + */ + +#ifdef _KERNEL_ +# include +#else +# include +# include +#endif + +#include + +tree_t * tree_create(void) { + /* Create a new tree */ + tree_t * out = malloc(sizeof(tree_t)); + out->nodes = 0; + out->root = NULL; + return out; +} + +void tree_set_root(tree_t * tree, void * value) { + /* Set the root node for a new tree. */ + tree_node_t * root = tree_node_create(value); + tree->root = root; + tree->nodes = 1; +} + +void tree_node_destroy(tree_node_t * node) { + /* Free the contents of a node and its children, but not the nodes themselves */ + foreach(child, node->children) { + tree_node_destroy((tree_node_t *)child->value); + } + free(node->value); +} + +void tree_destroy(tree_t * tree) { + /* Free the contents of a tree, but not the nodes */ + if (tree->root) { + tree_node_destroy(tree->root); + } +} + +void tree_node_free(tree_node_t * node) { + /* Free a node and its children, but not their contents */ + if (!node) return; + foreach(child, node->children) { + tree_node_free(child->value); + } + free(node); +} + +void tree_free(tree_t * tree) { + /* Free all of the nodes in a tree, but not their contents */ + tree_node_free(tree->root); +} + +tree_node_t * tree_node_create(void * value) { + /* Create a new tree node pointing to the given value */ + tree_node_t * out = malloc(sizeof(tree_node_t)); + out->value = value; + out->children = list_create(); + out->parent = NULL; + return out; +} + +void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node) { + /* Insert a node as a child of parent */ + list_insert(parent->children, node); + node->parent = parent; + tree->nodes++; +} + +tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value) { + /* Insert a (fresh) node as a child of parent */ + tree_node_t * out = tree_node_create(value); + tree_node_insert_child_node(tree, parent, out); + return out; +} + +tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle) { + /* Recursive node part of tree_find_parent */ + tree_node_t * found = NULL; + foreach(child, haystack->children) { + if (child->value == needle) { + return haystack; + } + found = tree_node_find_parent((tree_node_t *)child->value, needle); + if (found) { + break; + } + } + return found; +} + +tree_node_t * tree_find_parent(tree_t * tree, tree_node_t * node) { + /* Return the parent of a node, inefficiently. */ + if (!tree->root) return NULL; + return tree_node_find_parent(tree->root, node); +} + +size_t tree_count_children(tree_node_t * node) { + /* return the number of children this node has */ + if (!node) return 0; + if (!node->children) return 0; + size_t out = node->children->length; + foreach(child, node->children) { + out += tree_count_children((tree_node_t *)child->value); + } + return out; +} + +void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node) { + /* remove a node when we know its parent; update node counts for the tree */ + tree->nodes -= tree_count_children(node) + 1; + list_delete(parent->children, list_find(parent->children, node)); + tree_node_free(node); +} + +void tree_node_remove(tree_t * tree, tree_node_t * node) { + /* remove an entire branch given its root */ + tree_node_t * parent = node->parent; + if (!parent) { + if (node == tree->root) { + tree->nodes = 0; + tree->root = NULL; + tree_node_free(node); + } + } + tree_node_parent_remove(tree, parent, node); +} + +void tree_remove(tree_t * tree, tree_node_t * node) { + /* Remove this node and move its children into its parent's list of children */ + tree_node_t * parent = node->parent; + /* This is something we just can't do. We don't know how to merge our + * children into our "parent" because then we'd have more than one root node. + * A good way to think about this is actually what this tree struct + * primarily exists for: processes. Trying to remove the root is equivalent + * to trying to kill init! Which is bad. We immediately fault on such + * a case anyway ("Tried to kill init, shutting down!"). + */ + if (!parent) return; + tree->nodes--; + list_delete(parent->children, list_find(parent->children, node)); + foreach(child, node->children) { + /* Reassign the parents */ + ((tree_node_t *)child->value)->parent = parent; + } + list_merge(parent->children, node->children); + free(node); +} + +void tree_remove_reparent_root(tree_t * tree, tree_node_t * node) { + /* Remove this node and move its children into the root children */ + tree_node_t * parent = node->parent; + if (!parent) return; + tree->nodes--; + list_delete(parent->children, list_find(parent->children, node)); + foreach(child, node->children) { + /* Reassign the parents */ + ((tree_node_t *)child->value)->parent = tree->root; + } + list_merge(tree->root->children, node->children); + free(node); +} + +void tree_break_off(tree_t * tree, tree_node_t * node) { + tree_node_t * parent = node->parent; + if (!parent) return; + list_delete(parent->children, list_find(parent->children, node)); +} + +tree_node_t * tree_node_find(tree_node_t * node, void * search, tree_comparator_t comparator) { + if (comparator(node->value,search)) { + return node; + } + tree_node_t * found; + foreach(child, node->children) { + found = tree_node_find((tree_node_t *)child->value, search, comparator); + if (found) return found; + } + return NULL; +} + +tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator) { + return tree_node_find(tree->root, value, comparator); +} diff --git a/lib/yutani.c b/lib/yutani.c new file mode 100644 index 00000000..8a107808 --- /dev/null +++ b/lib/yutani.c @@ -0,0 +1,1117 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014-2018 K. Lange + * + * Yutani Client Library + * + * Client library for the compositing window system. + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* We need the flags but don't want the library dep (maybe the flags should be here?) */ +#include + +/** + * yutani_wait_for + * + * Wait for a particular kind of message, queuing other types + * of messages for processing later. + */ +yutani_msg_t * yutani_wait_for(yutani_t * y, uint32_t type) { + do { + yutani_msg_t * out; + size_t size; + { + char tmp[MAX_PACKET_SIZE]; + size = pex_recv(y->sock, tmp); + out = malloc(size); + memcpy(out, tmp, size); + } + + if (out->type == type) { + return out; + } else { + list_insert(y->queued, out); + } + } while (1); /* XXX: (!y->abort) */ +} + +/** + * yutani_query + * + * Check if there is an available message, either in the + * internal queue or directly from the server interface. + */ +size_t yutani_query(yutani_t * y) { + if (y->queued->length > 0) return 1; + return pex_query(y->sock); +} + +/** + * _handle_internal + * + * Some messages are processed internally. They are still + * available to the client application, but some work will + * be done before they are handed off. + * + * WELCOME: Update the display_width and display_height for the connection. + * WINDOW_MOVE: Update the window location. + */ +static void _handle_internal(yutani_t * y, yutani_msg_t * out) { + switch (out->type) { + case YUTANI_MSG_WELCOME: + { + struct yutani_msg_welcome * mw = (void *)out->data; + y->display_width = mw->display_width; + y->display_height = mw->display_height; + } + break; + case YUTANI_MSG_WINDOW_MOVE: + { + struct yutani_msg_window_move * wm = (void *)out->data; + yutani_window_t * win = hashmap_get(y->windows, (void *)wm->wid); + if (win) { + win->x = wm->x; + win->y = wm->y; + } + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void *)out->data; + yutani_window_t * win = hashmap_get(y->windows, (void *)wr->wid); + if (win) { + if (wr->flags & YUTANI_RESIZE_TILED) { + win->decorator_flags |= (DECOR_FLAG_TILED); + } else { + win->decorator_flags &= ~(DECOR_FLAG_TILED); + } + } + } + default: + break; + } +} + +/** + * yutani_poll + * + * Wait for a message to be available, processing it if + * it has internal processing requirements. + */ +yutani_msg_t * yutani_poll(yutani_t * y) { + yutani_msg_t * out; + + if (y->queued->length > 0) { + node_t * node = list_dequeue(y->queued); + out = (yutani_msg_t *)node->value; + free(node); + _handle_internal(y, out); + return out; + } + + size_t size; + { + char tmp[MAX_PACKET_SIZE]; + size = pex_recv(y->sock, tmp); + out = malloc(size); + memcpy(out, tmp, size); + } + + _handle_internal(y, out); + + return out; +} + +/** + * yutani_poll_async + * + * Get the next available message, if there is one, otherwise + * return immediately. Generally should be called in a loop + * after an initial call to yutani_poll in case processing + * caused additional messages to be queued. + */ +yutani_msg_t * yutani_poll_async(yutani_t * y) { + if (yutani_query(y) > 0) { + return yutani_poll(y); + } + return NULL; +} + +void yutani_msg_buildx_hello(yutani_msg_t * msg) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_HELLO; + msg->size = sizeof(struct yutani_message); +} + + +void yutani_msg_buildx_flip(yutani_msg_t * msg, yutani_wid_t wid) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_FLIP; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_flip); + + struct yutani_msg_flip * mw = (void *)msg->data; + + mw->wid = wid; +} + + +void yutani_msg_buildx_welcome(yutani_msg_t * msg, uint32_t width, uint32_t height) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WELCOME; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_welcome); + + struct yutani_msg_welcome * mw = (void *)msg->data; + + mw->display_width = width; + mw->display_height = height; +} + + +void yutani_msg_buildx_window_new(yutani_msg_t * msg, uint32_t width, uint32_t height) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_NEW; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_new); + + struct yutani_msg_window_new * mw = (void *)msg->data; + + mw->width = width; + mw->height = height; +} + + +void yutani_msg_buildx_window_new_flags(yutani_msg_t * msg, uint32_t width, uint32_t height, uint32_t flags) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_NEW_FLAGS; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_new_flags); + + struct yutani_msg_window_new_flags * mw = (void *)msg->data; + + mw->width = width; + mw->height = height; + mw->flags = flags; +} + + +void yutani_msg_buildx_window_init(yutani_msg_t * msg, yutani_wid_t wid, uint32_t width, uint32_t height, uint32_t bufid) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_INIT; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_init); + + struct yutani_msg_window_init * mw = (void *)msg->data; + + mw->wid = wid; + mw->width = width; + mw->height = height; + mw->bufid = bufid; +} + + +void yutani_msg_buildx_window_close(yutani_msg_t * msg, yutani_wid_t wid) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_CLOSE; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_close); + + struct yutani_msg_window_close * mw = (void *)msg->data; + + mw->wid = wid; +} + + +void yutani_msg_buildx_key_event(yutani_msg_t * msg, yutani_wid_t wid, key_event_t * event, key_event_state_t * state) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_KEY_EVENT; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_key_event); + + struct yutani_msg_key_event * mw = (void *)msg->data; + + mw->wid = wid; + memcpy(&mw->event, event, sizeof(key_event_t)); + memcpy(&mw->state, state, sizeof(key_event_state_t)); +} + + +void yutani_msg_buildx_mouse_event(yutani_msg_t * msg, yutani_wid_t wid, mouse_device_packet_t * event, int32_t type) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_MOUSE_EVENT; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_mouse_event); + + struct yutani_msg_mouse_event * mw = (void *)msg->data; + + mw->wid = wid; + memcpy(&mw->event, event, sizeof(mouse_device_packet_t)); + mw->type = type; +} + + +void yutani_msg_buildx_window_move(yutani_msg_t * msg, yutani_wid_t wid, int32_t x, int32_t y) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_MOVE; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_move); + + struct yutani_msg_window_move * mw = (void *)msg->data; + + mw->wid = wid; + mw->x = x; + mw->y = y; +} + + +void yutani_msg_buildx_window_stack(yutani_msg_t * msg, yutani_wid_t wid, int z) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_STACK; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_stack); + + struct yutani_msg_window_stack * mw = (void *)msg->data; + + mw->wid = wid; + mw->z = z; +} + + +void yutani_msg_buildx_window_focus_change(yutani_msg_t * msg, yutani_wid_t wid, int focused) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_FOCUS_CHANGE; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_focus_change); + + struct yutani_msg_window_focus_change * mw = (void *)msg->data; + + mw->wid = wid; + mw->focused = focused; +} + + +void yutani_msg_buildx_window_mouse_event(yutani_msg_t * msg, yutani_wid_t wid, int32_t new_x, int32_t new_y, int32_t old_x, int32_t old_y, uint8_t buttons, uint8_t command) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_MOUSE_EVENT; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_mouse_event); + + struct yutani_msg_window_mouse_event * mw = (void *)msg->data; + + mw->wid = wid; + mw->new_x = new_x; + mw->new_y = new_y; + mw->old_x = old_x; + mw->old_y = old_y; + mw->buttons = buttons; + mw->command = command; +} + + +void yutani_msg_buildx_flip_region(yutani_msg_t * msg, yutani_wid_t wid, int32_t x, int32_t y, int32_t width, int32_t height) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_FLIP_REGION; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_flip_region); + + struct yutani_msg_flip_region * mw = (void *)msg->data; + + mw->wid = wid; + mw->x = x; + mw->y = y; + mw->width = width; + mw->height = height; +} + + +void yutani_msg_buildx_window_resize(yutani_msg_t * msg, uint32_t type, yutani_wid_t wid, uint32_t width, uint32_t height, uint32_t bufid, uint32_t flags) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = type; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_resize); + + struct yutani_msg_window_resize * mw = (void *)msg->data; + + mw->wid = wid; + mw->width = width; + mw->height = height; + mw->bufid = bufid; + mw->flags = flags; +} + + +void yutani_msg_buildx_window_advertise(yutani_msg_t * msg, yutani_wid_t wid, uint32_t flags, uint16_t * offsets, size_t length, char * data) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_ADVERTISE; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_advertise) + length; + + struct yutani_msg_window_advertise * mw = (void *)msg->data; + + mw->wid = wid; + mw->flags = flags; + mw->size = length; + if (offsets) { + memcpy(mw->offsets, offsets, sizeof(uint16_t)*5); + } else { + memset(mw->offsets, 0, sizeof(uint16_t)*5); + } + if (data) { + memcpy(mw->strings, data, mw->size); + } +} + + +void yutani_msg_buildx_subscribe(yutani_msg_t * msg) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_SUBSCRIBE; + msg->size = sizeof(struct yutani_message); +} + + +void yutani_msg_buildx_unsubscribe(yutani_msg_t * msg) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_UNSUBSCRIBE; + msg->size = sizeof(struct yutani_message); +} + + +void yutani_msg_buildx_query_windows(yutani_msg_t * msg) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_QUERY_WINDOWS; + msg->size = sizeof(struct yutani_message); +} + + +void yutani_msg_buildx_notify(yutani_msg_t * msg) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_NOTIFY; + msg->size = sizeof(struct yutani_message); +} + + +void yutani_msg_buildx_session_end(yutani_msg_t * msg) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_SESSION_END; + msg->size = sizeof(struct yutani_message); +} + + +void yutani_msg_buildx_window_focus(yutani_msg_t * msg, yutani_wid_t wid) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_FOCUS; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_focus); + + struct yutani_msg_window_focus * mw = (void *)msg->data; + + mw->wid = wid; +} + + +void yutani_msg_buildx_key_bind(yutani_msg_t * msg, kbd_key_t key, kbd_mod_t mod, int response) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_KEY_BIND; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_key_bind); + + struct yutani_msg_key_bind * mw = (void *)msg->data; + + mw->key = key; + mw->modifiers = mod; + mw->response = response; +} + + +void yutani_msg_buildx_window_drag_start(yutani_msg_t * msg, yutani_wid_t wid) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_DRAG_START; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_drag_start); + + struct yutani_msg_window_drag_start * mw = (void *)msg->data; + + mw->wid = wid; +} + + +void yutani_msg_buildx_window_update_shape(yutani_msg_t * msg, yutani_wid_t wid, int set_shape) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_UPDATE_SHAPE; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_update_shape); + + struct yutani_msg_window_update_shape * mw = (void *)msg->data; + + mw->wid = wid; + mw->set_shape = set_shape; +} + + +void yutani_msg_buildx_window_warp_mouse(yutani_msg_t * msg, yutani_wid_t wid, int32_t x, int32_t y) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_WARP_MOUSE; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_warp_mouse); + + struct yutani_msg_window_warp_mouse * mw = (void *)msg->data; + + mw->wid = wid; + mw->x = x; + mw->y = y; +} + + +void yutani_msg_buildx_window_show_mouse(yutani_msg_t * msg, yutani_wid_t wid, int32_t show_mouse) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_SHOW_MOUSE; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_show_mouse); + + struct yutani_msg_window_show_mouse * mw = (void *)msg->data; + + mw->wid = wid; + mw->show_mouse = show_mouse; +} + + +void yutani_msg_buildx_window_resize_start(yutani_msg_t * msg, yutani_wid_t wid, yutani_scale_direction_t direction) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_WINDOW_RESIZE_START; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_resize_start); + + struct yutani_msg_window_resize_start * mw = (void *)msg->data; + + mw->wid = wid; + mw->direction = direction; +} + + +void yutani_msg_buildx_special_request(yutani_msg_t * msg, yutani_wid_t wid, uint32_t request) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_SPECIAL_REQUEST; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_special_request); + + struct yutani_msg_special_request * sr = (void *)msg->data; + + sr->wid = wid; + sr->request = request; +} + +void yutani_msg_buildx_clipboard(yutani_msg_t * msg, char * content) { + msg->magic = YUTANI_MSG__MAGIC; + msg->type = YUTANI_MSG_CLIPBOARD; + msg->size = sizeof(struct yutani_message) + sizeof(struct yutani_msg_clipboard) + strlen(content); + + struct yutani_msg_clipboard * cl = (void *)msg->data; + + cl->size = strlen(content); + memcpy(cl->content, content, strlen(content)); +} + +int yutani_msg_send(yutani_t * y, yutani_msg_t * msg) { + return pex_reply(y->sock, msg->size, (char *)msg); +} + +yutani_t * yutani_context_create(FILE * socket) { + yutani_t * out = malloc(sizeof(yutani_t)); + + out->sock = socket; + out->display_width = 0; + out->display_height = 0; + out->windows = hashmap_create_int(10); + out->queued = list_create(); + return out; +} + +/** + * yutani_init + * + * Connect to the compositor. + * + * Connects and handles the initial welcome message. + */ +yutani_t * yutani_init(void) { + char * server_name = getenv("DISPLAY"); + if (!server_name) { + server_name = "compositor"; + } + FILE * c = pex_connect(server_name); + + if (!c) { + return NULL; /* Connection failed. */ + } + + yutani_t * y = yutani_context_create(c); + yutani_msg_buildx_hello_alloc(m); + yutani_msg_buildx_hello(m); + yutani_msg_send(y, m); + + yutani_msg_t * mm = yutani_wait_for(y, YUTANI_MSG_WELCOME); + struct yutani_msg_welcome * mw = (void *)&mm->data; + y->display_width = mw->display_width; + y->display_height = mw->display_height; + y->server_ident = server_name; + free(mm); + + return y; +} + +/** + * yutani_window_create_flags + * + * Create a window with certain pre-specified properties. + */ +yutani_window_t * yutani_window_create_flags(yutani_t * y, int width, int height, uint32_t flags) { + yutani_window_t * win = malloc(sizeof(yutani_window_t)); + + yutani_msg_buildx_window_new_flags_alloc(m); + yutani_msg_buildx_window_new_flags(m, width, height, flags); + yutani_msg_send(y, m); + + yutani_msg_t * mm = yutani_wait_for(y, YUTANI_MSG_WINDOW_INIT); + struct yutani_msg_window_init * mw = (void *)&mm->data; + + win->width = mw->width; + win->height = mw->height; + win->bufid = mw->bufid; + win->wid = mw->wid; + win->focused = 0; + win->decorator_flags = 0; + win->x = 0; + win->y = 0; + win->user_data = NULL; + win->ctx = y; + free(mm); + + hashmap_set(y->windows, (void*)win->wid, win); + + char key[1024]; + YUTANI_SHMKEY(y->server_ident, key, 1024, win); + + size_t size = (width * height * 4); + win->buffer = (char *)syscall_shm_obtain(key, &size); + return win; + +} + +/** + * yutani_window_create + * + * Create a basic window. + */ +yutani_window_t * yutani_window_create(yutani_t * y, int width, int height) { + return yutani_window_create_flags(y,width,height,0); +} + +/** + * yutani_flip + * + * Ask the server to redraw the window. + */ +void yutani_flip(yutani_t * y, yutani_window_t * win) { + yutani_msg_buildx_flip_alloc(m); + yutani_msg_buildx_flip(m, win->wid); + yutani_msg_send(y, m); +} + +/** + * yutani_flip_region + * + * Ask the server to redraw a region relative the window. + */ +void yutani_flip_region(yutani_t * yctx, yutani_window_t * win, int32_t x, int32_t y, int32_t width, int32_t height) { + yutani_msg_buildx_flip_region_alloc(m); + yutani_msg_buildx_flip_region(m, win->wid, x, y, width, height); + yutani_msg_send(yctx, m); +} + +/** + * yutani_close + * + * Close a window. A closed window should not be used again, + * and its associated buffers will be freed. + */ +void yutani_close(yutani_t * y, yutani_window_t * win) { + yutani_msg_buildx_window_close_alloc(m); + yutani_msg_buildx_window_close(m, win->wid); + yutani_msg_send(y, m); + + /* Now destroy our end of the window */ + { + char key[1024]; + YUTANI_SHMKEY_EXP(y->server_ident, key, 1024, win->bufid); + syscall_shm_release(key); + } + + hashmap_remove(y->windows, (void*)win->wid); + free(win); +} + +/** + * yutani_window_move + * + * Request a window be moved to new a location on screen. + */ +void yutani_window_move(yutani_t * yctx, yutani_window_t * window, int x, int y) { + yutani_msg_buildx_window_move_alloc(m); + yutani_msg_buildx_window_move(m, window->wid, x, y); + yutani_msg_send(yctx, m); +} + +/** + * yutani_set_stack + * + * Set the stacking order of the window. + */ +void yutani_set_stack(yutani_t * yctx, yutani_window_t * window, int z) { + yutani_msg_buildx_window_stack_alloc(m); + yutani_msg_buildx_window_stack(m, window->wid, z); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_resize + * + * Request that the server resize a window. + */ +void yutani_window_resize(yutani_t * yctx, yutani_window_t * window, uint32_t width, uint32_t height) { + yutani_msg_buildx_window_resize_alloc(m); + yutani_msg_buildx_window_resize(m, YUTANI_MSG_RESIZE_REQUEST, window->wid, width, height, 0, 0); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_resize_offer + * + * In a response to a server resize message, offer an alternative size. + * Allows the client to reject a user-provided resize request due to + * size constraints or other reasons. + */ +void yutani_window_resize_offer(yutani_t * yctx, yutani_window_t * window, uint32_t width, uint32_t height) { + yutani_msg_buildx_window_resize_alloc(m); + yutani_msg_buildx_window_resize(m, YUTANI_MSG_RESIZE_OFFER, window->wid, width, height, 0, 0); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_resize_accept + * + * Accept the server's resize request, initialize new buffers + * and all the client to draw into the new buffers. + */ +void yutani_window_resize_accept(yutani_t * yctx, yutani_window_t * window, uint32_t width, uint32_t height) { + yutani_msg_buildx_window_resize_alloc(m); + yutani_msg_buildx_window_resize(m, YUTANI_MSG_RESIZE_ACCEPT, window->wid, width, height, 0, 0); + yutani_msg_send(yctx, m); + + /* Now wait for the new bufid */ + yutani_msg_t * mm = yutani_wait_for(yctx, YUTANI_MSG_RESIZE_BUFID); + struct yutani_msg_window_resize * wr = (void*)mm->data; + + if (window->wid != wr->wid) { + /* I am not sure what to do here. */ + return; + } + + /* Update the window */ + window->width = wr->width; + window->height = wr->height; + window->oldbufid = window->bufid; + window->bufid = wr->bufid; + free(mm); + + /* Allocate the buffer */ + { + char key[1024]; + YUTANI_SHMKEY(yctx->server_ident, key, 1024, window); + + size_t size = (window->width * window->height * 4); + window->buffer = (char *)syscall_shm_obtain(key, &size); + } +} + +/** + * yutani_window_resize_done + * + * The client has finished drawing into the new buffers after + * accepting a resize request and the server should now + * discard the old buffer and switch to the new one. + */ +void yutani_window_resize_done(yutani_t * yctx, yutani_window_t * window) { + /* Destroy the old buffer */ + { + char key[1024]; + YUTANI_SHMKEY_EXP(yctx->server_ident, key, 1024, window->oldbufid); + syscall_shm_release(key); + } + + yutani_msg_buildx_window_resize_alloc(m); + yutani_msg_buildx_window_resize(m, YUTANI_MSG_RESIZE_DONE, window->wid, window->width, window->height, window->bufid, 0); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_advertise + * + * Provide a title for a window to have it show up + * in the panel window list. + */ +void yutani_window_advertise(yutani_t * yctx, yutani_window_t * window, char * name) { + + uint32_t flags = 0; /* currently, no client flags */ + uint16_t offsets[5] = {0,0,0,0,0}; + uint32_t length = 0; + char * strings; + + if (!name) { + length = 1; + strings = " "; + } else { + length = strlen(name) + 1; + strings = name; + /* All the other offsets will point to null characters */ + offsets[1] = strlen(name); + offsets[2] = strlen(name); + offsets[3] = strlen(name); + offsets[4] = strlen(name); + } + + yutani_msg_buildx_window_advertise_alloc(m, length); + yutani_msg_buildx_window_advertise(m, window->wid, flags, offsets, length, strings); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_advertise_icon + * + * Provide a title and an icon for the panel to show. + * + * Note that three additional fields are available in the advertisement + * messages which are not yet used. This is to allow for future expansion. + */ +void yutani_window_advertise_icon(yutani_t * yctx, yutani_window_t * window, char * name, char * icon) { + + uint32_t flags = 0; /* currently no client flags */ + uint16_t offsets[5] = {0,0,0,0,0}; + uint32_t length = strlen(name) + strlen(icon) + 2; + char * strings = malloc(length); + + if (name) { + memcpy(&strings[0], name, strlen(name)+1); + offsets[0] = 0; + offsets[1] = strlen(name); + offsets[2] = strlen(name); + offsets[3] = strlen(name); + offsets[4] = strlen(name); + } + if (icon) { + memcpy(&strings[offsets[1]+1], icon, strlen(icon)+1); + offsets[1] = strlen(name)+1; + offsets[2] = strlen(name)+1+strlen(icon); + offsets[3] = strlen(name)+1+strlen(icon); + offsets[4] = strlen(name)+1+strlen(icon); + } + + yutani_msg_buildx_window_advertise_alloc(m, length); + yutani_msg_buildx_window_advertise(m, window->wid, flags, offsets, length, strings); + yutani_msg_send(yctx, m); + free(strings); +} + +/** + * yutani_subscribe_windows + * + * Subscribe to messages about new window advertisements. + * Basically, if you're a panel, you want to do this, so + * you can know when windows move around or change focus. + */ +void yutani_subscribe_windows(yutani_t * y) { + yutani_msg_buildx_subscribe_alloc(m); + yutani_msg_buildx_subscribe(m); + yutani_msg_send(y, m); +} + +/** + * yutani_unsubscribe_windows + * + * If you no longer wish to receive window change messages, + * you can unsubscribe your client from them. + */ +void yutani_unsubscribe_windows(yutani_t * y) { + yutani_msg_buildx_unsubscribe_alloc(m); + yutani_msg_buildx_unsubscribe(m); + yutani_msg_send(y, m); +} + +/** + * yutani_query_windows + * + * When notified of changes, call this to request + * the new information. + */ +void yutani_query_windows(yutani_t * y) { + yutani_msg_buildx_query_windows_alloc(m); + yutani_msg_buildx_query_windows(m); + yutani_msg_send(y, m); +} + +/** + * yutani_session_end + * + * For use by session managers, tell the compositor + * that the session has ended and it should inform + * other clients of this so they can exit. + */ +void yutani_session_end(yutani_t * y) { + yutani_msg_buildx_session_end_alloc(m); + yutani_msg_buildx_session_end(m); + yutani_msg_send(y, m); +} + +/** + * yutani_focus_window + * + * Change focus to the given window. Mostly used by + * panels and other window management things, but if you + * have a multi-window application, such as one with a + * model dialog, and you want to force focus away from one + * window and onto another, you can use this. + */ +void yutani_focus_window(yutani_t * yctx, yutani_wid_t wid) { + yutani_msg_buildx_window_focus_alloc(m); + yutani_msg_buildx_window_focus(m, wid); + yutani_msg_send(yctx, m); +} + +/** + * yutani_key_bind + * + * Request a key combination always be sent to this client. + * You can request for the combination to be sent only to + * this client (steal binding) or to also go to other clients + * (spy binding), the latter of which is useful for catching + * changes to modifier keys. + */ +void yutani_key_bind(yutani_t * yctx, kbd_key_t key, kbd_mod_t mod, int response) { + yutani_msg_buildx_key_bind_alloc(m); + yutani_msg_buildx_key_bind(m, key,mod,response); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_drag_start + * + * Begin a mouse-driven window movement action. + * Typically used by decorators to start moving the window + * when the user clicks and drags on the title bar. + */ +void yutani_window_drag_start(yutani_t * yctx, yutani_window_t * window) { + yutani_msg_buildx_window_drag_start_alloc(m); + yutani_msg_buildx_window_drag_start(m, window->wid); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_drag_start_wid + * + * Same as above, but takes a wid (of a presumably-foreign window) + * instead of a window pointer; used by the panel to initiate + * window movement through a drop-down menu for other clients. + */ +void yutani_window_drag_start_wid(yutani_t * yctx, yutani_wid_t wid) { + yutani_msg_buildx_window_drag_start_alloc(m); + yutani_msg_buildx_window_drag_start(m, wid); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_update_shape + * + * Change the window shaping threshold. + * Allows partially-transparent windows to control whether they + * should still receive mouse events in their transparent regions. + */ +void yutani_window_update_shape(yutani_t * yctx, yutani_window_t * window, int set_shape) { + yutani_msg_buildx_window_update_shape_alloc(m); + yutani_msg_buildx_window_update_shape(m, window->wid, set_shape); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_warp_mouse + * + * Move the mouse to a locate relative to the window. + * Only works with relative mouse cursor. + * Useful for games. + * + * TODO: We still need a way to lock the cursor to a particular window. + * Even in games where warping happens quickly, we can still + * end up with the cursor outside of the window when a click happens. + */ +void yutani_window_warp_mouse(yutani_t * yctx, yutani_window_t * window, int32_t x, int32_t y) { + yutani_msg_buildx_window_warp_mouse_alloc(m); + yutani_msg_buildx_window_warp_mouse(m, window->wid, x, y); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_show_mouse + * + * Set the cursor type. Used to change to risize and drag indicators. + * Could be used to show a text insertion bar, or a link-clicking hand, + * but those cursors need to be added in the server. + * + * TODO: We should add a way to use client-provided cursor textures. + */ +void yutani_window_show_mouse(yutani_t * yctx, yutani_window_t * window, int32_t show_mouse) { + yutani_msg_buildx_window_show_mouse_alloc(m); + yutani_msg_buildx_window_show_mouse(m, window->wid, show_mouse); + yutani_msg_send(yctx, m); +} + +/** + * yutani_window_resize_start + * + * Start a mouse-driven window resize action. + * Used by decorators. + */ +void yutani_window_resize_start(yutani_t * yctx, yutani_window_t * window, yutani_scale_direction_t direction) { + yutani_msg_buildx_window_resize_start_alloc(m); + yutani_msg_buildx_window_resize_start(m, window->wid, direction); + yutani_msg_send(yctx, m); +} + +/** + * yutani_special_request + * + * Send one of the special request messages that aren't + * important enough to get their own message types. + * + * (MAXIMIZE, PLEASE_CLOSE, CLIPBOARD) + * + * Note that, especially in the CLIPBOARD case, the + * window does not to be set. + */ +void yutani_special_request(yutani_t * yctx, yutani_window_t * window, uint32_t request) { + /* wid isn't necessary; if window is null, set to 0 */ + yutani_msg_buildx_special_request_alloc(m); + yutani_msg_buildx_special_request(m, window ? window->wid : 0, request); + yutani_msg_send(yctx, m); +} + +/** + * yutani_special_request_wid + * + * Same as above, but takes a wid instead of a window pointer, + * for use with foreign windows. + */ +void yutani_special_request_wid(yutani_t * yctx, yutani_wid_t wid, uint32_t request) { + /* For working with other applications' windows */ + yutani_msg_buildx_special_request_alloc(m); + yutani_msg_buildx_special_request(m, wid, request); + yutani_msg_send(yctx, m); +} + +/** + * yutani_set_clipboard + * + * Set the clipboard content. + * + * If the clipboard content is too large for a message, + * it will be stored in a file and a special clipboard string + * will be set to indicate the real contents are + * in the file. + * + * To get the clipboard contents, send a CLIPBOARD special + * request and wait for the CLIPBOARD response message. + */ +void yutani_set_clipboard(yutani_t * yctx, char * content) { + /* Set clipboard contents */ + int len = strlen(content); + if (len > 511) { + char tmp_file[100]; + sprintf(tmp_file, "/tmp/.clipboard.%s", yctx->server_ident); + FILE * tmp = fopen(tmp_file, "w+"); + fwrite(content, len, 1, tmp); + fclose(tmp); + + char tmp_data[100]; + sprintf(tmp_data, "\002 %d", len); + yutani_msg_buildx_clipboard_alloc(m, strlen(tmp_data)); + yutani_msg_buildx_clipboard(m, tmp_data); + yutani_msg_send(yctx, m); + } else { + yutani_msg_buildx_clipboard_alloc(m, len); + yutani_msg_buildx_clipboard(m, content); + yutani_msg_send(yctx, m); + } +} + +/** + * yutani_open_clipboard + * + * Open the clipboard contents file. + */ +FILE * yutani_open_clipboard(yutani_t * yctx) { + char tmp_file[100]; + sprintf(tmp_file, "/tmp/.clipboard.%s", yctx->server_ident); + return fopen(tmp_file, "r"); +} + +/** + * init_graphics_yutani + * + * Create a graphical context around a Yutani window. + */ +gfx_context_t * init_graphics_yutani(yutani_window_t * window) { + gfx_context_t * out = malloc(sizeof(gfx_context_t)); + out->width = window->width; + out->height = window->height; + out->stride = window->width * sizeof(uint32_t); + out->depth = 32; + out->size = GFX_H(out) * GFX_W(out) * GFX_B(out); + out->buffer = window->buffer; + out->backbuffer = out->buffer; + out->clips = NULL; + return out; +} + +/** + * init_graphics_yutani_double_buffer + * + * Create a graphics context around a Yutani window + * with a separate backing store for double-buffering. + */ +gfx_context_t * init_graphics_yutani_double_buffer(yutani_window_t * window) { + gfx_context_t * out = init_graphics_yutani(window); + out->backbuffer = malloc(GFX_B(out) * GFX_W(out) * GFX_H(out)); + return out; +} + +/** + * reinit_graphics_yutani + * + * Reinitialize a graphics context, such as when + * the window size changes. + */ +void reinit_graphics_yutani(gfx_context_t * out, yutani_window_t * window) { + out->width = window->width; + out->height = window->height; + out->stride = window->width * 4; + out->depth = 32; + out->size = GFX_H(out) * GFX_W(out) * GFX_B(out); + if (out->buffer == out->backbuffer) { + out->buffer = window->buffer; + out->backbuffer = out->buffer; + } else { + out->buffer = window->buffer; + out->backbuffer = realloc(out->backbuffer, GFX_B(out) * GFX_W(out) * GFX_H(out)); + } +} + +/** + * release_graphics_yutani + * + * Release a graphics context. + * XXX: This seems to work generically for any graphics context? + */ +void release_graphics_yutani(gfx_context_t * gfx) { + if (gfx->backbuffer != gfx->buffer) { + free(gfx->backbuffer); + } + free(gfx); +} diff --git a/libc/assert/assert.c b/libc/assert/assert.c new file mode 100644 index 00000000..e530124c --- /dev/null +++ b/libc/assert/assert.c @@ -0,0 +1,6 @@ +#include + +void __assert_func(const char * file, int line, const char * func, const char * failedexpr) { + fprintf(stderr, "Assertion failed in %s:%d (%s): %s\n", file, line, func, failedexpr); + // void +} diff --git a/toolchain/patches/newlib/toaru/crt0.s b/libc/crt0.s similarity index 100% rename from toolchain/patches/newlib/toaru/crt0.s rename to libc/crt0.s diff --git a/toolchain/patches/newlib/toaru/crti.s b/libc/crti.s similarity index 100% rename from toolchain/patches/newlib/toaru/crti.s rename to libc/crti.s diff --git a/toolchain/patches/newlib/toaru/crtn.s b/libc/crtn.s similarity index 100% rename from toolchain/patches/newlib/toaru/crtn.s rename to libc/crtn.s diff --git a/libc/ctype/isalnum.c b/libc/ctype/isalnum.c new file mode 100644 index 00000000..4ccb614a --- /dev/null +++ b/libc/ctype/isalnum.c @@ -0,0 +1,5 @@ +#include + +int isalnum(int c) { + return isalpha(c) || isdigit(c); +} diff --git a/libc/ctype/isalpha.c b/libc/ctype/isalpha.c new file mode 100644 index 00000000..941f192a --- /dev/null +++ b/libc/ctype/isalpha.c @@ -0,0 +1,3 @@ +int isalpha(int c) { + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); +} diff --git a/libc/ctype/isascii.c b/libc/ctype/isascii.c new file mode 100644 index 00000000..78c8eba0 --- /dev/null +++ b/libc/ctype/isascii.c @@ -0,0 +1,3 @@ +int isascii(int c) { + return (c <= 0x7f); +} diff --git a/libc/ctype/iscntrl.c b/libc/ctype/iscntrl.c new file mode 100644 index 00000000..0b80b4ca --- /dev/null +++ b/libc/ctype/iscntrl.c @@ -0,0 +1,3 @@ +int iscntrl(int c) { + return ((c >= 0 && c <= 0x1f) || (c == 0x7f)); +} diff --git a/libc/ctype/isdigit.c b/libc/ctype/isdigit.c new file mode 100644 index 00000000..c0b0cee6 --- /dev/null +++ b/libc/ctype/isdigit.c @@ -0,0 +1,3 @@ +int isdigit(int c) { + return (c >= '0' && c <= '9'); +} diff --git a/libc/ctype/isgraph.c b/libc/ctype/isgraph.c new file mode 100644 index 00000000..c97a4bae --- /dev/null +++ b/libc/ctype/isgraph.c @@ -0,0 +1,3 @@ +int isgraph(int c) { + return (c >= '!' && c <= '~'); +} diff --git a/libc/ctype/islower.c b/libc/ctype/islower.c new file mode 100644 index 00000000..a108a3cb --- /dev/null +++ b/libc/ctype/islower.c @@ -0,0 +1,3 @@ +int islower(int c) { + return (c >= 'a' && c <= 'z'); +} diff --git a/libc/ctype/isprint.c b/libc/ctype/isprint.c new file mode 100644 index 00000000..70c62867 --- /dev/null +++ b/libc/ctype/isprint.c @@ -0,0 +1,5 @@ +#include + +int isprint(int c) { + return isgraph(c) || (c == ' '); +} diff --git a/libc/ctype/ispunct.c b/libc/ctype/ispunct.c new file mode 100644 index 00000000..636355b6 --- /dev/null +++ b/libc/ctype/ispunct.c @@ -0,0 +1,5 @@ +#include + +int ispunct(int c) { + return isgraph(c) && !isalnum(c); +} diff --git a/libc/ctype/isspace.c b/libc/ctype/isspace.c new file mode 100644 index 00000000..a0599635 --- /dev/null +++ b/libc/ctype/isspace.c @@ -0,0 +1,3 @@ +int isspace(int c) { + return (c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == ' '); +} diff --git a/libc/ctype/isupper.c b/libc/ctype/isupper.c new file mode 100644 index 00000000..aefee52c --- /dev/null +++ b/libc/ctype/isupper.c @@ -0,0 +1,3 @@ +int isupper(int c) { + return (c >= 'A' && c <= 'Z'); +} diff --git a/libc/ctype/isxdigit.c b/libc/ctype/isxdigit.c new file mode 100644 index 00000000..fcb431c4 --- /dev/null +++ b/libc/ctype/isxdigit.c @@ -0,0 +1,3 @@ +int isxdigit(int c) { + return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +} diff --git a/libc/ctype/tolower.c b/libc/ctype/tolower.c new file mode 100644 index 00000000..576516ac --- /dev/null +++ b/libc/ctype/tolower.c @@ -0,0 +1,6 @@ +int tolower(int c) { + if (c >= 'A' && c <= 'Z') { + return c - 'A' + 'a'; + } + return c; +} diff --git a/libc/ctype/toupper.c b/libc/ctype/toupper.c new file mode 100644 index 00000000..8af6fc39 --- /dev/null +++ b/libc/ctype/toupper.c @@ -0,0 +1,7 @@ +int toupper(int c) { + if (c >= 'a' && c <= 'z') { + return c - 'a' + 'A'; + } + return c; +} + diff --git a/libc/dirent/dir.c b/libc/dirent/dir.c new file mode 100644 index 00000000..f6c4e2f6 --- /dev/null +++ b/libc/dirent/dir.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include + +DIR * opendir (const char * dirname) { + int fd = open(dirname, O_RDONLY); + if (fd < 0) { + errno = -fd; + return NULL; + } + + DIR * dir = (DIR *)malloc(sizeof(DIR)); + dir->fd = fd; + dir->cur_entry = -1; + return dir; +} + +int closedir (DIR * dir) { + if (dir && (dir->fd != -1)) { + return close(dir->fd); + } else { + return -EBADF; + } +} + +struct dirent * readdir (DIR * dirp) { + static struct dirent ent; + + int ret = syscall_readdir(dirp->fd, ++dirp->cur_entry, &ent); + if (ret < 0) { + errno = -ret; + memset(&ent, 0, sizeof(struct dirent)); + return NULL; + } + + if (ret == 0) { + /* end of directory */ + memset(&ent, 0, sizeof(struct dirent)); + return NULL; + } + + return &ent; +} diff --git a/libc/dirent/mkdir.c b/libc/dirent/mkdir.c new file mode 100644 index 00000000..451c5950 --- /dev/null +++ b/libc/dirent/mkdir.c @@ -0,0 +1,7 @@ +#include +#include +#include + +int mkdir(const char *pathname, mode_t mode) { + __sets_errno(syscall_mkdir((char *)pathname, mode)); +} diff --git a/userspace/lib/dlfcn.c b/libc/dlfcn/dlfcn.c similarity index 100% rename from userspace/lib/dlfcn.c rename to libc/dlfcn/dlfcn.c diff --git a/libc/errno/errorno.c b/libc/errno/errorno.c new file mode 100644 index 00000000..14a81221 --- /dev/null +++ b/libc/errno/errorno.c @@ -0,0 +1,3 @@ +#include + +int errno = 0; diff --git a/libc/ioctl/ioctl.c b/libc/ioctl/ioctl.c new file mode 100644 index 00000000..09207b3f --- /dev/null +++ b/libc/ioctl/ioctl.c @@ -0,0 +1,74 @@ +#include +#include +#include + +int ioctl(int fd, int request, void * argp) { + return syscall_ioctl(fd, request, argp); +} + +/* termios */ +speed_t cfgetispeed(const struct termios * tio) { + return 0; +} +speed_t cfgetospeed(const struct termios * tio) { + return 0; +} + +int cfsetispeed(struct termios * tio, speed_t speed) { + /* hahahaha, yeah right */ + return 0; +} + +int cfsetospeed(struct termios * tio, speed_t speed) { + return 0; +} + +int tcdrain(int i) { + //DEBUG_STUB("tcdrain(%d)\n", i); + return 0; +} + +int tcflow(int fd, int arg) { + return ioctl(fd, TCXONC, (void*)arg); +} + +int tcflush(int fd, int arg) { + return ioctl(fd, TCFLSH, (void*)arg); +} + +pid_t tcgetsid(int fd) { + //DEBUG_STUB("tcgetsid(%d)\n", fd); + return getpid(); +} + +int tcsendbreak(int fd, int arg) { + return ioctl(fd, TCSBRK, (void*)arg); +} + +int tcgetattr(int fd, struct termios * tio) { + return ioctl(fd, TCGETS, tio); +} + +int tcsetattr(int fd, int actions, struct termios * tio) { + switch (actions) { + case TCSANOW: + return ioctl(fd, TCSETS, tio); + case TCSADRAIN: + return ioctl(fd, TCSETSW, tio); + case TCSAFLUSH: + return ioctl(fd, TCSETSF, tio); + default: + return 0; + } +} + +int tcsetpgrp(int fd, pid_t pgrp) { + return ioctl(fd, TIOCSPGRP, &pgrp); +} + +pid_t tcgetpgrp(int fd) { + pid_t pgrp; + ioctl(fd, TIOCGPGRP, &pgrp); + return pgrp; +} + diff --git a/libc/locale/localeconv.c b/libc/locale/localeconv.c new file mode 100644 index 00000000..8ebe01d8 --- /dev/null +++ b/libc/locale/localeconv.c @@ -0,0 +1,26 @@ +#include + +static struct lconv _en_US = { + .decimal_point = ".", + .thousands_sep = ",", + .grouping = "\x03\x03", + .int_curr_symbol = "USD ", + .currency_symbol = "$", + .mon_decimal_point = ".", + .mon_thousands_sep = ",", + .mon_grouping = "\x03\x03", + .positive_sign = "+", + .negative_sign = "-", + .int_frac_digits = 2, + .frac_digits = 2, + .p_cs_precedes = 1, + .p_sep_by_space = 0, + .n_cs_precedes = 1, + .n_sep_by_space = 0, + .p_sign_posn = 1, + .n_sign_posn = 1, +}; + +struct lconv * localeconv(void) { + return &_en_US; +} diff --git a/libc/locale/setlocale.c b/libc/locale/setlocale.c new file mode 100644 index 00000000..411852cc --- /dev/null +++ b/libc/locale/setlocale.c @@ -0,0 +1,7 @@ +#include +#include + +char * setlocale(int category, const char *locale) { + return "en_US"; +} + diff --git a/libc/main.c b/libc/main.c new file mode 100644 index 00000000..b653b0fa --- /dev/null +++ b/libc/main.c @@ -0,0 +1,130 @@ +#include +#include +#include + +#include +#include + +DEFN_SYSCALL1(exit, 0, int); +DEFN_SYSCALL1(print, 1, const char *); +DEFN_SYSCALL2(gettimeofday, 6, void *, void *); +DEFN_SYSCALL3(execve, 7, char *, char **, char **); +DEFN_SYSCALL1(sbrk, 10, int); +DEFN_SYSCALL0(getgraphicsaddress, 11); +DEFN_SYSCALL1(setgraphicsoffset, 16, int); +DEFN_SYSCALL1(wait, 17, unsigned int); +DEFN_SYSCALL0(getgraphicswidth, 18); +DEFN_SYSCALL0(getgraphicsheight, 19); +DEFN_SYSCALL0(getgraphicsdepth, 20); +DEFN_SYSCALL0(mkpipe, 21); +DEFN_SYSCALL1(kernel_string_XXX, 25, char *); +DEFN_SYSCALL0(reboot, 26); +DEFN_SYSCALL3(readdir, 27, int, int, void *); +DEFN_SYSCALL3(clone, 30, uintptr_t, uintptr_t, void *); +DEFN_SYSCALL0(mousedevice, 33); +DEFN_SYSCALL2(mkdir, 34, char *, unsigned int); +DEFN_SYSCALL2(shm_obtain, 35, char *, size_t *); +DEFN_SYSCALL1(shm_release, 36, char *); +DEFN_SYSCALL2(share_fd, 39, int, int); +DEFN_SYSCALL1(get_fd, 40, int); +DEFN_SYSCALL0(gettid, 41); +DEFN_SYSCALL2(system_function, 43, int, char **); +DEFN_SYSCALL1(open_serial, 44, int); +DEFN_SYSCALL2(sleepabs, 45, unsigned long, unsigned long); +DEFN_SYSCALL3(ioctl, 47, int, int, void *); +DEFN_SYSCALL2(access, 48, char *, int); +DEFN_SYSCALL2(stat, 49, char *, void *); +DEFN_SYSCALL3(waitpid, 53, int, int *, int); +DEFN_SYSCALL5(mount, SYS_MOUNT, char *, char *, char *, unsigned long, void *); +DEFN_SYSCALL2(lstat, SYS_LSTAT, char *, void *); + +extern void _init(); +extern void _fini(); + +char ** environ = NULL; +int _environ_size = 0; +char * _argv_0 = NULL; + +char ** __argv = NULL; +extern char ** __get_argv(void) { + return __argv; +} + +extern void __stdio_init_buffers(void); + +void _exit(int val){ + _fini(); + syscall_exit(val); + + __builtin_unreachable(); +} + +__attribute__((constructor)) +static void _libc_init(void) { + __stdio_init_buffers(); + + unsigned int x = 0; + unsigned int nulls = 0; + for (x = 0; 1; ++x) { + if (!__get_argv()[x]) { + ++nulls; + if (nulls == 2) { + break; + } + continue; + } + if (nulls == 1) { + environ = &__get_argv()[x]; + break; + } + } + if (!environ) { + environ = malloc(sizeof(char *) * 4); + environ[0] = NULL; + environ[1] = NULL; + environ[2] = NULL; + environ[3] = NULL; + _environ_size = 4; + } else { + /* Find actual size */ + int size = 0; + + char ** tmp = environ; + while (*tmp) { + size++; + tmp++; + } + + if (size < 4) { + _environ_size = 4; + } else { + /* Multiply by two */ + _environ_size = size * 2; + } + + char ** new_environ = malloc(sizeof(char*) * _environ_size); + int i = 0; + while (i < _environ_size && environ[i]) { + new_environ[i] = environ[i]; + i++; + } + + while (i < _environ_size) { + new_environ[i] = NULL; + i++; + } + + environ = new_environ; + } + _argv_0 = __get_argv()[0]; +} + +void pre_main(int (*main)(int,char**), int argc, char * argv[]) { + if (!__get_argv()) { + /* Statically loaded, must set __argv so __get_argv() works */ + __argv = argv; + } + _init(); + exit(main(argc, argv)); +} + diff --git a/libc/math/bad.c b/libc/math/bad.c new file mode 100644 index 00000000..f97efa8f --- /dev/null +++ b/libc/math/bad.c @@ -0,0 +1,55 @@ +/* STUB MATH LIBRARY */ +#include +#include + +#define BAD do { if (getenv("LIBM_DEBUG")) { fprintf(stderr, "Called bad math function %s\n", __func__); } } while (0) + +double acos(double x) { + BAD; + return 0.0; +} + +double asin(double x) { + BAD; + return 0.0; +} + +double cosh(double x) { + BAD; + return 0.0; +} + +double ldexp(double a, int exp) { + double out = a; + while (exp) { + out *= 2.0; + exp--; + } + return out; +} + +double log(double x) { + BAD; + return 0.0; +} + +double log10(double x) { + BAD; + return 0.0; +} + +double log2(double x) { + BAD; + return 0.0; +} + +double sinh(double x) { + BAD; + return 0.0; +} + +double tanh(double x) { + BAD; + return 0.0; +} + diff --git a/libc/math/math.c b/libc/math/math.c new file mode 100644 index 00000000..4be9ffa7 --- /dev/null +++ b/libc/math/math.c @@ -0,0 +1,535 @@ +#include +#include +#include +#include + +//#define MATH do { fprintf(stderr, "Executed math function %s\n", __func__); } while (0) +#define MATH (void)0 + +double exp(double x) { + return pow(2.71828182846, x); +} + +double ceil(double x) { + int _x = x; + if ((float)_x == x) return x; + if (x < 0.0) { + return (double)_x; + } + return (double)_x + 1; +} + +double floor(double x) { + MATH; + if (x > -1.0 && x < 1.0) { + if (x >= 0) { + return 0.0; + } else { + return -1.0; + } + } + + if (x < 0) { + int x_i = x; + return (double)(x_i - 1); + } else { + int x_i = x; + return (double)x_i; + } +} + +int abs(int j) { + return (j < 0 ? -j : j); +} + +double pow(double x, double y) { + MATH; + double out; + asm volatile ( + "fyl2x;" + "fld %%st;" + "frndint;" + "fsub %%st,%%st(1);" + "fxch;" + "fchs;" + "f2xm1;" + "fld1;" + "faddp;" + "fxch;" + "fld1;" + "fscale;" + "fstp %%st(1);" + "fmulp;" : "=t"(out) : "0"(x),"u"(y) : "st(1)" ); + return out; +} + +double fabs(double x) { + MATH; + return __builtin_fabs(x); +} + +double fmod(double x, double y) { + MATH; + if (x >= 0.0) { + while (x > y) { + x -= y; + } + return x; + } else { + return 0.0; + } +} + +double sqrt(double x) { + MATH; + return __builtin_sqrt(x); +} + +static double bad_sine_table[] = { + 0, + 0.01745240644, + 0.03489949671, + 0.05233595625, + 0.06975647375, + 0.08715574276, + 0.1045284633, + 0.1218693434, + 0.139173101, + 0.1564344651, + 0.1736481777, + 0.1908089954, + 0.2079116908, + 0.2249510544, + 0.2419218956, + 0.2588190451, + 0.2756373559, + 0.2923717048, + 0.3090169944, + 0.3255681545, + 0.3420201434, + 0.3583679496, + 0.3746065935, + 0.3907311285, + 0.4067366431, + 0.4226182618, + 0.4383711468, + 0.4539904998, + 0.4694715628, + 0.4848096203, + 0.5000000001, + 0.515038075, + 0.5299192643, + 0.5446390351, + 0.5591929035, + 0.5735764364, + 0.5877852524, + 0.6018150232, + 0.6156614754, + 0.6293203911, + 0.6427876098, + 0.6560590291, + 0.6691306064, + 0.6819983601, + 0.6946583705, + 0.7071067813, + 0.7193398004, + 0.7313537017, + 0.7431448256, + 0.7547095803, + 0.7660444432, + 0.7771459615, + 0.7880107537, + 0.7986355101, + 0.8090169944, + 0.8191520444, + 0.8290375726, + 0.838670568, + 0.8480480962, + 0.8571673008, + 0.8660254039, + 0.8746197072, + 0.8829475929, + 0.8910065243, + 0.8987940464, + 0.9063077871, + 0.9135454577, + 0.9205048535, + 0.9271838546, + 0.9335804266, + 0.9396926208, + 0.9455185757, + 0.9510565163, + 0.956304756, + 0.961261696, + 0.9659258263, + 0.9702957263, + 0.9743700648, + 0.9781476008, + 0.9816271835, + 0.984807753, + 0.9876883406, + 0.9902680688, + 0.9925461517, + 0.9945218954, + 0.9961946981, + 0.9975640503, + 0.9986295348, + 0.999390827, + 0.9998476952, + 1, + 0.9998476952, + 0.999390827, + 0.9986295347, + 0.9975640502, + 0.9961946981, + 0.9945218953, + 0.9925461516, + 0.9902680687, + 0.9876883406, + 0.984807753, + 0.9816271834, + 0.9781476007, + 0.9743700647, + 0.9702957262, + 0.9659258262, + 0.9612616959, + 0.9563047559, + 0.9510565162, + 0.9455185755, + 0.9396926207, + 0.9335804264, + 0.9271838545, + 0.9205048534, + 0.9135454575, + 0.9063077869, + 0.8987940462, + 0.8910065241, + 0.8829475927, + 0.874619707, + 0.8660254036, + 0.8571673006, + 0.848048096, + 0.8386705678, + 0.8290375724, + 0.8191520441, + 0.8090169942, + 0.7986355099, + 0.7880107534, + 0.7771459613, + 0.7660444429, + 0.75470958, + 0.7431448253, + 0.7313537014, + 0.7193398001, + 0.707106781, + 0.6946583702, + 0.6819983598, + 0.6691306061, + 0.6560590288, + 0.6427876094, + 0.6293203908, + 0.6156614751, + 0.6018150229, + 0.587785252, + 0.5735764361, + 0.5591929032, + 0.5446390347, + 0.5299192639, + 0.5150380746, + 0.4999999997, + 0.4848096199, + 0.4694715625, + 0.4539904994, + 0.4383711465, + 0.4226182614, + 0.4067366428, + 0.3907311282, + 0.3746065931, + 0.3583679492, + 0.342020143, + 0.3255681541, + 0.309016994, + 0.2923717044, + 0.2756373555, + 0.2588190447, + 0.2419218952, + 0.224951054, + 0.2079116904, + 0.190808995, + 0.1736481773, + 0.1564344647, + 0.1391731006, + 0.121869343, + 0.1045284629, + 0.08715574235, + 0.06975647334, + 0.05233595584, + 0.0348994963, + 0.01745240603, + -0.000000000410206857, + -0.01745240685, + -0.03489949712, + -0.05233595666, + -0.06975647416, + -0.08715574317, + -0.1045284637, + -0.1218693438, + -0.1391731014, + -0.1564344655, + -0.1736481781, + -0.1908089958, + -0.2079116912, + -0.2249510548, + -0.241921896, + -0.2588190455, + -0.2756373562, + -0.2923717052, + -0.3090169948, + -0.3255681549, + -0.3420201438, + -0.35836795, + -0.3746065938, + -0.3907311289, + -0.4067366435, + -0.4226182622, + -0.4383711472, + -0.4539905002, + -0.4694715632, + -0.4848096207, + -0.5000000004, + -0.5150380753, + -0.5299192646, + -0.5446390354, + -0.5591929039, + -0.5735764368, + -0.5877852527, + -0.6018150235, + -0.6156614757, + -0.6293203914, + -0.6427876101, + -0.6560590294, + -0.6691306067, + -0.6819983604, + -0.6946583708, + -0.7071067815, + -0.7193398007, + -0.731353702, + -0.7431448258, + -0.7547095806, + -0.7660444435, + -0.7771459618, + -0.7880107539, + -0.7986355104, + -0.8090169947, + -0.8191520446, + -0.8290375729, + -0.8386705682, + -0.8480480964, + -0.857167301, + -0.8660254041, + -0.8746197074, + -0.8829475931, + -0.8910065244, + -0.8987940465, + -0.9063077873, + -0.9135454579, + -0.9205048537, + -0.9271838548, + -0.9335804267, + -0.939692621, + -0.9455185758, + -0.9510565165, + -0.9563047561, + -0.9612616961, + -0.9659258264, + -0.9702957264, + -0.9743700649, + -0.9781476009, + -0.9816271836, + -0.9848077531, + -0.9876883407, + -0.9902680688, + -0.9925461517, + -0.9945218954, + -0.9961946981, + -0.9975640503, + -0.9986295348, + -0.999390827, + -0.9998476952, + -1, + -0.9998476951, + -0.999390827, + -0.9986295347, + -0.9975640502, + -0.996194698, + -0.9945218953, + -0.9925461516, + -0.9902680687, + -0.9876883405, + -0.9848077529, + -0.9816271833, + -0.9781476006, + -0.9743700646, + -0.9702957261, + -0.9659258261, + -0.9612616958, + -0.9563047558, + -0.9510565161, + -0.9455185754, + -0.9396926206, + -0.9335804263, + -0.9271838543, + -0.9205048532, + -0.9135454574, + -0.9063077868, + -0.898794046, + -0.8910065239, + -0.8829475925, + -0.8746197068, + -0.8660254034, + -0.8571673003, + -0.8480480958, + -0.8386705676, + -0.8290375722, + -0.8191520439, + -0.809016994, + -0.7986355096, + -0.7880107532, + -0.777145961, + -0.7660444427, + -0.7547095798, + -0.743144825, + -0.7313537011, + -0.7193397998, + -0.7071067807, + -0.6946583699, + -0.6819983595, + -0.6691306058, + -0.6560590284, + -0.6427876091, + -0.6293203905, + -0.6156614747, + -0.6018150226, + -0.5877852517, + -0.5735764357, + -0.5591929029, + -0.5446390344, + -0.5299192636, + -0.5150380743, + -0.4999999993, + -0.4848096196, + -0.4694715621, + -0.4539904991, + -0.4383711461, + -0.422618261, + -0.4067366424, + -0.3907311278, + -0.3746065927, + -0.3583679488, + -0.3420201426, + -0.3255681537, + -0.3090169936, + -0.292371704, + -0.2756373551, + -0.2588190443, + -0.2419218948, + -0.2249510536, + -0.20791169, + -0.1908089946, + -0.1736481769, + -0.1564344643, + -0.1391731002, + -0.1218693426, + -0.1045284625, + -0.08715574194, + -0.06975647293, + -0.05233595543, + -0.03489949589, + -0.01745240562, + 0.0 +}; + +double sin(double x) { + MATH; + if (x < 0.0) { + x += 3.141592654 * 2.0 * 100.0; + } + double z = fmod(x, 3.141592654 * 2.0); + + int i = z * 360.0 / (3.141582654 * 2.0); + + return bad_sine_table[i]; +} + +double cos(double x) { + return sin(x + 3.141592654 / 2.0); +} + +double tan(double x) { + MATH; + float out; + float _x = x; + float one; + asm volatile ( + "fld %2\n" + "fptan\n" + "fstp %1\n" + "fstp %0\n" + : "=m"(out), "=m"(one) : "m"(_x) + ); + return out; +} + +double atan2(double y, double x) { + MATH; + float out; + float _x = x; + float _y = y; + asm volatile ( + "fld %1\n" + "fld %2\n" + "fpatan\n" + "fstp %0\n" + : "=m"(out) : "m"(_y), "m"(_x) + ); + return out; +} + +double atan(double x) { + return atan2(x,1.0); +} + +double hypot(double x, double y) { + return sqrt(x * x + y * y); +} + +double modf(double x, double *iptr) { + MATH; + int i = (int)x; + *iptr = (double)i; + return x - i; +} + +double frexp(double x, int *exp) { + MATH; + struct { + uint32_t lsw; + uint32_t msw; + } extract; + + memcpy(&extract, &x, sizeof(double)); + + *exp = ((extract.msw & 0x7ff00000) >> 20) - 0x3FE; + + struct { + uint32_t lsw; + uint32_t msw; + } out_double; + + out_double.msw = (extract.msw & 0x800fffff) | 0x3FE00000; + out_double.lsw = extract.lsw; + + double out; + memcpy(&out, &out_double, sizeof(double)); + return out; +} diff --git a/libc/poll/poll.c b/libc/poll/poll.c new file mode 100644 index 00000000..38d16688 --- /dev/null +++ b/libc/poll/poll.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +extern char * _argv_0; + +int poll(struct pollfd *fds, nfds_t nfds, int timeout) { + int count_pollin = 0; + + for (nfds_t i = 0; i < nfds; ++i) { + if (fds[i].events & POLLIN) { + count_pollin++; + } + fds[i].revents = 0; + } + + for (nfds_t i = 0; i < nfds; ++i) { + if (fds[i].events & (~POLLIN)) { + fprintf(stderr, "%s: poll: unsupported bit set in fds (this implementation only supports POLLIN)\n", _argv_0); + return -EINVAL; + } + } + + int fswait_fds[count_pollin]; + int fswait_backref[count_pollin]; + int j = 0; + for (nfds_t i = 0; i < nfds; ++i) { + if (fds[i].events & POLLIN) { + fswait_fds[j] = fds[i].fd; + fswait_backref[j] = i; + j++; + } + } + + int ret = fswait2(count_pollin, fswait_fds, timeout); + + if (ret >= 0 && ret < count_pollin) { + fds[fswait_backref[ret]].revents = POLLIN; + return 1; + } else if (ret == count_pollin) { + return 0; + } else { + return ret; /* Error */ + } +} diff --git a/userspace/lib/pthread.c b/libc/pthread/pthread.c similarity index 82% rename from userspace/lib/pthread.c rename to libc/pthread/pthread.c index f970b854..419f5816 100644 --- a/userspace/lib/pthread.c +++ b/libc/pthread/pthread.c @@ -1,20 +1,21 @@ /* This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2014 Kevin Lange + * Copyright (C) 2012-2018 K. Lange */ #include #include #include #include -#include "pthread.h" +#include +#include #define PTHREAD_STACK_SIZE 0x100000 int clone(uintptr_t a,uintptr_t b,void* c) { - return syscall_clone(a,b,c); + __sets_errno(syscall_clone(a,b,c)); } int gettid() { - return syscall_gettid(); + return syscall_gettid(); /* never fails */ } int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg) { @@ -26,7 +27,7 @@ int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *(*start_rout } int pthread_kill(pthread_t thread, int sig) { - return kill(thread.id, sig); + __sets_errno(kill(thread.id, sig)); } void pthread_exit(void * value) { diff --git a/libc/pty/pty.c b/libc/pty/pty.c new file mode 100644 index 00000000..e60d65d7 --- /dev/null +++ b/libc/pty/pty.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include +#include + +DEFN_SYSCALL5(openpty, SYS_OPENPTY, int *, int *, char *, void *, void *); + +int openpty(int * amaster, int * aslave, char * name, const struct termios *termp, const struct winsize * winp) { + __sets_errno(syscall_openpty(amaster,aslave,name,(struct termios *)termp,(struct winsize *)winp)); +} diff --git a/toolchain/patches/newlib/toaru/pwent.c b/libc/pwd/pwd.c similarity index 93% rename from toolchain/patches/newlib/toaru/pwent.c rename to libc/pwd/pwd.c index 4f7888c1..3afc8009 100644 --- a/toolchain/patches/newlib/toaru/pwent.c +++ b/libc/pwd/pwd.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange + * Copyright (C) 2013-2018 K. Lange * * getpwent, setpwent, endpwent, fgetpwent * getpwuid, getpwnam @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -39,14 +40,18 @@ static struct passwd * pw_ent; static char * pw_blob; struct passwd * fgetpwent(FILE * stream) { + if (!stream) { + return NULL; + } if (!pw_ent) { pw_ent = malloc(sizeof(struct passwd)); pw_blob = malloc(LINE_LEN); } - memset(pw_blob, 0x00, sizeof(pw_blob)); + memset(pw_blob, 0x00, LINE_LEN); fgets(pw_blob, LINE_LEN, stream); + if (pw_blob[strlen(pw_blob)-1] == '\n') { pw_blob[strlen(pw_blob)-1] = '\0'; /* erase newline */ } @@ -78,6 +83,10 @@ struct passwd * getpwent(void) { open_it(); } + if (!pwdb) { + return NULL; + } + return fgetpwent(pwdb); } @@ -128,3 +137,4 @@ struct passwd * getpwuid(uid_t uid) { return NULL; } + diff --git a/libc/sched/sched_yield.c b/libc/sched/sched_yield.c new file mode 100644 index 00000000..c1a062ec --- /dev/null +++ b/libc/sched/sched_yield.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +DEFN_SYSCALL0(yield, SYS_YIELD); + +int sched_yield(void) { + __sets_errno(syscall_yield()); +} diff --git a/libc/setjmp.S b/libc/setjmp.S new file mode 100644 index 00000000..83c121e6 --- /dev/null +++ b/libc/setjmp.S @@ -0,0 +1,64 @@ +.global setjmp +.type setjmp, STT_FUNC +setjmp: + + pushl %ebp + movl %esp,%ebp + + pushl %edi + movl 8(%ebp),%edi + + movl %eax,0 (%edi) + movl %ebx,4 (%edi) + movl %ecx,8 (%edi) + movl %edx,12 (%edi) + movl %esi,16 (%edi) + + movl -4 (%ebp),%eax + movl %eax,20 (%edi) + + movl 0 (%ebp),%eax + movl %eax,24 (%edi) + + movl %esp,%eax + addl $12,%eax + movl %eax,28 (%edi) + + movl 4 (%ebp),%eax + movl %eax,32 (%edi) + + popl %edi + movl $0,%eax + leave + ret + +.global longjmp +.type longjmp, STT_FUNC +longjmp: + pushl %ebp + movl %esp,%ebp + + movl 8(%ebp),%edi /* get jmp_buf */ + movl 12(%ebp),%eax /* store retval in j->eax */ + testl %eax,%eax + jne 0f + incl %eax +0: + movl %eax,0(%edi) + + movl 24(%edi),%ebp + + /*__CLI */ + movl 28(%edi),%esp + + pushl 32(%edi) + + movl 0 (%edi),%eax + movl 4 (%edi),%ebx + movl 8 (%edi),%ecx + movl 12(%edi),%edx + movl 16(%edi),%esi + movl 20(%edi),%edi + /*__STI */ + + ret diff --git a/libc/signal/kill.c b/libc/signal/kill.c new file mode 100644 index 00000000..0f2e66d0 --- /dev/null +++ b/libc/signal/kill.c @@ -0,0 +1,9 @@ +#include +#include + +DEFN_SYSCALL2(send_signal, 37, uint32_t, uint32_t); + +int kill(int pid, int sig) { + return syscall_send_signal(pid, sig); +} + diff --git a/libc/signal/raise.c b/libc/signal/raise.c new file mode 100644 index 00000000..4152787e --- /dev/null +++ b/libc/signal/raise.c @@ -0,0 +1,6 @@ +#include +#include + +int raise(int sig) { + return kill(getpid(), sig); +} diff --git a/libc/signal/signal.c b/libc/signal/signal.c new file mode 100644 index 00000000..e8172421 --- /dev/null +++ b/libc/signal/signal.c @@ -0,0 +1,8 @@ +#include +#include + +DEFN_SYSCALL2(signal, 38, uint32_t, void *); + +sighandler_t signal(int signum, sighandler_t handler) { + return (sighandler_t)syscall_signal(signum, (void *)handler); +} diff --git a/libc/stdio/perror.c b/libc/stdio/perror.c new file mode 100644 index 00000000..c17c9b49 --- /dev/null +++ b/libc/stdio/perror.c @@ -0,0 +1,6 @@ +#include +#include + +void perror(const char *s) { + fprintf(stderr, "%s: %s\n", s, strerror(errno)); +} diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c new file mode 100644 index 00000000..b0900ed0 --- /dev/null +++ b/libc/stdio/printf.c @@ -0,0 +1,335 @@ +#include +#include +#include + +static void print_dec(unsigned int value, unsigned int width, char * buf, int * ptr, int fill_zero, int align_right) { + unsigned int n_width = 1; + unsigned int i = 9; + + if (value < 10UL) { + n_width = 1; + } else if (value < 100UL) { + n_width = 2; + } else if (value < 1000UL) { + n_width = 3; + } else if (value < 10000UL) { + n_width = 4; + } else if (value < 100000UL) { + n_width = 5; + } else if (value < 1000000UL) { + n_width = 6; + } else if (value < 10000000UL) { + n_width = 7; + } else if (value < 100000000UL) { + n_width = 8; + } else if (value < 1000000000UL) { + n_width = 9; + } else { + n_width = 10; + } + + int printed = 0; + if (align_right) { + while (n_width + printed < width) { + buf[*ptr] = fill_zero ? '0' : ' '; + *ptr += 1; + printed += 1; + } + + i = n_width; + while (i > 0) { + unsigned int n = value / 10; + int r = value % 10; + buf[*ptr + i - 1] = r + '0'; + i--; + value = n; + } + *ptr += n_width; + } else { + i = n_width; + while (i > 0) { + unsigned int n = value / 10; + int r = value % 10; + buf[*ptr + i - 1] = r + '0'; + i--; + value = n; + printed++; + } + *ptr += n_width; + while (printed < (int)width) { + buf[*ptr] = fill_zero ? '0' : ' '; + *ptr += 1; + printed += 1; + } + } +} + +/* + * Hexadecimal to string + */ +static void print_hex(unsigned int value, unsigned int width, char * buf, int * ptr) { + int i = width; + + if (i == 0) i = 8; + + unsigned int n_width = 1; + unsigned int j = 0x0F; + while (value > j && j < UINT32_MAX) { + n_width += 1; + j *= 0x10; + j += 0x0F; + } + + while (i > (int)n_width) { + buf[*ptr] = '0'; + *ptr += 1; + i--; + } + + i = (int)n_width; + while (i-- > 0) { + buf[*ptr] = "0123456789abcdef"[(value>>(i*4))&0xF]; + *ptr += + 1; + } +} + +/* + * vasprintf() + */ +int xvasprintf(char * buf, const char * fmt, va_list args) { + int i = 0; + char * s; + char * b = buf; + int precision = -1; + for (const char *f = fmt; *f; f++) { + if (*f != '%') { + *b++ = *f; + continue; + } + ++f; + unsigned int arg_width = 0; + int align = 1; /* right */ + int fill_zero = 0; + int big = 0; + if (*f == '-') { + align = 0; + ++f; + } + if (*f == '*') { + arg_width = (char)va_arg(args, int); + ++f; + } + if (*f == '0') { + fill_zero = 1; + ++f; + } + while (*f >= '0' && *f <= '9') { + arg_width *= 10; + arg_width += *f - '0'; + ++f; + } + if (*f == '.') { + ++f; + precision = 0; + if (*f == '*') { + precision = (int)va_arg(args, int); + ++f; + } else { + while (*f >= '0' && *f <= '9') { + precision *= 10; + precision += *f - '0'; + ++f; + } + } + } + if (*f == 'l') { + big = 1; + ++f; + } + if (*f == 'z') { + big = 1; + ++f; + } + /* fmt[i] == '%' */ + switch (*f) { + case 's': /* String pointer -> String */ + { + size_t count = 0; + if (big) { + wchar_t * ws = (wchar_t *)va_arg(args, wchar_t *); + if (ws == NULL) { + ws = L"(null)"; + } + size_t count = 0; + while (*ws) { + *b++ = *ws++; + count++; + if (arg_width && count == arg_width) break; + } + } else { + s = (char *)va_arg(args, char *); + if (s == NULL) { + s = "(null)"; + } + if (precision >= 0) { + while (*s && precision > 0) { + *b++ = *s++; + count++; + precision--; + if (arg_width && count == arg_width) break; + } + } else { + while (*s) { + *b++ = *s++; + count++; + if (arg_width && count == arg_width) break; + } + } + } + while (count < arg_width) { + *b++ = ' '; + count++; + } + } + break; + case 'c': /* Single character */ + *b++ = (char)va_arg(args, int); + break; + case 'p': + if (!arg_width) { + arg_width = 8; + } + case 'x': /* Hexadecimal number */ + i = b - buf; + print_hex((unsigned long)va_arg(args, unsigned long), arg_width, buf, &i); + b = buf + i; + break; + case 'i': + case 'd': /* Decimal number */ + i = b - buf; + { + long val = (long)va_arg(args, long); + if (val < 0) { + *b++ = '-'; + buf++; + val = -val; + } + print_dec(val, arg_width, buf, &i, fill_zero, align); + } + b = buf + i; + break; + case 'u': /* Unsigned ecimal number */ + i = b - buf; + { + long val = (long)va_arg(args, long); + print_dec(val, arg_width, buf, &i, fill_zero, align); + } + b = buf + i; + break; + case 'g': /* supposed to also support e */ + case 'f': + { + double val = (double)va_arg(args, double); + i = b - buf; + if (val < 0) { + *b++ = '-'; + buf++; + val = -val; + } + print_dec((long)val, arg_width, buf, &i, fill_zero, align); + b = buf + i; + i = b - buf; + *b++ = '.'; + buf++; + for (int j = 0; j < ((precision > -1 && precision < 8) ? precision : 8); ++j) { + if ((int)(val * 100000.0) % 100000 == 0 && j != 0) break; + val *= 10.0; + print_dec((int)(val) % 10, 0, buf, &i, 0, 0); + } + b = buf + i; + } + break; + case '%': /* Escape */ + *b++ = '%'; + break; + default: /* Nothing at all, just dump it */ + *b++ = *f; + break; + } + } + /* Ensure the buffer ends in a null */ + *b = '\0'; + return b - buf; +} + +int vasprintf(char ** buf, const char * fmt, va_list args) { + char * b = malloc(1024); + *buf = b; + return xvasprintf(b, fmt, args); +} + +int vsprintf(char * buf, const char *fmt, va_list args) { + return xvasprintf(buf, fmt, args); +} + +int vsnprintf(char * buf, size_t size, const char *fmt, va_list args) { + /* XXX */ + return xvasprintf(buf, fmt, args); +} + +int vfprintf(FILE * device, const char *fmt, va_list args) { + char * buffer; + vasprintf(&buffer, fmt, args); + + int out = fwrite(buffer, 1, strlen(buffer), device); + free(buffer); + return out; +} + +int vprintf(const char *fmt, va_list args) { + return vfprintf(stdout, fmt, args); +} + +int fprintf(FILE * device, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + char * buffer; + vasprintf(&buffer, fmt, args); + va_end(args); + + int out = fwrite(buffer, 1, strlen(buffer), device); + free(buffer); + return out; +} + +int printf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + char * buffer; + vasprintf(&buffer, fmt, args); + va_end(args); + + int out = fwrite(buffer, 1, strlen(buffer), stdout); + free(buffer); + return out; +} + +int sprintf(char * buf, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int out = xvasprintf(buf, fmt, args); + va_end(args); + return out; +} + +int snprintf(char * buf, size_t size, const char * fmt, ...) { + /* XXX This is bad. */ + (void)size; + va_list args; + va_start(args, fmt); + int out = xvasprintf(buf, fmt, args); + va_end(args); + return out; +} + + diff --git a/libc/stdio/puts.c b/libc/stdio/puts.c new file mode 100644 index 00000000..92b3b5cd --- /dev/null +++ b/libc/stdio/puts.c @@ -0,0 +1,9 @@ +#include +#include + +int puts(const char *s) { + /* eof? */ + fwrite(s, 1, strlen(s), stdout); + fwrite("\n", 1, 1, stdout); + return 0; +} diff --git a/libc/stdio/remove.c b/libc/stdio/remove.c new file mode 100644 index 00000000..d06a8291 --- /dev/null +++ b/libc/stdio/remove.c @@ -0,0 +1,7 @@ +#include +#include + +int remove(const char * pathname) { + /* TODO directories */ + return unlink(pathname); +} diff --git a/libc/stdio/rename.c b/libc/stdio/rename.c new file mode 100644 index 00000000..ee698a3c --- /dev/null +++ b/libc/stdio/rename.c @@ -0,0 +1,8 @@ +#include + +/* TODO */ + +int rename(const char * oldpath, const char * newpath) { + /* Unsupported */ + return -1; +} diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c new file mode 100644 index 00000000..a21c59e5 --- /dev/null +++ b/libc/stdio/stdio.c @@ -0,0 +1,408 @@ +#include +#include +#include +#include +#include +#include +#include + +#include <_xlog.h> + +struct _FILE { + int fd; + + char * read_buf; + int available; + int offset; + int read_from; + int ungetc; + int eof; + int bufsiz; +}; + +FILE _stdin = { + .fd = 0, + .read_buf = NULL, + .available = 0, + .offset = 0, + .read_from = 0, + .ungetc = -1, + .eof = 0, + .bufsiz = BUFSIZ, +}; + +FILE _stdout = { + .fd = 1, + .read_buf = NULL, + .available = 0, + .offset = 0, + .read_from = 0, + .ungetc = -1, + .eof = 0, + .bufsiz = BUFSIZ, +}; + +FILE _stderr = { + .fd = 2, + .read_buf = NULL, + .available = 0, + .offset = 0, + .read_from = 0, + .ungetc = -1, + .eof = 0, + .bufsiz = BUFSIZ, +}; + +FILE * stdin = &_stdin; +FILE * stdout = &_stdout; +FILE * stderr = &_stderr; + +void __stdio_init_buffers(void) { + _stdin.read_buf = malloc(BUFSIZ); + //_stdout.read_buf = malloc(BUFSIZ); + //_stderr.read_buf = malloc(BUFSIZ); +} + +#if 0 +static char * stream_id(FILE * stream) { + static char out[] = "stream\0\0\0\0\0\0"; + if (stream == &_stdin) return "stdin"; + if (stream == &_stdout) return "stdout"; + if (stream == &_stderr) return "stderr"; + sprintf(out, "stream %d", fileno(stream)); + return out; +} +#endif + +extern char * _argv_0; + +int setvbuf(FILE * stream, char * buf, int mode, size_t size) { + if (mode != _IOLBF) { + return -1; /* Unsupported */ + } + if (buf) { + if (stream->read_buf) { + free(stream->read_buf); + } + stream->read_buf = buf; + stream->bufsiz = size; + } + return 0; +} + +static size_t read_bytes(FILE * f, char * out, size_t len) { + size_t r_out = 0; + + //fprintf(stderr, "%s: Read %d bytes from %s\n", _argv_0, len, stream_id(f)); + //fprintf(stderr, "%s: off[%d] avail[%d] read[%d]\n", _argv_0, f->offset, f->available, f->read_from); + + while (len > 0) { + if (f->ungetc >= 0) { + *out = f->ungetc; + len--; + out++; + r_out++; + f->ungetc = -1; + continue; + } + + if (f->available == 0) { + if (f->offset == f->bufsiz) { + f->offset = 0; + } + ssize_t r = read(fileno(f), &f->read_buf[f->offset], f->bufsiz - f->offset); + if (r < 0) { + //fprintf(stderr, "error condition\n"); + return r_out; + } else { + f->read_from = f->offset; + f->available = r; + f->offset += f->available; + } + } + + if (f->available == 0) { + /* EOF condition */ + //fprintf(stderr, "%s: no bytes available, returning read value of %d\n", _argv_0, r_out); + f->eof = 1; + return r_out; + } + + //fprintf(stderr, "%s: reading until %d reaches %d or %d reaches 0\n", _argv_0, f->read_from, f->offset, len); + while (f->read_from < f->offset && len > 0 && f->available > 0) { + *out = f->read_buf[f->read_from]; + len--; + f->read_from++; + f->available--; + out++; + r_out += 1; + } + } + + //fprintf(stderr, "%s: read completed, returning read value of %d\n", _argv_0, r_out); + return r_out; +} + +static void parse_mode(const char * mode, int * flags_, int * mask_) { + const char * x = mode; + + int flags = 0; + int mask = 0644; + + while (*x) { + if (*x == 'a') { + flags |= O_WRONLY; + flags |= O_APPEND; + flags |= O_CREAT; + } + if (*x == 'w') { + flags |= O_WRONLY; + flags |= O_CREAT; + flags |= O_TRUNC; + mask = 0666; + } + if (*x == '+') { + flags |= O_RDWR; + flags &= ~(O_APPEND); /* uh... */ + } + ++x; + } + + *flags_ = flags; + *mask_ = mask; +} + + +FILE * fopen(const char *path, const char *mode) { + + int flags, mask; + parse_mode(mode, &flags, &mask); + int fd = syscall_open(path, flags, mask); + + if (fd < 0) { + errno = -fd; + return NULL; + } + + FILE * out = malloc(sizeof(FILE)); + out->fd = fd; + out->read_buf = malloc(BUFSIZ); + out->bufsiz = BUFSIZ; + out->available = 0; + out->read_from = 0; + out->offset = 0; + out->ungetc = -1; + out->eof = 0; + + return out; +} + +/* This is very wrong */ +FILE * freopen(const char *path, const char *mode, FILE * stream) { + + if (path) { + if (stream) { + fclose(stream); + } + int flags, mask; + parse_mode(mode, &flags, &mask); + int fd = syscall_open(path, flags, mask); + stream->fd = fd; + stream->available = 0; + stream->read_from = 0; + stream->offset = 0; + stream->ungetc = -1; + stream->eof = 0; + if (fd < 0) { + errno = -fd; + return NULL; + } + } + + return stream; +} + +int ungetc(int c, FILE * stream) { + if (stream->ungetc > 0) + return EOF; + + return (stream->ungetc = c); +} + +FILE * fdopen(int fd, const char *mode){ + FILE * out = malloc(sizeof(FILE)); + out->fd = fd; + out->read_buf = malloc(BUFSIZ); + out->bufsiz = BUFSIZ; + out->available = 0; + out->read_from = 0; + out->offset = 0; + out->ungetc = -1; + out->eof = 0; + + return out; +} + +int _fwouldblock(FILE * stream) { + return !stream->available; +} + +int fclose(FILE * stream) { + int out = syscall_close(stream->fd); + free(stream->read_buf); + if (stream == &_stdin || stream == &_stdout || stream == &_stderr) { + return out; + } else { + free(stream); + return out; + } +} + +int fseek(FILE * stream, long offset, int whence) { + //fprintf(stderr, "%s: seek called, resetting\n", _argv_0); + stream->offset = 0; + stream->read_from = 0; + stream->available = 0; + stream->ungetc = -1; + stream->eof = 0; + + int resp = syscall_lseek(stream->fd,offset,whence); + if (resp < 0) { + errno = -resp; + return -1; + } + return 0; +} + +long ftell(FILE * stream) { + //fprintf(stderr, "%s: tell called, resetting\n", _argv_0); + stream->offset = 0; + stream->read_from = 0; + stream->available = 0; + stream->ungetc = -1; + stream->eof = 0; + long resp = syscall_lseek(stream->fd, 0, SEEK_CUR); + if (resp < 0) { + errno = -resp; + return -1; + } + return resp; +} + +size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream) { + char * tracking = (char*)ptr; + for (size_t i = 0; i < nmemb; ++i) { + int r = read_bytes(stream, tracking, size); + if (r < 0) { + return -1; + } + tracking += r; + if (r < (int)size) { + return i; + } + } + return nmemb; +} + +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE * stream) { + size_t out_size = size * nmemb; + + int r = syscall_write(stream->fd, (void*)ptr, out_size); + if (r < 0) { + errno = -r; + return -1; + } + + return r / size; +} + +int fileno(FILE * stream) { + return stream->fd; +} + +int fflush(FILE * stream) { + return 0; +} + +int fputs(const char *s, FILE *stream) { + fwrite(s, strlen(s), 1, stream); + /* eof? */ + return 0; +} + +int fputc(int c, FILE *stream) { + char data[] = {c}; + fwrite(data, 1, 1, stream); + return c; +} + +int putc(int c, FILE *stream) __attribute__((weak, alias("fputc"))); + +int fgetc(FILE * stream) { + char buf[1]; + int r; + r = fread(buf, 1, 1, stream); + if (r < 0) { + stream->eof = 1; + return EOF; + } else if (r == 0) { + stream->eof = 1; + return EOF; + } + return (unsigned char)buf[0]; +} + +int getc(FILE * stream) __attribute__((weak, alias("fgetc"))); + +int getchar(void) { + return fgetc(stdin); +} + +char *fgets(char *s, int size, FILE *stream) { + int c; + char * out = s; + while ((c = fgetc(stream)) > 0) { + *s++ = c; + size--; + if (size == 0) { + return out; + } + *s = '\0'; + if (c == '\n') { + return out; + } + } + if (c == EOF) { + stream->eof = 1; + if (out == s) { + return NULL; + } else { + return out; + } + } + return NULL; +} + +int putchar(int c) { + return fputc(c, stdout); +} + +void rewind(FILE *stream) { + fseek(stream, 0, SEEK_SET); +} + +void setbuf(FILE * stream, char * buf) { + // ... +} + +int feof(FILE * stream) { + return stream->eof; +} + +void clearerr(FILE * stream) { + stream->eof = 0; +} + +int ferror(FILE * stream) { + return 0; /* TODO */ +} diff --git a/libc/stdio/tmpfile.c b/libc/stdio/tmpfile.c new file mode 100644 index 00000000..eb35c6ab --- /dev/null +++ b/libc/stdio/tmpfile.c @@ -0,0 +1,15 @@ +#include +#include + +FILE * tmpfile(void) { + static int tmpfile_num = 1; + + char tmp[100]; + sprintf(tmp, "/tmp/tmp%d.%d", getpid(), tmpfile_num++); + + FILE * out = fopen(tmp, "w+b"); + + unlink(tmp); + + return out; +} diff --git a/libc/stdio/tmpnam.c b/libc/stdio/tmpnam.c new file mode 100644 index 00000000..53a42305 --- /dev/null +++ b/libc/stdio/tmpnam.c @@ -0,0 +1,16 @@ +#include +#include + +static char _internal[L_tmpnam]; + +char * tmpnam(char * s) { + static int tmp_id = 1; + + if (!s) { + s = _internal; + } + + sprintf(s, "/tmp/tmp%d.%d", getpid(), tmp_id++); + + return s; +} diff --git a/libc/stdlib/abort.c b/libc/stdlib/abort.c new file mode 100644 index 00000000..0da7cb08 --- /dev/null +++ b/libc/stdlib/abort.c @@ -0,0 +1,7 @@ +#include +#include + +void abort(void) { + syscall_exit(-1); + __builtin_unreachable(); +} diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c new file mode 100644 index 00000000..cb4969cd --- /dev/null +++ b/libc/stdlib/atexit.c @@ -0,0 +1,19 @@ +#include + +static void (*_atexit_handlers[32])(void) = {NULL}; +static int _atexit_count = 0; + +void _handle_atexit(void) { + if (!_atexit_count) return; + do { + _atexit_count--; + _atexit_handlers[_atexit_count](); + } while (_atexit_count); +} + +int atexit(void (*h)(void)) { + if (_atexit_count == ATEXIT_MAX) return 1; + _atexit_handlers[_atexit_count++] = h; + return 0; +} + diff --git a/libc/stdlib/atof.c b/libc/stdlib/atof.c new file mode 100644 index 00000000..b36693e9 --- /dev/null +++ b/libc/stdlib/atof.c @@ -0,0 +1,7 @@ +/* Really bad atof */ + +#include + +double atof(const char * nptr) { + return strtod(nptr, NULL); +} diff --git a/libc/stdlib/getenv.c b/libc/stdlib/getenv.c new file mode 100644 index 00000000..563fb9f5 --- /dev/null +++ b/libc/stdlib/getenv.c @@ -0,0 +1,19 @@ +#include +#include + +extern char ** environ; + +char * getenv(const char *name) { + char ** e = environ; + size_t len = strlen(name); + while (*e) { + char * t = *e; + if (strstr(t, name) == *e) { + if (t[len] == '=') { + return &t[len+1]; + } + } + e++; + } + return NULL; +} diff --git a/libc/stdlib/labs.c b/libc/stdlib/labs.c new file mode 100644 index 00000000..893b9c13 --- /dev/null +++ b/libc/stdlib/labs.c @@ -0,0 +1,3 @@ +long int labs(long int j) { + return (j < 0) ? -j : j; +} diff --git a/toolchain/patches/newlib/toaru/klmalloc.c b/libc/stdlib/malloc.c similarity index 92% rename from toolchain/patches/newlib/toaru/klmalloc.c rename to libc/stdlib/malloc.c index c7dd79f1..728ef222 100644 --- a/toolchain/patches/newlib/toaru/klmalloc.c +++ b/libc/stdlib/malloc.c @@ -1,6 +1,6 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * - * Kevin Lange's Slab Allocator + * klange's Slab Allocator * * Implemented for CS241, Fall 2010, machine problem 7 * at the University of Illinois, Urbana-Champaign. @@ -8,9 +8,9 @@ * Overall competition winner for speed. * Well ranked in memory usage. * - * Copyright (c) 2010 Kevin Lange. All rights reserved. + * Copyright (c) 2010-2018 K. Lange. All rights reserved. * - * Developed by: Kevin Lange + * Developed by: K. Lange * Dave Majnemer * Assocation for Computing Machinery * University of Illinois, Urbana-Champaign @@ -106,9 +106,12 @@ #include #include #include +#include /* }}} */ /* Definitions {{{ */ +#define sbrk syscall_sbrk + /* * Defines for often-used integral values * related to our binning and paging strategy. @@ -189,7 +192,7 @@ void free(void * ptr) { /* * Adjust bin size in bin_size call to proper bounds. */ -static uintptr_t __attribute__ ((always_inline, pure)) klmalloc_adjust_bin(uintptr_t bin) +static inline uintptr_t __attribute__ ((always_inline, pure)) klmalloc_adjust_bin(uintptr_t bin) { if (bin <= (uintptr_t)SMALLEST_BIN_LOG) { @@ -206,7 +209,7 @@ static uintptr_t __attribute__ ((always_inline, pure)) klmalloc_adjust_bin(uint * Given a size value, find the correct bin * to place the requested allocation in. */ -static uintptr_t __attribute__ ((always_inline, pure)) klmalloc_bin_size(uintptr_t size) { +static inline uintptr_t __attribute__ ((always_inline, pure)) klmalloc_bin_size(uintptr_t size) { uintptr_t bin = sizeof(size) * CHAR_BIT - __builtin_clzl(size); bin += !!(size & (size - 1)); return klmalloc_adjust_bin(bin); @@ -267,7 +270,7 @@ static klmalloc_big_bin_header * klmalloc_newest_big = NULL; /* Newest big bin * position in the list by linking * its neighbors to eachother. */ -static void __attribute__ ((always_inline)) klmalloc_list_decouple(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { +static inline void __attribute__ ((always_inline)) klmalloc_list_decouple(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { klmalloc_bin_header *next = node->next; head->first = next; node->next = NULL; @@ -280,7 +283,7 @@ static void __attribute__ ((always_inline)) klmalloc_list_decouple(klmalloc_bin_ * elements are updated to point back * to it (our list is doubly linked). */ -static void __attribute__ ((always_inline)) klmalloc_list_insert(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { +static inline void __attribute__ ((always_inline)) klmalloc_list_insert(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { node->next = head->first; head->first = node; } @@ -291,7 +294,7 @@ static void __attribute__ ((always_inline)) klmalloc_list_insert(klmalloc_bin_he * are really great, and just in case * we change the list implementation. */ -static klmalloc_bin_header * __attribute__ ((always_inline)) klmalloc_list_head(klmalloc_bin_header_head *head) { +static inline klmalloc_bin_header * __attribute__ ((always_inline)) klmalloc_list_head(klmalloc_bin_header_head *head) { return head->first; } @@ -327,7 +330,7 @@ static uint32_t __attribute__ ((pure)) klmalloc_skip_rand(void) { /* * Generate a random level for a skip node */ -static int __attribute__ ((pure, always_inline)) klmalloc_random_level(void) { +static inline int __attribute__ ((pure, always_inline)) klmalloc_random_level(void) { int level = 0; /* * Keep trying to check rand() against 50% of its maximum. @@ -569,7 +572,7 @@ static void klmalloc_stack_push(klmalloc_bin_header *header, void *ptr) { * stack, so there is no more free * space available in the block. */ -static int __attribute__ ((always_inline)) klmalloc_stack_empty(klmalloc_bin_header *header) { +static inline int __attribute__ ((always_inline)) klmalloc_stack_empty(klmalloc_bin_header *header) { return header->head == NULL; } @@ -981,21 +984,3 @@ static void * __attribute__ ((malloc)) klcalloc(uintptr_t nmemb, uintptr_t size) /* }}} */ -/* newlib stuff {{{ */ -void * _malloc_r (struct _reent *ptr, size_t size) { - (void)ptr; - return malloc (size); -} -void * _calloc_r (struct _reent *ptr, size_t nmemb, size_t size) { - (void)ptr; - return calloc (nmemb, size); -} -void _free_r (struct _reent *ptr, void *p) { - (void)ptr; - free(p); -} -void * _realloc_r (struct _reent *ptr, void *p, size_t size) { - (void)ptr; - return realloc(p, size); -} -/* }}} */ diff --git a/libc/stdlib/putenv.c b/libc/stdlib/putenv.c new file mode 100644 index 00000000..df7dc659 --- /dev/null +++ b/libc/stdlib/putenv.c @@ -0,0 +1,84 @@ +#include +#include +#include + +extern char ** environ; +extern int _environ_size; + +static int why_no_strnstr(char * a, char * b, int n) { + for (int i = 0; (i < n) && (a[i]) && (b[i]); ++i) { + if (a[i] != b[i]) { + return 1; + } + } + return 0; +} + +int unsetenv(const char * str) { + int last_index = -1; + int found_index = -1; + int len = strlen(str); + + for (int i = 0; environ[i]; ++i) { + if (found_index == -1 && (strstr(environ[i], str) == environ[i] && environ[i][len] == '=')) { + found_index = i; + } + last_index = i; + } + + if (found_index == -1) { + /* not found = success */ + return 0; + } + + if (last_index == found_index) { + /* Was last element */ + environ[last_index] = NULL; + return 0; + } + + /* Was not last element, swap ordering */ + environ[found_index] = environ[last_index]; + environ[last_index] = NULL; + return 0; +} + + +int putenv(char * string) { + char name[strlen(string)]; + strcpy(name, string); + char * c = strchr(name, '='); + if (!c) { + return 1; + } + *c = NULL; + + int s = strlen(name); + + int i; + for (i = 0; i < (_environ_size - 1) && environ[i]; ++i) { + if (!why_no_strnstr(name, environ[i], s) && environ[i][s] == '=') { + environ[i] = string; + return 0; + } + } + /* Not found */ + if (i == _environ_size - 1) { + int _new_environ_size = _environ_size * 2; + char ** new_environ = malloc(sizeof(char*) * _new_environ_size); + int j = 0; + while (j < _new_environ_size && environ[j]) { + new_environ[j] = environ[j]; + j++; + } + while (j < _new_environ_size) { + new_environ[j] = NULL; + j++; + } + _environ_size = _new_environ_size; + environ = new_environ; + } + + environ[i] = string; + return 0; +} diff --git a/libc/stdlib/qsort.c b/libc/stdlib/qsort.c new file mode 100644 index 00000000..8924de09 --- /dev/null +++ b/libc/stdlib/qsort.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +void qsort(void * base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { + for (size_t i = 0; i < nmemb-1; ++i) { + for (size_t j = 0; j < nmemb-1; ++j) { + void * left = (char *)base + size * j; + void * right = (char *)base + size * (j + 1); + if (compar(left,right) > 0) { + char tmp[size]; + memcpy(tmp, right, size); + memcpy(right, left, size); + memcpy(left, tmp, size); + } + } + } +} diff --git a/libc/stdlib/rand.c b/libc/stdlib/rand.c new file mode 100644 index 00000000..d8928b2c --- /dev/null +++ b/libc/stdlib/rand.c @@ -0,0 +1,20 @@ +#include +#include +#include + +static uint32_t x = 123456789; +static uint32_t y = 362436069; +static uint32_t z = 521288629; +static uint32_t w = 88675123; + +int rand(void) { + uint32_t t; + + t = x ^ (x << 11); + x = y; y = z; z = w; + return abs(w = w ^ (w >> 19) ^ t ^ (t >> 8)); +} + +void srand(unsigned int seed) { + w ^= seed; +} diff --git a/libc/stdlib/setenv.c b/libc/stdlib/setenv.c new file mode 100644 index 00000000..5625a628 --- /dev/null +++ b/libc/stdlib/setenv.c @@ -0,0 +1,16 @@ +#include +#include + +int setenv(const char *name, const char *value, int overwrite) { + if (!overwrite) { + char * tmp = getenv(name); + if (tmp) + return 0; + } + char * tmp = malloc(strlen(name) + strlen(value) + 2); + *tmp = '\0'; + strcat(tmp, name); + strcat(tmp, "="); + strcat(tmp, value); + return putenv(tmp); +} diff --git a/libc/stdlib/strtod.c b/libc/stdlib/strtod.c new file mode 100644 index 00000000..a405f889 --- /dev/null +++ b/libc/stdlib/strtod.c @@ -0,0 +1,74 @@ +#include +#include +#include + +double strtod(const char *nptr, char **endptr) { + int sign = 1; + if (*nptr == '-') { + sign = -1; + nptr++; + } + + long long decimal_part = 0; + + while (*nptr && *nptr != '.') { + if (*nptr < '0' || *nptr > '9') { + break; + } + decimal_part *= 10LL; + decimal_part += (long long)(*nptr - '0'); + nptr++; + } + + double sub_part = 0; + double multiplier = 0.1; + + if (*nptr == '.') { + nptr++; + + while (*nptr) { + if (*nptr < '0' || *nptr > '9') { + break; + } + + sub_part += multiplier * (*nptr - '0'); + multiplier *= 0.1; + nptr++; + } + } + + double expn = (double)sign; + + if (*nptr == 'e' || *nptr == 'E') { + nptr++; + + int exponent_sign = 1; + + if (*nptr == '+') { + nptr++; + } else if (*nptr == '-') { + exponent_sign = -1; + nptr++; + } + + int exponent = 0; + + while (*nptr) { + if (*nptr < '0' || *nptr > '9') { + break; + } + exponent *= 10; + exponent += (*nptr - '0'); + nptr++; + } + + expn = pow(10.0,(double)(exponent * exponent_sign)); + } + + if (endptr) { + *endptr = (char *)nptr; + } + double result = ((double)decimal_part + sub_part) * expn; + return result; +} + diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c new file mode 100644 index 00000000..47b34021 --- /dev/null +++ b/libc/stdlib/system.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +int system(const char * command) { + char * args[] = { + "/bin/sh", + "-c", + (char *)command, + NULL, + }; + pid_t pid = fork(); + if (!pid) { + execvp(args[0], args); + exit(1); + } else { + int status; + waitpid(pid, &status, 0); + return status; + } +} diff --git a/libc/string/memcpy.c b/libc/string/memcpy.c new file mode 100644 index 00000000..ff974cda --- /dev/null +++ b/libc/string/memcpy.c @@ -0,0 +1,9 @@ +#include + +void * memcpy(void * restrict dest, const void * restrict src, size_t n) { + asm volatile("cld; rep movsb" + : "=c"((int){0}) + : "D"(dest), "S"(src), "c"(n) + : "flags", "memory"); + return dest; +} diff --git a/libc/string/memmove.c b/libc/string/memmove.c new file mode 100644 index 00000000..1617f798 --- /dev/null +++ b/libc/string/memmove.c @@ -0,0 +1,52 @@ +#include +#include +#include + +void * memmove(void * dest, const void * src, size_t n) { + char * d = dest; + const char * s = src; + + if (d==s) { + return d; + } + + if (s+n <= d || d+n <= s) { + return memcpy(d, s, n); + } + + if (d= sizeof(size_t); n -= sizeof(size_t), d += sizeof(size_t), s += sizeof(size_t)) { + *(size_t *)d = *(size_t *)s; + } + } + for (; n; n--) { + *d++ = *s++; + } + } else { + if ((uintptr_t)s % sizeof(size_t) == (uintptr_t)d % sizeof(size_t)) { + while ((uintptr_t)(d+n) % sizeof(size_t)) { + if (!n--) { + return dest; + } + d[n] = s[n]; + } + while (n >= sizeof(size_t)) { + n -= sizeof(size_t); + *(size_t *)(d+n) = *(size_t *)(s+n); + } + } + while (n) { + n--; + d[n] = s[n]; + } + } + + return dest; +} diff --git a/libc/string/memset.c b/libc/string/memset.c new file mode 100644 index 00000000..e8b33c60 --- /dev/null +++ b/libc/string/memset.c @@ -0,0 +1,10 @@ +#include + +void * memset(void * dest, int c, size_t n) { + asm volatile("cld; rep stosb" + : "=c"((int){0}) + : "D"(dest), "a"(c), "c"(n) + : "flags", "memory"); + return dest; +} + diff --git a/libc/string/str.c b/libc/string/str.c new file mode 100644 index 00000000..51bbb8e3 --- /dev/null +++ b/libc/string/str.c @@ -0,0 +1,463 @@ +#include +#include +#include +#include +#include +#include + +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define MAX(A, B) ((A) > (B) ? (A) : (B)) + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(X) (((X)-ONES) & ~(X) & HIGHS) + +#define BITOP(A, B, OP) \ + ((A)[(size_t)(B)/(8*sizeof *(A))] OP (size_t)1<<((size_t)(B)%(8*sizeof *(A)))) + +int memcmp(const void * vl, const void * vr, size_t n) { + const unsigned char *l = vl; + const unsigned char *r = vr; + for (; n && *l == *r; n--, l++, r++); + return n ? *l-*r : 0; +} + +void * memchr(const void * src, int c, size_t n) { + const unsigned char * s = src; + c = (unsigned char)c; + for (; ((uintptr_t)s & (ALIGN - 1)) && n && *s != c; s++, n--); + if (n && *s != c) { + const size_t * w; + size_t k = ONES * c; + for (w = (const void *)s; n >= sizeof(size_t) && !HASZERO(*w^k); w++, n -= sizeof(size_t)); + for (s = (const void *)w; n && *s != c; s++, n--); + } + return n ? (void *)s : 0; +} + +void * memrchr(const void * m, int c, size_t n) { + const unsigned char * s = m; + c = (unsigned char)c; + while (n--) { + if (s[n] == c) { + return (void*)(s+n); + } + } + return 0; +} + +int strcasecmp(const char * s1, const char * s2) { + for (; tolower(*s1) == tolower(*s2) && *s1; s1++, s2++); + return *(unsigned char *)s1 - *(unsigned char *)s2; +} + +int strcmp(const char * l, const char * r) { + for (; *l == *r && *l; l++, r++); + return *(unsigned char *)l - *(unsigned char *)r; +} + +int strcoll(const char * s1, const char * s2) { + return strcmp(s1,s2); /* TODO locales */ +} + +size_t strlen(const char * s) { + const char * a = s; + const size_t * w; + for (; (uintptr_t)s % ALIGN; s++) { + if (!*s) { + return s-a; + } + } + for (w = (const void *)s; !HASZERO(*w); w++); + for (s = (const void *)w; *s; s++); + return s-a; +} + +char * strdup(const char * s) { + size_t l = strlen(s); + return memcpy(malloc(l+1), s, l+1); +} + +char * stpcpy(char * restrict d, const char * restrict s) { + size_t * wd; + const size_t * ws; + + if ((uintptr_t)s % ALIGN == (uintptr_t)d % ALIGN) { + for (; (uintptr_t)s % ALIGN; s++, d++) { + if (!(*d = *s)) { + return d; + } + } + wd = (void *)d; + ws = (const void *)s; + for (; !HASZERO(*ws); *wd++ = *ws++); + d = (void *)wd; + s = (const void *)ws; + } + + for (; (*d=*s); s++, d++); + + return d; +} + +char * strcpy(char * restrict dest, const char * restrict src) { + char * out = dest; + for (; (*dest=*src); src++, dest++); + return out; +} + +size_t strspn(const char * s, const char * c) { + const char * a = s; + size_t byteset[32/sizeof(size_t)] = { 0 }; + + if (!c[0]) { + return 0; + } + if (!c[1]) { + for (; *s == *c; s++); + return s-a; + } + + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++); + for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++); + + return s-a; +} + +char * strchrnul(const char * s, int c) { + size_t * w; + size_t k; + + c = (unsigned char)c; + if (!c) { + return (char *)s + strlen(s); + } + + for (; (uintptr_t)s % ALIGN; s++) { + if (!*s || *(unsigned char *)s == c) { + return (char *)s; + } + } + + k = ONES * c; + for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++); + for (s = (void *)w; *s && *(unsigned char *)s != c; s++); + return (char *)s; +} + +char * strchr(const char * s, int c) { + char *r = strchrnul(s, c); + return *(unsigned char *)r == (unsigned char)c ? r : 0; +} + +char * strrchr(const char * s, int c) { + return memrchr(s, c, strlen(s) + 1); +} + +size_t strcspn(const char * s, const char * c) { + const char *a = s; + if (c[0] && c[1]) { + size_t byteset[32/sizeof(size_t)] = { 0 }; + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++); + for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++); + return s-a; + } + return strchrnul(s, *c)-a; +} + +char * strpbrk(const char * s, const char * b) { + s += strcspn(s, b); + return *s ? (char *)s : 0; +} + +static char *strstr_2b(const unsigned char * h, const unsigned char * n) { + uint16_t nw = n[0] << 8 | n[1]; + uint16_t hw = h[0] << 8 | h[1]; + for (h++; *h && hw != nw; hw = hw << 8 | *++h); + return *h ? (char *)h-1 : 0; +} + +static char *strstr_3b(const unsigned char * h, const unsigned char * n) { + uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8; + uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8; + for (h += 2; *h && hw != nw; hw = (hw|*++h) << 8); + return *h ? (char *)h-2 : 0; +} + +static char *strstr_4b(const unsigned char * h, const unsigned char * n) { + uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; + for (h += 3; *h && hw != nw; hw = hw << 8 | *++h); + return *h ? (char *)h-3 : 0; +} + +static char *strstr_twoway(const unsigned char * h, const unsigned char * n) { + size_t mem; + size_t mem0; + size_t byteset[32 / sizeof(size_t)] = { 0 }; + size_t shift[256]; + size_t l; + + /* Computing length of needle and fill shift table */ + for (l = 0; n[l] && h[l]; l++) { + BITOP(byteset, n[l], |=); + shift[n[l]] = l+1; + } + + if (n[l]) { + return 0; /* hit the end of h */ + } + + /* Compute maximal suffix */ + size_t ip = -1; + size_t jp = 0; + size_t k = 1; + size_t p = 1; + while (jp+k n[jp+k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + size_t ms = ip; + size_t p0 = p; + + /* And with the opposite comparison */ + ip = -1; + jp = 0; + k = p = 1; + while (jp+k ms+1) { + ms = ip; + } else { + p = p0; + } + + /* Periodic needle? */ + if (memcmp(n, n+p, ms+1)) { + mem0 = 0; + p = MAX(ms, l-ms-1) + 1; + } else { + mem0 = l-p; + } + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + const unsigned char * z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if ((size_t)(z-h) < l) { + /* Fast estimate for MIN(l,63) */ + size_t grow = l | 63; + const unsigned char *z2 = memchr(z, 0, grow); + if (z2) { + z = z2; + if ((size_t)(z-h) < l) { + return 0; + } + } else { + z += grow; + } + } + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l-1], &)) { + k = l-shift[h[l-1]]; + if (k) { + if (mem0 && mem && k < p) k = l-p; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++); + if (n[k]) { + h += k-ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--); + if (k <= mem) { + return (char *)h; + } + h += p; + mem = mem0; + } +} + +char *strstr(const char * h, const char * n) { + /* Return immediately on empty needle */ + if (!n[0]) { + return (char *)h; + } + + /* Use faster algorithms for short needles */ + h = strchr(h, *n); + if (!h || !n[1]) { + return (char *)h; + } + + if (!h[1]) return 0; + if (!n[2]) return strstr_2b((void *)h, (void *)n); + if (!h[2]) return 0; + if (!n[3]) return strstr_3b((void *)h, (void *)n); + if (!h[3]) return 0; + if (!n[4]) return strstr_4b((void *)h, (void *)n); + + /* Two-way on large needles */ + return strstr_twoway((void *)h, (void *)n); +} + +long atol(const char * s) { + int n = 0; + int neg = 0; + while (isspace(*s)) { + s++; + } + switch (*s) { + case '-': + neg = 1; + /* Fallthrough is intentional here */ + case '+': + s++; + } + while (isdigit(*s)) { + n = 10*n - (*s++ - '0'); + } + /* The sign order may look incorrect here but this is correct as n is calculated + * as a negative number to avoid overflow on INT_MAX. + */ + return neg ? n : -n; +} + +int atoi(const char * s) { + int n = 0; + int neg = 0; + while (isspace(*s)) { + s++; + } + switch (*s) { + case '-': + neg = 1; + /* Fallthrough is intentional here */ + case '+': + s++; + } + while (isdigit(*s)) { + n = 10*n - (*s++ - '0'); + } + /* The sign order may look incorrect here but this is correct as n is calculated + * as a negative number to avoid overflow on INT_MAX. + */ + return neg ? n : -n; +} + +long int strtol(const char * s, char **endptr, int base) { + int n = 0; + int neg = 0; + while (isspace(*s)) { + s++; + } + switch (*s) { + case '-': + neg = 1; + /* Fallthrough is intentional here */ + case '+': + s++; + } + while (isdigit(*s)) { + n = 10*n - (*s++ - '0'); + } + /* The sign order may look incorrect here but this is correct as n is calculated + * as a negative number to avoid overflow on INT_MAX. + */ + return neg ? n : -n; +} + +size_t lfind(const char * str, const char accept) { + return (size_t)strchr(str, accept); +} + +size_t rfind(const char * str, const char accept) { + return (size_t)strrchr(str, accept); +} + +char * strtok_r(char * str, const char * delim, char ** saveptr) { + char * token; + if (str == NULL) { + str = *saveptr; + } + str += strspn(str, delim); + if (*str == '\0') { + *saveptr = str; + return NULL; + } + token = str; + str = strpbrk(token, delim); + if (str == NULL) { + *saveptr = (char *)lfind(token, '\0'); + } else { + *str = '\0'; + *saveptr = str + 1; + } + return token; +} + +char * strtok(char * str, const char * delim) { + static char * saveptr = NULL; + if (str) { + saveptr = NULL; + } + return strtok_r(str, delim, &saveptr); +} + +char * strcat(char *dest, const char *src) { + char * end = dest; + while (*end != '\0') { + ++end; + } + while (*src) { + *end = *src; + end++; + src++; + } + *end = '\0'; + return dest; +} diff --git a/libc/string/strerror.c b/libc/string/strerror.c new file mode 100644 index 00000000..61ee1804 --- /dev/null +++ b/libc/string/strerror.c @@ -0,0 +1,126 @@ +#include +#include + +static char * _error_strings[256] = { + [EPERM] = "Not super-user", + [ENOENT] = "No such file or directory", + [ESRCH] = "No such process", + [EINTR] = "Interrupted system call", + [EIO] = "I/O error", + [ENXIO] = "No such device or address", + [E2BIG] = "Arg list too long", + [ENOEXEC] = "Exec format error", + [EBADF] = "Bad file number", + [ECHILD] = "No children", + [EAGAIN] = "No more processes", + [ENOMEM] = "Not enough core", + [EACCES] = "Permission denied", + [EFAULT] = "Bad address", + [ENOTBLK] = "Block device required", + [EBUSY] = "Mount device busy", + [EEXIST] = "File exists", + [EXDEV] = "Cross-device link", + [ENODEV] = "No such device", + [ENOTDIR] = "Not a directory", + [EISDIR] = "Is a directory", + [EINVAL] = "Invalid argument", + [ENFILE] = "Too many open files in system", + [EMFILE] = "Too many open files", + [ENOTTY] = "Not a typewriter", + [ETXTBSY] = "Text file busy", + [EFBIG] = "File too large", + [ENOSPC] = "No space left on device", + [ESPIPE] = "Illegal seek", + [EROFS] = "Read only file system", + [EMLINK] = "Too many links", + [EPIPE] = "Broken pipe", + [EDOM] = "Math arg out of domain of func", + [ERANGE] = "Math result not representable", + [ENOMSG] = "No message of desired type", + [EIDRM] = "Identifier removed", + [ECHRNG] = "Channel number out of range", + [EL2NSYNC] = "Level 2 not synchronized", + [EL3HLT] = "Level 3 halted", + [EL3RST] = "Level 3 reset", + [ELNRNG] = "Link number out of range", + [EUNATCH] = "Protocol driver not attached", + [ENOCSI] = "No CSI structure available", + [EL2HLT] = "Level 2 halted", + [EDEADLK] = "Deadlock condition", + [ENOLCK] = "No record locks available", + [EBADE] = "Invalid exchange", + [EBADR] = "Invalid request descriptor", + [EXFULL] = "Exchange full", + [ENOANO] = "No anode", + [EBADRQC] = "Invalid request code", + [EBADSLT] = "Invalid slot", + [EDEADLOCK] = "File locking deadlock error", + [EBFONT] = "Bad font file fmt", + [ENOSTR] = "Device not a stream", + [ENODATA] = "No data (for no delay io)", + [ETIME] = "Timer expired", + [ENOSR] = "Out of streams resources", + [ENONET] = "Machine is not on the network", + [ENOPKG] = "Package not installed", + [EREMOTE] = "The object is remote", + [ENOLINK] = "The link has been severed", + [EADV] = "Advertise error", + [ESRMNT] = "Srmount error", + [ECOMM] = "Communication error on send", + [EPROTO] = "Protocol error", + [EMULTIHOP] = "Multihop attempted", + [ELBIN] = "Inode is remote (not really error)", + [EDOTDOT] = "Cross mount point (not really error)", + [EBADMSG] = "Trying to read unreadable message", + [EFTYPE] = "Inappropriate file type or format", + [ENOTUNIQ] = "Given log. name not unique", + [EBADFD] = "f.d. invalid for this operation", + [EREMCHG] = "Remote address changed", + [ELIBACC] = "Can't access a needed shared lib", + [ELIBBAD] = "Accessing a corrupted shared lib", + [ELIBSCN] = ".lib section in a.out corrupted", + [ELIBMAX] = "Attempting to link in too many libs", + [ELIBEXEC] = "Attempting to exec a shared library", + [ENOSYS] = "Function not implemented", + [ENOTEMPTY] = "Directory not empty", + [ENAMETOOLONG] = "File or path name too long", + [ELOOP] = "Too many symbolic links", + [EOPNOTSUPP] = "Operation not supported on transport endpoint", + [EPFNOSUPPORT] = "Protocol family not supported", + [ECONNRESET] = "Connection reset by peer", + [ENOBUFS] = "No buffer space available", + [EAFNOSUPPORT] = "Address family not supported by protocol family", + [EPROTOTYPE] = "Protocol wrong type for socket", + [ENOTSOCK] = "Socket operation on non-socket", + [ENOPROTOOPT] = "Protocol not available", + [ESHUTDOWN] = "Can't send after socket shutdown", + [ECONNREFUSED] = "Connection refused", + [EADDRINUSE] = "Address already in use", + [ECONNABORTED] = "Connection aborted", + [ENETUNREACH] = "Network is unreachable", + [ENETDOWN] = "Network interface is not configured", + [ETIMEDOUT] = "Connection timed out", + [EHOSTDOWN] = "Host is down", + [EHOSTUNREACH] = "Host is unreachable", + [EINPROGRESS] = "Connection already in progress", + [EALREADY] = "Socket already connected", + [EDESTADDRREQ] = "Destination address required", + [EMSGSIZE] = "Message too long", + [EPROTONOSUPPORT] = "Unknown protocol", + [ESOCKTNOSUPPORT] = "Socket type not supported", + [EADDRNOTAVAIL] = "Address not available", + [EISCONN] = "Socket is already connected", + [ENOTCONN] = "Socket is not connected", + [ENOTSUP] = "Not supported", + [EOVERFLOW] = "Value too large for defined data type", + [ECANCELED] = "Operation canceled", + [ENOTRECOVERABLE] = "State not recoverable", + [EOWNERDEAD] = "Previous owner died", + [ESTRPIPE] = "Streams pipe error", +}; + +char * strerror(int errnum) { + if (errnum > 255) return "???"; + if (!_error_strings[errnum]) return "???"; + return _error_strings[errnum]; +} diff --git a/libc/string/strncmp.c b/libc/string/strncmp.c new file mode 100644 index 00000000..2bd0f810 --- /dev/null +++ b/libc/string/strncmp.c @@ -0,0 +1,13 @@ +#include + +int strncmp(const char *s1, const char *s2, size_t n) { + size_t i = 0; + while (i < n && *s1 && *s2) { + if (*s1 < *s2) return -1; + if (*s1 > *s2) return 1; + s1++; + s2++; + i++; + } + return 0; +} diff --git a/libc/string/strncpy.c b/libc/string/strncpy.c new file mode 100644 index 00000000..a665b87d --- /dev/null +++ b/libc/string/strncpy.c @@ -0,0 +1,13 @@ +#include + +char * strncpy(char * dest, const char * src, size_t n) { + char * out = dest; + while (n > 0) { + if (!*src) break; + *out = *src; + ++out; + ++src; + --n; + } + return out; +} diff --git a/libc/sys/fswait.c b/libc/sys/fswait.c new file mode 100644 index 00000000..3777733c --- /dev/null +++ b/libc/sys/fswait.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +DEFN_SYSCALL2(fswait, SYS_FSWAIT, int, int *); +DEFN_SYSCALL3(fswait2, SYS_FSWAIT2, int, int *,int); + + +int fswait(int count, int * fds) { + __sets_errno(syscall_fswait(count, fds)); +} + +int fswait2(int count, int * fds, int timeout) { + __sets_errno(syscall_fswait2(count, fds, timeout)); +} diff --git a/libc/sys/mount.c b/libc/sys/mount.c new file mode 100644 index 00000000..65973bc6 --- /dev/null +++ b/libc/sys/mount.c @@ -0,0 +1,7 @@ +#include +#include + +int mount(char * source, char * target, char * type, unsigned long flags, void * data) { + __sets_errno(syscall_mount(source, target, type, flags, data)); +} + diff --git a/userspace/lib/network.c b/libc/sys/network.c similarity index 97% rename from userspace/lib/network.c rename to libc/sys/network.c index 41934a0d..0c149cba 100644 --- a/userspace/lib/network.c +++ b/libc/sys/network.c @@ -1,7 +1,5 @@ /* - * libnetwork - * - * Install me to /usr/lib/libnetwork.a + * socket methods (mostly unimplemented) */ #include #include @@ -10,8 +8,9 @@ #include #include #include +#include +#include -#include "network.h" static struct hostent _out_host = {0}; static struct in_addr * _out_host_vector[2] = {NULL, NULL}; @@ -124,3 +123,4 @@ int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t return -1; } + diff --git a/libc/sys/uname.c b/libc/sys/uname.c new file mode 100644 index 00000000..aaeae9a7 --- /dev/null +++ b/libc/sys/uname.c @@ -0,0 +1,8 @@ +#include +#include + +DEFN_SYSCALL1(uname, 12, void *); + +int uname(struct utsname *__name) { + return syscall_uname((void *)__name); +} diff --git a/libc/sys/wait.c b/libc/sys/wait.c new file mode 100644 index 00000000..454a50e9 --- /dev/null +++ b/libc/sys/wait.c @@ -0,0 +1,11 @@ +#include +#include + +int waitpid(int pid, int *status, int options) { + /* XXX: status, options? */ + __sets_errno(syscall_waitpid(pid, status, options)); +} + +int wait(int *status) { + return waitpid(-1, status, 0); +} diff --git a/libc/time/clock.c b/libc/time/clock.c new file mode 100644 index 00000000..e730efbc --- /dev/null +++ b/libc/time/clock.c @@ -0,0 +1,5 @@ +#include + +clock_t clock(void) { + return -1; +} diff --git a/libc/time/ctime.c b/libc/time/ctime.c new file mode 100644 index 00000000..a7cff4ba --- /dev/null +++ b/libc/time/ctime.c @@ -0,0 +1,9 @@ +#include +#include + +/* + * TODO: Also supposed to set tz values... + */ +char * ctime(const time_t * timep) { + return asctime(localtime(timep)); +} diff --git a/libc/time/gettimeofday.c b/libc/time/gettimeofday.c new file mode 100644 index 00000000..68a9389b --- /dev/null +++ b/libc/time/gettimeofday.c @@ -0,0 +1,7 @@ +#include +#include + +int gettimeofday(struct timeval *p, void *z){ + return syscall_gettimeofday(p,z); +} + diff --git a/libc/time/localtime.c b/libc/time/localtime.c new file mode 100644 index 00000000..3da3a34c --- /dev/null +++ b/libc/time/localtime.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#define SEC_DAY 86400 + +#define fprintf(...) + +static struct tm _timevalue; + +static int year_is_leap(int year) { + return ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))); +} + +// 0 was a Thursday + +static int day_of_week(long seconds) { + long day = seconds / SEC_DAY; + day += 4; + return day % 7; +} + +static long days_in_month(int month, int year) { + switch(month) { + case 11: + return 30; + case 10: + return 31; + case 9: + return 30; + case 8: + return 31; + case 7: + return 31; + case 6: + return 30; + case 5: + return 31; + case 4: + return 30; + case 3: + return 31; + case 2: + return year_is_leap(year) ? 29 : 28; + case 1: + return 31; + } + return 0; +} + +static long secs_of_month(int months, int year) { + long days = 0; + for (int i = 1; i < months; ++i) { + days += days_in_month(months, year); + } + return days * SEC_DAY; +} + +struct tm *localtime_r(const time_t *timep, struct tm * _timevalue) { + + fprintf(stderr, "Hello world? %p %d\n", _timevalue, *timep); + + long seconds = 0; // this needs to be bigger, but whatever + + long year_sec = 0; + + for (int year = 1970; year < 2100; ++year) { + fprintf(stderr, "Checking year %d\n", year); + long added = year_is_leap(year) ? 366 : 365; + fprintf(stderr, "adding %d...\n", added); + long secs = added * 86400; + + if (seconds + secs >= *timep + 1) { + _timevalue->tm_year = year - 1900; + year_sec = seconds; + fprintf(stderr, "The year is %d, year_sec=%d\n", year, year_sec); + for (int month = 1; month <= 12; ++month) { + fprintf(stderr, "Checking %d\n", month); + secs = days_in_month(month, year) * SEC_DAY; + fprintf(stderr, "%d vs %d\n", seconds + secs, *timep); + if (seconds + secs >= *timep) { + fprintf(stderr, "The month is %d.\n", month); + _timevalue->tm_mon = month - 1; + for (int day = 1; day <= days_in_month(month, year); ++day) { + secs = 60 * 60 * 24; + fprintf(stderr, "Checking day %d, %d vs . %d\n", day, seconds + secs, *timep); + if (seconds + secs >= *timep) { + fprintf(stderr, "The day is %d.\n", day); + _timevalue->tm_mday = day; + for (int hour = 1; hour <= 24; ++hour) { + secs = 60 * 60; + if (seconds + secs >= *timep) { + long remaining = *timep - seconds; + _timevalue->tm_hour = hour-1; + _timevalue->tm_min = remaining / 60; + _timevalue->tm_sec = remaining % 60; // can be 60 on a leap second, ignore that + _timevalue->tm_wday = day_of_week(*timep); // oh shit + _timevalue->tm_yday = (*timep - year_sec) / SEC_DAY; + _timevalue->tm_isdst = 0; // never because UTC + return _timevalue; + } else { + seconds += secs; + } + } + fprintf(stderr, "Failed but this is definitely the right day, returning NULL (seconds = %dbut need %d)\n", seconds, *timep); + return NULL; + } else { + seconds += secs; + } + } + fprintf(stderr, "Failed but this is definitely the right month, returning NULL\n"); + return NULL; + } else { + seconds += secs; + } + } + fprintf(stderr, "Failed but this is definitely the right year, returning NULL\n"); + return NULL; + } else { + seconds += secs; + } + } + + fprintf(stderr, "Uh, no?\n"); + return (void *)0; /// uh what +} + +static unsigned int secs_of_years(int years) { + unsigned int days = 0; + years += 2000; + while (years > 1969) { + days += 365; + if (year_is_leap(years)) { + days++; + } + years--; + } + return days * 86400; +} + + +time_t mktime(struct tm *tm) { + return + secs_of_years(tm->tm_year + 1900) + + secs_of_month(tm->tm_mon, tm->tm_year + 1900) + + (tm->tm_mday - 1) * 86400 + + (tm->tm_hour) * 3600 + + (tm->tm_min) * 60 + + (tm->tm_sec); + +} + +struct tm * gmtime_r(const time_t * timep, struct tm * tm) { + return localtime_r(timep, tm); +} + +struct tm * localtime(const time_t *timep) { + return localtime_r(timep, &_timevalue); +} + +struct tm *gmtime(const time_t *timep) { + return localtime(timep); +} + diff --git a/libc/time/strftime.c b/libc/time/strftime.c new file mode 100644 index 00000000..3fcd340d --- /dev/null +++ b/libc/time/strftime.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include + +static char * weekdays[] = { + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" +}; + +static char * weekdays_short[] = { + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" +}; + +static char * months[] = { + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" +}; + +static char * months_short[] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +size_t strftime(char *s, size_t max, const char *fmt, const struct tm *tm) { + char * b = s; + size_t count = 0; + for (const char *f = fmt; *f; f++) { + if (*f != '%') { + count++; + *b++ = *f; + if (count == max) return b - s; + continue; + } + ++f; + int _alte = 0; + int _alto = 0; + if (*f == 'E') { + _alte = 1; + ++f; + } else if (*f == '0') { + _alto = 1; + ++f; + } + (void)_alte; /* TODO: Implement these */ + (void)_alto; + switch (*f) { + case 'a': + b += sprintf(b, "%s", weekdays_short[tm->tm_wday]); + break; + case 'A': + b += sprintf(b, "%s", weekdays[tm->tm_wday]); + break; + case 'h': + case 'b': + b += sprintf(b, "%s", months_short[tm->tm_mon]); + break; + case 'B': + b += sprintf(b, "%s", months[tm->tm_mon]); + break; + case 'c': + b += sprintf(b, "%s %s %02d %02d:%02d:%02d %04d", + weekdays_short[tm->tm_wday], + months_short[tm->tm_mon], + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + tm->tm_year + 1900); + break; + case 'C': + b += sprintf(b, "%02d", (tm->tm_year + 1900) / 100); + break; + case 'd': + b += sprintf(b, "%02d", tm->tm_mday); + break; + case 'D': + b += sprintf(b, "%02d/%02d/%02d", tm->tm_mon+1, tm->tm_mday, tm->tm_year % 100); + break; + case 'e': + b += sprintf(b, "%2d", tm->tm_mday); + break; + case 'F': + b += sprintf(b, "%04d-%02d-%02d", tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday); + break; + case 'H': + b += sprintf(b, "%02d", tm->tm_hour); + break; + case 'I': + b += sprintf(b, "%02d", tm->tm_hour == 0 ? 12 : (tm->tm_hour == 12 ? 12 : (tm->tm_hour % 12))); + break; + case 'j': + b += sprintf(b, "%03d", tm->tm_yday); + break; + case 'k': + b += sprintf(b, "%2d", tm->tm_hour); + break; + case 'l': + b += sprintf(b, "%2d", tm->tm_hour == 0 ? 12 : (tm->tm_hour == 12 ? 12 : (tm->tm_hour % 12))); + break; + case 'm': + b += sprintf(b, "%02d", tm->tm_mon+1); + break; + case 'M': + b += sprintf(b, "%02d", tm->tm_min); + break; + case 'n': + b += sprintf(b, "\n"); + break; + case 'p': + b += sprintf(b, "%s", tm->tm_hour < 12 ? "AM" : "PM"); + break; + case 'P': + b += sprintf(b, "%s", tm->tm_hour < 12 ? "am" : "pm"); + break; + case 'r': + b += sprintf(b, "%02d:%02d:%02d %s", + tm->tm_hour == 0 ? 12 : (tm->tm_hour == 12 ? 12 : (tm->tm_hour % 12)), + tm->tm_min, + tm->tm_sec, + tm->tm_hour < 12 ? "AM" : "PM"); + break; + case 'R': + b += sprintf(b, "%02d:%02d", + tm->tm_hour, + tm->tm_min); + break; + case 'S': + b += sprintf(b, "%02d", tm->tm_sec); + break; + case 't': + b += sprintf(b, "\t"); + break; + case 'T': + b += sprintf(b, "%02d:%02d:%02d", + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + break; + case 'u': + b += sprintf(b, "%d", tm->tm_wday == 0 ? 7 : tm->tm_wday); + break; + case 'w': + b += sprintf(b, "%d", tm->tm_wday); + break; + case 'x': + b += sprintf(b, "%02d/%02d/%02d", tm->tm_mon+1, tm->tm_mday, tm->tm_year % 100); + break; + case 'X': + b += sprintf(b, "%02d:%02d:%02d", + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + break; + case 'y': + b += sprintf(b, "%02d", tm->tm_year % 100); + break; + case 'Y': + b += sprintf(b, "%04d", tm->tm_year + 1900); + break; + case 'z': + b += sprintf(b, "+0000"); + break; + case 'Z': + b += sprintf(b, "UTC"); + break; + case '%': + b += sprintf(b, "%c", '%'); + break; + case 'V': + case 'W': + case 's': + case 'U': + case 'G': + case 'g': + b += sprintf(b, "<%c unsupported>", *f); + break; + } + } + /* Ensure the buffer ends in a null */ + *b = '\0'; + return b - s; +} + +static char output[26]; +char * asctime(const struct tm *tm) { + strftime(output, 26, "%a %b %d %T %Y\n", tm); + return output; +} + diff --git a/libc/time/time.c b/libc/time/time.c new file mode 100644 index 00000000..159b0309 --- /dev/null +++ b/libc/time/time.c @@ -0,0 +1,15 @@ +#include +#include + +time_t time(time_t * out) { + struct timeval p; + gettimeofday(&p, NULL); + if (out) { + *out = p.tv_sec; + } + return p.tv_sec; +} + +double difftime(time_t a, time_t b) { + return (double)(a - b); +} diff --git a/libc/unistd/access.c b/libc/unistd/access.c new file mode 100644 index 00000000..71034526 --- /dev/null +++ b/libc/unistd/access.c @@ -0,0 +1,12 @@ +#include +#include +#include + +int access(const char *pathname, int mode) { + int result = syscall_access((char *)pathname, mode); + if (result < 0) { + errno = ENOENT; /* XXX */ + } + return result; +} + diff --git a/libc/unistd/chdir.c b/libc/unistd/chdir.c new file mode 100644 index 00000000..f1dbe949 --- /dev/null +++ b/libc/unistd/chdir.c @@ -0,0 +1,10 @@ +#include +#include +#include + +DEFN_SYSCALL1(chdir, 28, char *); + +int chdir(const char *path) { + __sets_errno(syscall_chdir((char*)path)); +} + diff --git a/libc/unistd/chmod.c b/libc/unistd/chmod.c new file mode 100644 index 00000000..21770a57 --- /dev/null +++ b/libc/unistd/chmod.c @@ -0,0 +1,10 @@ +#include +#include +#include + +DEFN_SYSCALL2(chmod, 50, char *, int); + +int chmod(const char *path, mode_t mode) { + __sets_errno(syscall_chmod((char *)path, mode)); +} + diff --git a/libc/unistd/chown.c b/libc/unistd/chown.c new file mode 100644 index 00000000..5476df72 --- /dev/null +++ b/libc/unistd/chown.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +DEFN_SYSCALL3(chown, SYS_CHOWN, char *, int, int); + +int chown(const char * pathname, uid_t owner, gid_t group) { + __sets_errno(syscall_chown((char*)pathname,owner,group)); +} + diff --git a/libc/unistd/close.c b/libc/unistd/close.c new file mode 100644 index 00000000..c74e2c7d --- /dev/null +++ b/libc/unistd/close.c @@ -0,0 +1,8 @@ +#include +#include + +DEFN_SYSCALL1(close, 5, int); + +int close(int file) { + return syscall_close(file); +} diff --git a/libc/unistd/creat.c b/libc/unistd/creat.c new file mode 100644 index 00000000..e02fbd57 --- /dev/null +++ b/libc/unistd/creat.c @@ -0,0 +1,6 @@ +#include +#include + +int creat(const char *path, mode_t mode) { + return open(path, O_WRONLY|O_CREAT|O_TRUNC, mode); +} diff --git a/libc/unistd/dup2.c b/libc/unistd/dup2.c new file mode 100644 index 00000000..5f4fceca --- /dev/null +++ b/libc/unistd/dup2.c @@ -0,0 +1,12 @@ +#include +#include + +DEFN_SYSCALL2(dup2, 22, int, int); + +int dup2(int oldfd, int newfd) { + return syscall_dup2(oldfd, newfd); +} + +int dup(int oldfd) { + return dup2(oldfd, -1); +} diff --git a/libc/unistd/execvp.c b/libc/unistd/execvp.c new file mode 100644 index 00000000..a2087368 --- /dev/null +++ b/libc/unistd/execvp.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +extern char ** environ; +extern char * getenv(char *); + +#define DEFAULT_PATH "/bin:/usr/bin" + +int execve(const char *name, char * const argv[], char * const envp[]) { + __sets_errno(syscall_execve((char*)name,(char**)argv,(char**)envp)); +} + +int execvp(const char *file, char *const argv[]) { + if (file && (!strstr(file, "/"))) { + /* We don't quite understand "$PATH", so... */ + char * path = getenv("PATH"); + if (!path) { + path = DEFAULT_PATH; + } + char * xpath = strdup(path); + char * p, * last; + for ((p = strtok_r(xpath, ":", &last)); p; p = strtok_r(NULL, ":", &last)) { + int r; + struct stat stat_buf; + char * exe = malloc(strlen(p) + strlen(file) + 2); + strcpy(exe, p); + strcat(exe, "/"); + strcat(exe, file); + + r = stat(exe, &stat_buf); + if (r != 0) { + continue; + } + if (!(stat_buf.st_mode & 0111)) { + continue; /* XXX not technically correct; need to test perms */ + } + return execve(exe, argv, environ); + } + free(xpath); + errno = ENOENT; + return -1; + } else if (file) { + return execve(file, argv, environ); + } + errno = ENOENT; + return -1; +} + +int execv(const char * file, char * const argv[]) { + return execve(file, argv, environ); +} diff --git a/libc/unistd/exit.c b/libc/unistd/exit.c new file mode 100644 index 00000000..2747e5f9 --- /dev/null +++ b/libc/unistd/exit.c @@ -0,0 +1,7 @@ +#include +#include + +void exit(int val) { + _handle_atexit(); + _exit(val); +} diff --git a/libc/unistd/fcntl.c b/libc/unistd/fcntl.c new file mode 100644 index 00000000..1a5fd4ea --- /dev/null +++ b/libc/unistd/fcntl.c @@ -0,0 +1,11 @@ +#include + +int fcntl(int fd, int cmd, ...) { + switch (cmd) { + case F_GETFD: + return 0; + case F_SETFD: + return 0; + } + return -1; +} diff --git a/libc/unistd/fork.c b/libc/unistd/fork.c new file mode 100644 index 00000000..6d235619 --- /dev/null +++ b/libc/unistd/fork.c @@ -0,0 +1,8 @@ +#include +#include + +DEFN_SYSCALL0(fork, 8); + +pid_t fork(void) { + return syscall_fork(); +} diff --git a/libc/unistd/fstat.c b/libc/unistd/fstat.c new file mode 100644 index 00000000..5a2b27cd --- /dev/null +++ b/libc/unistd/fstat.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include +#include + +DEFN_SYSCALL2(fstat, SYS_STAT, int, void *); + +int fstat(int file, struct stat *st) { + __sets_errno(syscall_fstat(file, st)); +} diff --git a/libc/unistd/getcwd.c b/libc/unistd/getcwd.c new file mode 100644 index 00000000..b4e0a778 --- /dev/null +++ b/libc/unistd/getcwd.c @@ -0,0 +1,11 @@ +#include +#include +#include + +DEFN_SYSCALL2(getcwd, 29, char *, size_t); + +char *getcwd(char *buf, size_t size) { + if (!buf) buf = malloc(size); + return (char *)syscall_getcwd(buf, size); +} + diff --git a/libc/unistd/getegid.c b/libc/unistd/getegid.c new file mode 100644 index 00000000..8d9ff7a3 --- /dev/null +++ b/libc/unistd/getegid.c @@ -0,0 +1,6 @@ +#include + +int getegid() { + return getgid(); +} + diff --git a/libc/unistd/geteuid.c b/libc/unistd/geteuid.c new file mode 100644 index 00000000..f7939c77 --- /dev/null +++ b/libc/unistd/geteuid.c @@ -0,0 +1,5 @@ +#include + +int geteuid() { + return getuid(); +} diff --git a/libc/unistd/getgid.c b/libc/unistd/getgid.c new file mode 100644 index 00000000..a29ae23e --- /dev/null +++ b/libc/unistd/getgid.c @@ -0,0 +1,5 @@ +#include + +int getgid() { + return getuid(); +} diff --git a/libc/unistd/getopt.c b/libc/unistd/getopt.c new file mode 100644 index 00000000..0cbdbfc2 --- /dev/null +++ b/libc/unistd/getopt.c @@ -0,0 +1,11 @@ +#include +#include + +char * optarg = NULL; +int optind = 1; +int opterr = 1; +int optopt = 0; + +int getopt(int argc, char * const argv[], const char * optstring) { + return getopt_long(argc, argv, optstring, NULL, 0); +} diff --git a/libc/unistd/getopt_long.c b/libc/unistd/getopt_long.c new file mode 100644 index 00000000..f7b64635 --- /dev/null +++ b/libc/unistd/getopt_long.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include + +/** + * getopt / getopt_long + */ + +int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex) { + static char * nextchar = NULL; + + if (optind >= argc) { + return -1; + } + + do { + if (!nextchar) { + nextchar = argv[optind]; + if (*nextchar != '-') { + return -1; + } else { + nextchar++; + + if (*nextchar == '\0') { + /* Special case - is a non-option argument */ + return -1; + } + + if (*nextchar == '-') { + if (nextchar[1] == '\0') { + /* End of arguments */ + optind++; + return -1; + } else if (longopts) { + /* Scan through options */ + nextchar++; + char tmp[strlen(nextchar)+1]; + strcpy(tmp, nextchar); + char * eq = strchr(tmp, '='); + if (eq) { + *eq = '\0'; + optarg = nextchar + (eq - tmp + 1); + } else { + optarg = NULL; + } + + int found = -1; + for (int index = 0; longopts[index].name; ++index) { + if (!strcmp(longopts[index].name, tmp)) { + found = index; + } + } + + if (found == -1) { + if (longindex) { + *longindex = -1; + } + if (opterr) { + fprintf(stderr, "unknown long argument: %s\n", tmp); + } + nextchar = NULL; + optind++; + optopt = '\0'; + return '?'; + } else { + if (longindex) { + *longindex = found; + } + if (longopts[found].has_arg == required_argument) { + if (!optarg) { + optarg = argv[optind+1]; + optind++; + } + } + nextchar = NULL; + optind++; + if (!longopts[found].flag) { + return longopts[found].val; + } else { + *longopts[found].flag = longopts[found].val; + return 0; + } + } + } + /* else: --foo but not long, see if -: is set, otherwise continue as if - was an option */ + } + } + } + + if (*nextchar == '\0') { + nextchar = NULL; + optind++; + continue; + } + + if ((*nextchar < 'A' || *nextchar > 'z' || (*nextchar > 'Z' && *nextchar < 'a')) && (*nextchar != '?') && (*nextchar != '-')) { + if (opterr) { + fprintf(stderr, "Invalid option character: %c\n", *nextchar); + } + optopt = *nextchar; + nextchar++; + return '?'; + } + + char * opt = strchr(optstring, *nextchar); + + if (!opt) { + if (opterr) { + fprintf(stderr, "Invalid option character: %c\n", *nextchar); + } + optopt = *nextchar; + nextchar++; + return '?'; + } + + int optout = *nextchar; + + if (opt[1] == ':') { + if (nextchar[1] != '\0') { + optarg = &nextchar[1]; + nextchar = NULL; + optind++; + } else { + optarg = argv[optind+1]; + optind += 2; + nextchar = NULL; + } + } else { + nextchar++; + } + + return optout; + + } while (optind < argc); + + return -1; +} diff --git a/libc/unistd/getpgrp.c b/libc/unistd/getpgrp.c new file mode 100644 index 00000000..94e8c5d4 --- /dev/null +++ b/libc/unistd/getpgrp.c @@ -0,0 +1,6 @@ +#include + +int getpgrp() { + /* XXX */ + return getgid(); +} diff --git a/libc/unistd/getpid.c b/libc/unistd/getpid.c new file mode 100644 index 00000000..7ecc84dc --- /dev/null +++ b/libc/unistd/getpid.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +DEFN_SYSCALL0(getpid, SYS_GETPID); + +pid_t getpid(void) { + return syscall_getpid(); +} + +pid_t getppid(void) { + errno = ENOTSUP; + return -1; +} diff --git a/libc/unistd/getuid.c b/libc/unistd/getuid.c new file mode 100644 index 00000000..aad66ce2 --- /dev/null +++ b/libc/unistd/getuid.c @@ -0,0 +1,8 @@ +#include +#include + +DEFN_SYSCALL0(getuid, 23); + +int getuid() { + return syscall_getuid(); +} diff --git a/libc/unistd/getwd.c b/libc/unistd/getwd.c new file mode 100644 index 00000000..2a63c20a --- /dev/null +++ b/libc/unistd/getwd.c @@ -0,0 +1,5 @@ +#include + +char *getwd(char *buf) { + return getcwd(buf, 256); +} diff --git a/libc/unistd/hostname.c b/libc/unistd/hostname.c new file mode 100644 index 00000000..92774b8e --- /dev/null +++ b/libc/unistd/hostname.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +DEFN_SYSCALL1(sethostname, SYS_SETHOSTNAME, char *); +DEFN_SYSCALL1(gethostname, SYS_GETHOSTNAME, char *); + +int gethostname(char * name, size_t len) { + (void)len; /* TODO */ + __sets_errno(syscall_gethostname(name)); +} + +int sethostname(const char * name, size_t len) { + (void)len; /* TODO */ + __sets_errno(syscall_sethostname((char*)name)); +} diff --git a/libc/unistd/isatty.c b/libc/unistd/isatty.c new file mode 100644 index 00000000..2899abd1 --- /dev/null +++ b/libc/unistd/isatty.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int isatty(int fd) { + int dtype = ioctl(fd, IOCTLDTYPE, NULL); + if (dtype == IOCTL_DTYPE_TTY) return 1; + errno = EINVAL; + return 0; +} diff --git a/libc/unistd/link.c b/libc/unistd/link.c new file mode 100644 index 00000000..1e2b31a7 --- /dev/null +++ b/libc/unistd/link.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO: +// We have a system call for this? +int link(const char *old, const char *new) { + errno = EMLINK; + return -1; +} diff --git a/libc/unistd/lseek.c b/libc/unistd/lseek.c new file mode 100644 index 00000000..a4fece91 --- /dev/null +++ b/libc/unistd/lseek.c @@ -0,0 +1,9 @@ +#include +#include + +DEFN_SYSCALL3(lseek, 14, int, int, int); + +off_t lseek(int file, off_t ptr, int dir) { + return syscall_lseek(file,ptr,dir); +} + diff --git a/libc/unistd/open.c b/libc/unistd/open.c new file mode 100644 index 00000000..615da433 --- /dev/null +++ b/libc/unistd/open.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +#include + +DEFN_SYSCALL3(open, 2, const char *, int, int); + +int open(const char *name, int flags, ...) { + va_list argp; + int mode = 0; + int result; + va_start(argp, flags); + if (flags & O_CREAT) mode = va_arg(argp, int); + va_end(argp); + + result = syscall_open(name, flags, mode); + if (result == -1) { + /* Not sure this is necessary */ + if (flags & O_CREAT) { + errno = EACCES; + } else { + errno = ENOENT; + } + } else if (result < 0) { + errno = -result; + result = -1; + } + return result; +} + diff --git a/libc/unistd/pipe.c b/libc/unistd/pipe.c new file mode 100644 index 00000000..f965c4d2 --- /dev/null +++ b/libc/unistd/pipe.c @@ -0,0 +1,9 @@ +#include +#include +#include + +DEFN_SYSCALL1(pipe, 54, int *); + +int pipe(int fildes[2]) { + __sets_errno(syscall_pipe((int *)fildes)); +} diff --git a/libc/unistd/read.c b/libc/unistd/read.c new file mode 100644 index 00000000..261e56ce --- /dev/null +++ b/libc/unistd/read.c @@ -0,0 +1,8 @@ +#include +#include + +DEFN_SYSCALL3(read, 3, int, char *, int); + +int read(int file, void *ptr, size_t len) { + return syscall_read(file,ptr,len); +} diff --git a/libc/unistd/readlink.c b/libc/unistd/readlink.c new file mode 100644 index 00000000..a175e697 --- /dev/null +++ b/libc/unistd/readlink.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +DEFN_SYSCALL3(readlink, SYS_READLINK, char *, char *, int); + +ssize_t readlink(const char * name, char * buf, size_t len) { + __sets_errno(syscall_readlink((char*)name, buf, len)); +} + diff --git a/libc/unistd/rmdir.c b/libc/unistd/rmdir.c new file mode 100644 index 00000000..01a48d33 --- /dev/null +++ b/libc/unistd/rmdir.c @@ -0,0 +1,7 @@ +#include +#include + +int rmdir(const char *pathname) { + errno = ENOTSUP; + return -1; +} diff --git a/libc/unistd/setuid.c b/libc/unistd/setuid.c new file mode 100644 index 00000000..49c447ff --- /dev/null +++ b/libc/unistd/setuid.c @@ -0,0 +1,8 @@ +#include +#include + +DEFN_SYSCALL1(setuid, 24, unsigned int); + +int setuid(uid_t uid) { + return syscall_setuid(uid); +} diff --git a/libc/unistd/sleep.c b/libc/unistd/sleep.c new file mode 100644 index 00000000..a2938f38 --- /dev/null +++ b/libc/unistd/sleep.c @@ -0,0 +1,7 @@ +#include + +unsigned int sleep(unsigned int seconds) { + syscall_nanosleep(seconds, 0); + return 0; +} + diff --git a/libc/unistd/stat.c b/libc/unistd/stat.c new file mode 100644 index 00000000..a09058d9 --- /dev/null +++ b/libc/unistd/stat.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +#ifndef syscall_lstat +DECL_SYSCALL2(lstat, char *, void *); +#endif + +int stat(const char *file, struct stat *st){ + int ret = syscall_stat((char *)file, (void *)st); + if (ret >= 0) { + return ret; + } else { + errno = ENOENT; /* meh */ + memset(st, 0x00, sizeof(struct stat)); + return ret;; + } +} + +int lstat(const char *path, struct stat *st) { + int ret = syscall_lstat((char *)path, (void *)st); + if (ret >= 0) { + return ret; + } else { + errno = -ret; + memset(st, 0x00, sizeof(struct stat)); + return ret; + } +} diff --git a/libc/unistd/symlink.c b/libc/unistd/symlink.c new file mode 100644 index 00000000..3aa014ba --- /dev/null +++ b/libc/unistd/symlink.c @@ -0,0 +1,12 @@ +#include +#include + +#include +#include + +DEFN_SYSCALL2(symlink, SYS_SYMLINK, const char *, const char *); + +int symlink(const char *target, const char *name) { + __sets_errno(syscall_symlink(target, name)); +} + diff --git a/libc/unistd/ttyname.c b/libc/unistd/ttyname.c new file mode 100644 index 00000000..ecf2fe93 --- /dev/null +++ b/libc/unistd/ttyname.c @@ -0,0 +1,7 @@ +#include +#include + +char * ttyname(int fd) { + errno = ENOTSUP; + return NULL; +} diff --git a/libc/unistd/umask.c b/libc/unistd/umask.c new file mode 100644 index 00000000..13f7665f --- /dev/null +++ b/libc/unistd/umask.c @@ -0,0 +1,9 @@ +#include +#include +#include + +DEFN_SYSCALL1(umask, SYS_UMASK, int); + +mode_t umask(mode_t mask) { + return syscall_umask(mask); +} diff --git a/libc/unistd/unlink.c b/libc/unistd/unlink.c new file mode 100644 index 00000000..7e2d64a9 --- /dev/null +++ b/libc/unistd/unlink.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +DEFN_SYSCALL1(unlink, SYS_UNLINK, char *); + +int unlink(const char * pathname) { + __sets_errno(syscall_unlink((char *)pathname)); +} diff --git a/libc/unistd/usleep.c b/libc/unistd/usleep.c new file mode 100644 index 00000000..d3612696 --- /dev/null +++ b/libc/unistd/usleep.c @@ -0,0 +1,10 @@ +#include +#include + +DEFN_SYSCALL2(nanosleep, 46, unsigned long, unsigned long); + +int usleep(useconds_t usec) { + syscall_nanosleep(0, usec / 10000); + return 0; +} + diff --git a/libc/unistd/utime.c b/libc/unistd/utime.c new file mode 100644 index 00000000..96b080c1 --- /dev/null +++ b/libc/unistd/utime.c @@ -0,0 +1,8 @@ +#include +#include + +int utime(const char *filename, const struct utimbuf *times) { + /* Unimplemented */ + errno = ENOTSUP; + return -1; +} diff --git a/libc/unistd/write.c b/libc/unistd/write.c new file mode 100644 index 00000000..a23e9f8c --- /dev/null +++ b/libc/unistd/write.c @@ -0,0 +1,8 @@ +#include +#include + +DEFN_SYSCALL3(write, 4, int, char *, int); + +ssize_t write(int file, const void *ptr, size_t len) { + return syscall_write(file,(char *)ptr,len); +} diff --git a/libc/wchar/wcs.c b/libc/wchar/wcs.c new file mode 100644 index 00000000..21f0c31e --- /dev/null +++ b/libc/wchar/wcs.c @@ -0,0 +1,27 @@ +#include + +size_t wcstombs(char * dest, const wchar_t *src, size_t n) { + /* TODO */ + size_t c = 0; + while (c < n && *src) { + *dest = *src; + c++; + src++; + dest++; + } + *dest = 0; + return c; +} + +size_t mbstowcs(wchar_t * dest, const char *src, size_t n) { + /* TODO */ + size_t c = 0; + while (c < n && *src) { + *dest = *src; + c++; + src++; + dest++; + } + *dest = 0; + return c; +} diff --git a/libc/wchar/wcscat.c b/libc/wchar/wcscat.c new file mode 100644 index 00000000..d0303de7 --- /dev/null +++ b/libc/wchar/wcscat.c @@ -0,0 +1,32 @@ +#include +#include + +wchar_t * wcscat(wchar_t *dest, const wchar_t *src) { + wchar_t * end = dest; + while (*end != 0) { + ++end; + } + while (*src) { + *end = *src; + end++; + src++; + } + *end = 0; + return dest; +} + +wchar_t * wcsncat(wchar_t *dest, const wchar_t * src, size_t n) { + wchar_t * end = dest; + size_t c = 0; + while (*end != 0) { + ++end; + } + while (*src && c < n) { + *end = *src; + end++; + src++; + c++; + } + *end = 0; + return dest; +} diff --git a/libc/wchar/wcscmp.c b/libc/wchar/wcscmp.c new file mode 100644 index 00000000..e2b4c3c4 --- /dev/null +++ b/libc/wchar/wcscmp.c @@ -0,0 +1,6 @@ +#include + +int wcscmp(const wchar_t *l, const wchar_t *r) { + for (; *l == *r && *l; l++, r++); + return *(unsigned int *)l - *(unsigned int *)r; +} diff --git a/libc/wchar/wcscpy.c b/libc/wchar/wcscpy.c new file mode 100644 index 00000000..ad244945 --- /dev/null +++ b/libc/wchar/wcscpy.c @@ -0,0 +1,7 @@ +#include + +wchar_t * wcscpy(wchar_t * restrict dest, const wchar_t * restrict src) { + wchar_t * out = dest; + for (; (*dest=*src); src++, dest++); + return out; +} diff --git a/libc/wchar/wcslen.c b/libc/wchar/wcslen.c new file mode 100644 index 00000000..ac778ca1 --- /dev/null +++ b/libc/wchar/wcslen.c @@ -0,0 +1,10 @@ +#include + +size_t wcslen(const wchar_t * s) { + size_t out = 0; + while (*s) { + out++; + s++; + } + return out; +} diff --git a/libc/wchar/wcsncpy.c b/libc/wchar/wcsncpy.c new file mode 100644 index 00000000..ae902363 --- /dev/null +++ b/libc/wchar/wcsncpy.c @@ -0,0 +1,13 @@ +#include + +wchar_t * wcsncpy(wchar_t * dest, const wchar_t * src, size_t n) { + wchar_t * out = dest; + while (n > 0) { + *dest = *src; + if (!*src) break; + dest++; + src++; + n--; + } + return out; +} diff --git a/libc/wchar/wcstok.c b/libc/wchar/wcstok.c new file mode 100644 index 00000000..fc907f66 --- /dev/null +++ b/libc/wchar/wcstok.c @@ -0,0 +1,74 @@ +#include + +size_t wcsspn(const wchar_t * wcs, const wchar_t * accept) { + size_t out = 0; + + while (*wcs) { + int good = 0; + for (const wchar_t * a = accept; *a; ++a) { + if (*wcs == *a) { + good = 1; + break; + } + } + if (!good) break; + out++; + wcs++; + } + + return out; +} + +wchar_t *wcspbrk(const wchar_t *wcs, const wchar_t *accept) { + while (*wcs) { + for (const wchar_t * a = accept; *a; ++a) { + if (*wcs == *a) { + return (wchar_t *)wcs; + } + } + wcs++; + } + return NULL; +} + +wchar_t * wcschr(const wchar_t *wcs, wchar_t wc) { + while (*wcs != wc && *wcs != 0) { + wcs++; + } + if (!*wcs) return NULL; + return (wchar_t *)wcs; +} + +wchar_t * wcsrchr(const wchar_t *wcs, wchar_t wc) { + wchar_t * last = NULL; + while (*wcs != 0) { + if (*wcs == wc) { + last = (wchar_t *)wcs; + } + wcs++; + } + return last; +} + +wchar_t * wcstok(wchar_t * str, const wchar_t * delim, wchar_t ** saveptr) { + wchar_t * token; + if (str == NULL) { + str = *saveptr; + } + str += wcsspn(str, delim); + if (*str == '\0') { + *saveptr = str; + return NULL; + } + token = str; + str = wcspbrk(token, delim); + if (str == NULL) { + *saveptr = (wchar_t *)wcschr(token, '\0'); + } else { + *str = '\0'; + *saveptr = str + 1; + } + return token; +} + + diff --git a/toolchain/patches/newlib/wcwidth.c b/libc/wchar/wcwidth.c similarity index 99% rename from toolchain/patches/newlib/wcwidth.c rename to libc/wchar/wcwidth.c index 503ad537..7055edc0 100644 --- a/toolchain/patches/newlib/wcwidth.c +++ b/libc/wchar/wcwidth.c @@ -1093,3 +1093,4 @@ int wcwidth(wchar_t wc) { return -1; } + diff --git a/linker/.gitignore b/linker/.gitignore deleted file mode 100644 index cc726bc3..00000000 --- a/linker/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.so -demo -demob -.gdb_history diff --git a/linker/README.md b/linker/README.md new file mode 100644 index 00000000..0eeb6a5f --- /dev/null +++ b/linker/README.md @@ -0,0 +1,15 @@ +# ELF Shared Library Dynamic Linker/Loader + +ToaruOS employs *shared objects* to allow for smaller on-disk binary sizes and provide runtime loading and linking. + +The linker here becomes `/lib/ld.so` and is called as the interpreter for dynamically-linked binaries in the OS. + +## ld.so Implementation + +The linker is a minimal implementation of 32-bit x86 ELF dynamic linking. It does not (yet) employ shared file mappings for libraries or binaries. This does mean that memory usage of dynamically linked programs is generally higher than if they were statically linked, but disk space can be saved if multiple programs are using the same libraries (such as the C standard library itself). Actually sharing program code between processes is planned for the future, but requires additional functionally not yet available from the kernel. + +## ld.so Debugging + +You can enable debug output from the linker/loader by setting the environment variable `LD_DEBUG=1`. This will provide details on where ld.so is loading libraries, as well as reporting any unresolved symbols which it normally ignores. + + diff --git a/linker/linker.c b/linker/linker.c index 1ba83665..58af6c1d 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -1,36 +1,82 @@ -/* This file is part of ToaruOS and is released under the terms +/* vim: ts=4 sw=4 noexpandtab + * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016-2017 Kevin Lange + * Copyright (C) 2016-2018 Kevin Lange + * + * ELF Dynamic Linker/Loader + * + * Loads ELF executables and links them at runtime to their + * shared library dependencies. + * + * As of writing, this is a simplistic and not-fully-compliant + * implementation of ELF dynamic linking. It suffers from a number + * of issues, including not actually sharing libraries (there + * isn't a sufficient mechanism in the kernel at the moment for + * doing that - we need something with copy-on-write, preferably + * an mmap-file mechanism), as well as not handling symbol + * resolution correctly. + * + * However, it's sufficient for our purposes, and works well enough + * to load Python C modules. */ -#include #include #include -#include #include +#include +#include #include #include #include +#include +#include + +void * (*_malloc)(size_t size) = malloc; +void (*_free)(void * ptr) = free; + +#undef malloc +#undef free +#define malloc ld_x_malloc +#define free ld_x_free + +uintptr_t _malloc_minimum = 0; + +static void * malloc(size_t size) { + return _malloc(size); +} + +static void free(void * ptr) { + if ((uintptr_t)ptr < _malloc_minimum) return; + _free(ptr); +} + +/* + * When the LD_DEBUG environment variable is set, TRACE_LD messages + * will be printed to stderr + */ #define TRACE_APP_NAME "ld.so" - #define TRACE_LD(...) do { if (__trace_ld) { TRACE(__VA_ARGS__); } } while (0) static int __trace_ld = 0; -#include "../kernel/include/elf.h" -#include "../userspace/lib/trace.h" +#include -#include "../userspace/lib/list.c" -#include "../userspace/lib/hashmap.c" +/* + * This libraries are included in source form to avoid having + * to build separate objects for them and complicate linking, + * since ld is specially built as a static object. + */ +#include "../lib/list.c" +#include "../lib/hashmap.c" typedef int (*entry_point_t)(int, char *[], char**); -extern char end[]; - +/* Global linking state */ static hashmap_t * dumb_symbol_table; static hashmap_t * glob_dat; static hashmap_t * objects_map; +/* Used for dlerror */ static char * last_error = NULL; typedef struct elf_object { @@ -67,69 +113,90 @@ typedef struct elf_object { static elf_t * _main_obj = NULL; +/* Locate library for LD_LIBRARY PATH */ static char * find_lib(const char * file) { + /* If it was an absolute path, there's no need to find it. */ if (strchr(file, '/')) return strdup(file); + /* Collect the environment variable. */ char * path = getenv("LD_LIBRARY_PATH"); if (!path) { - path = "/usr/lib:/lib:/opt/lib"; + /* Not set - this is the default state. Should probably read from config file? */ + path = "/lib:/usr/lib"; } + + /* Duplicate so we can tokenize without editing */ char * xpath = strdup(path); - int found = 0; - char * p, * tokens[10], * last; - int i = 0; + char * p, * last; for ((p = strtok_r(xpath, ":", &last)); p; p = strtok_r(NULL, ":", &last)) { + /* Go through each LD_LIBRARY_PATH entry */ int r; struct stat stat_buf; + + /* Append the requested file to that path */ char * exe = malloc(strlen(p) + strlen(file) + 2); - strcpy(exe, p); + *exe = '\0'; + strcat(exe, p); strcat(exe, "/"); strcat(exe, file); + /* See if it exists */ r = stat(exe, &stat_buf); if (r != 0) { + /* Nope. */ free(exe); continue; } + + /* It exists, so this is what we want. */ return exe; } free(xpath); + /* No match found. */ return NULL; } +/* Open an object file */ static elf_t * open_object(const char * path) { + /* If no path (eg. dlopen(NULL)), return the main object (the executable). */ if (!path) { - _main_obj->loaded = 1; return _main_obj; } + /* If we've already opened a file with this name, return it - don't load things twice. */ if (hashmap_has(objects_map, (void*)path)) { elf_t * object = hashmap_get(objects_map, (void*)path); - object->loaded = 1; return object; } + /* Locate the library */ char * file = find_lib(path); if (!file) { last_error = "Could not find library."; return NULL; } + /* Open the library. */ FILE * f = fopen(file, "r"); + /* Free the expanded path, we don't need it anymore. */ free(file); + /* Failed to open? Unlikely, but could mean permissions problems. */ if (!f) { last_error = "Could not open library."; return NULL; } - elf_t * object = calloc(1, sizeof(elf_t)); + /* Initialize a fresh object object. */ + elf_t * object = malloc(sizeof(elf_t)); + memset(object, 0, sizeof(elf_t)); hashmap_set(objects_map, (void*)path, object); + /* Really unlikely... */ if (!object) { last_error = "Could not allocate space."; return NULL; @@ -137,14 +204,17 @@ static elf_t * open_object(const char * path) { object->file = f; + /* Read the header */ size_t r = fread(&object->header, sizeof(Elf32_Header), 1, object->file); + /* Header failed to read? */ if (!r) { last_error = "Failed to read object header."; free(object); return NULL; } + /* Is this actually an ELF object? */ if (object->header.e_ident[0] != ELFMAG0 || object->header.e_ident[1] != ELFMAG1 || object->header.e_ident[2] != ELFMAG2 || @@ -155,96 +225,108 @@ static elf_t * open_object(const char * path) { return NULL; } + /* Prepare a list for tracking dependencies. */ object->dependencies = list_create(); return object; } +/* Calculate the size of an object file by examining its phdrs */ static size_t object_calculate_size(elf_t * object) { uintptr_t base_addr = 0xFFFFFFFF; uintptr_t end_addr = 0x0; + size_t headers = 0; + while (headers < object->header.e_phnum) { + Elf32_Phdr phdr; - { - size_t headers = 0; - while (headers < object->header.e_phnum) { - Elf32_Phdr phdr; + /* Read the phdr */ + fseek(object->file, object->header.e_phoff + object->header.e_phentsize * headers, SEEK_SET); + fread(&phdr, object->header.e_phentsize, 1, object->file); - fseek(object->file, object->header.e_phoff + object->header.e_phentsize * headers, SEEK_SET); - fread(&phdr, object->header.e_phentsize, 1, object->file); - - switch (phdr.p_type) { - case PT_LOAD: - { - if (phdr.p_vaddr < base_addr) { - base_addr = phdr.p_vaddr; - } - if (phdr.p_memsz + phdr.p_vaddr > end_addr) { - end_addr = phdr.p_memsz + phdr.p_vaddr; - } + switch (phdr.p_type) { + case PT_LOAD: + { + /* If this loads lower than our current base... */ + if (phdr.p_vaddr < base_addr) { + base_addr = phdr.p_vaddr; } - break; - default: - break; - } - headers++; + /* Or higher than our current end address... */ + if (phdr.p_memsz + phdr.p_vaddr > end_addr) { + end_addr = phdr.p_memsz + phdr.p_vaddr; + } + } + break; + /* TODO: Do we care about other PHDR types here? */ + default: + break; } + + headers++; } + /* If base_addr is still -1, then no valid phdrs were found, and the object has no loaded size. */ if (base_addr == 0xFFFFFFFF) return 0; return end_addr - base_addr; } +/* Load an object into memory */ static uintptr_t object_load(elf_t * object, uintptr_t base) { uintptr_t end_addr = 0x0; object->base = base; - /* Load object */ - { - size_t headers = 0; - while (headers < object->header.e_phnum) { - Elf32_Phdr phdr; + size_t headers = 0; + while (headers < object->header.e_phnum) { + Elf32_Phdr phdr; - fseek(object->file, object->header.e_phoff + object->header.e_phentsize * headers, SEEK_SET); - fread(&phdr, object->header.e_phentsize, 1, object->file); + /* Read the phdr */ + fseek(object->file, object->header.e_phoff + object->header.e_phentsize * headers, SEEK_SET); + fread(&phdr, object->header.e_phentsize, 1, object->file); - switch (phdr.p_type) { - case PT_LOAD: - { - char * args[] = {(char *)(base + phdr.p_vaddr), (char *)phdr.p_memsz}; - syscall_system_function(10, args); - fseek(object->file, phdr.p_offset, SEEK_SET); - fread((void *)(base + phdr.p_vaddr), phdr.p_filesz, 1, object->file); - size_t r = phdr.p_filesz; - while (r < phdr.p_memsz) { - *(char *)(phdr.p_vaddr + base + r) = 0; - r++; - } + switch (phdr.p_type) { + case PT_LOAD: + { + /* Request memory to load this PHDR into */ + char * args[] = {(char *)(base + phdr.p_vaddr), (char *)phdr.p_memsz}; + syscall_system_function(10, args); - if (end_addr < phdr.p_vaddr + base + phdr.p_memsz) { - end_addr = phdr.p_vaddr + base + phdr.p_memsz; - } + /* Copy the code into memory */ + fseek(object->file, phdr.p_offset, SEEK_SET); + fread((void *)(base + phdr.p_vaddr), phdr.p_filesz, 1, object->file); + + /* Zero the remaining area */ + size_t r = phdr.p_filesz; + while (r < phdr.p_memsz) { + *(char *)(phdr.p_vaddr + base + r) = 0; + r++; } - break; - case PT_DYNAMIC: - { - object->dynamic = (Elf32_Dyn *)(base + phdr.p_vaddr); - } - break; - default: - break; - } - headers++; + /* If this expands our end address, be sure to update it */ + if (end_addr < phdr.p_vaddr + base + phdr.p_memsz) { + end_addr = phdr.p_vaddr + base + phdr.p_memsz; + } + } + break; + case PT_DYNAMIC: + { + /* Keep a reference to the dynamic section, which is actually loaded by a PT_LOAD normally. */ + object->dynamic = (Elf32_Dyn *)(base + phdr.p_vaddr); + } + break; + default: + break; } + + headers++; } return end_addr; } +/* Perform cleanup after loading */ static int object_postload(elf_t * object) { /* Load section string table */ @@ -257,10 +339,11 @@ static int object_postload(elf_t * object) { fread(object->string_table, shdr.sh_size, 1, object->file); } + /* If there is a dynamic table, parse it. */ if (object->dynamic) { Elf32_Dyn * table; - /* Locate string table */ + /* Locate string tables */ table = object->dynamic; while (table->d_tag) { switch (table->d_tag) { @@ -284,6 +367,12 @@ static int object_postload(elf_t * object) { table++; } + /* + * Read through dependencies + * We have to do this separately from the above to make sure + * we have the dynamic string tables loaded first, as they + * are needed for the dependency names. + */ table = object->dynamic; while (table->d_tag) { switch (table->d_tag) { @@ -295,18 +384,23 @@ static int object_postload(elf_t * object) { } } - size_t i = 0; + /* Locate constructors */ for (uintptr_t x = 0; x < object->header.e_shentsize * object->header.e_shnum; x += object->header.e_shentsize) { Elf32_Shdr shdr; + /* Read section header */ fseek(object->file, object->header.e_shoff + x, SEEK_SET); fread(&shdr, object->header.e_shentsize, 1, object->file); + /* ctors */ if (!strcmp((char *)((uintptr_t)object->string_table + shdr.sh_name), ".ctors")) { + /* Store load address and size */ object->ctors = (void *)(shdr.sh_addr + object->base); object->ctors_size = shdr.sh_size / sizeof(uintptr_t); } + /* init_array */ if (!strcmp((char *)((uintptr_t)object->string_table + shdr.sh_name), ".init_array")) { + /* Store load address and size */ object->init_array = (void *)(shdr.sh_addr + object->base); object->init_array_size = shdr.sh_size / sizeof(uintptr_t); } @@ -315,6 +409,7 @@ static int object_postload(elf_t * object) { return 0; } +/* Whether symbol addresses is needed for a relocation type */ static int need_symbol_for_type(unsigned char type) { switch(type) { case 1: @@ -328,33 +423,36 @@ static int need_symbol_for_type(unsigned char type) { } } - +/* Apply ELF relocations */ static int object_relocate(elf_t * object) { + + /* If there is a dynamic symbol table, load symbols */ if (object->dyn_symbol_table) { Elf32_Sym * table = object->dyn_symbol_table; size_t i = 0; while (i < object->dyn_symbol_table_size) { char * symname = (char *)((uintptr_t)object->dyn_string_table + table->st_name); + + /* If we haven't added this symbol to our symbol table, do so now. */ if (!hashmap_has(dumb_symbol_table, symname)) { if (table->st_shndx) { hashmap_set(dumb_symbol_table, symname, (void*)(table->st_value + object->base)); } - } else { - if (table->st_shndx) { - //table->st_value = (uintptr_t)hashmap_get(dumb_symbol_table, symname); - } } + table++; i++; } } - size_t i = 0; + /* Find relocation table */ for (uintptr_t x = 0; x < object->header.e_shentsize * object->header.e_shnum; x += object->header.e_shentsize) { Elf32_Shdr shdr; + /* Load section header */ fseek(object->file, object->header.e_shoff + x, SEEK_SET); fread(&shdr, object->header.e_shentsize, 1, object->file); + /* Relocation table found */ if (shdr.sh_type == 9) { Elf32_Rel * table = (Elf32_Rel *)(shdr.sh_addr + object->base); while ((uintptr_t)table - ((uintptr_t)shdr.sh_addr + object->base) < shdr.sh_size) { @@ -362,15 +460,15 @@ static int object_relocate(elf_t * object) { unsigned char type = ELF32_R_TYPE(table->r_info); Elf32_Sym * sym = &object->dyn_symbol_table[symbol]; + /* If we need symbol for this, get it. */ char * symname = NULL; uintptr_t x = sym->st_value + object->base; if (need_symbol_for_type(type) || (type == 5)) { symname = (char *)((uintptr_t)object->dyn_string_table + sym->st_name); - } - if ((sym->st_shndx == 0) && need_symbol_for_type(type) || (type == 5)) { if (symname && hashmap_has(dumb_symbol_table, symname)) { x = (uintptr_t)hashmap_get(dumb_symbol_table, symname); } else { + /* This isn't fatal, but do log a message if debugging is enabled. */ TRACE_LD("Symbol not found: %s", symname); x = 0x0; } @@ -414,13 +512,15 @@ static int object_relocate(elf_t * object) { return 0; } +/* Copy relocations are special and need to be located before other relocations. */ static void object_find_copy_relocations(elf_t * object) { - size_t i = 0; + for (uintptr_t x = 0; x < object->header.e_shentsize * object->header.e_shnum; x += object->header.e_shentsize) { Elf32_Shdr shdr; fseek(object->file, object->header.e_shoff + x, SEEK_SET); fread(&shdr, object->header.e_shentsize, 1, object->file); + /* Relocation table found */ if (shdr.sh_type == 9) { Elf32_Rel * table = (Elf32_Rel *)(shdr.sh_addr + object->base); while ((uintptr_t)table - ((uintptr_t)shdr.sh_addr + object->base) < shdr.sh_size) { @@ -435,10 +535,11 @@ static void object_find_copy_relocations(elf_t * object) { } } } - } +/* Find a symbol in a specific object. */ static void * object_find_symbol(elf_t * object, const char * symbol_name) { + if (!object->dyn_symbol_table) { last_error = "lib does not have a symbol table"; return NULL; @@ -458,6 +559,7 @@ static void * object_find_symbol(elf_t * object, const char * symbol_name) { return NULL; } +/* Fully load an object. */ static void * do_actual_load(const char * filename, elf_t * lib, int flags) { (void)flags; @@ -468,38 +570,52 @@ static void * do_actual_load(const char * filename, elf_t * lib, int flags) { size_t lib_size = object_calculate_size(lib); + /* Needs to be at least a page. */ if (lib_size < 4096) { lib_size = 4096; } + /* + * Allocate space to load the library + * This is where we should really be loading things into COW + * but we don't have the functionality available. + */ uintptr_t load_addr = (uintptr_t)malloc(lib_size); object_load(lib, load_addr); + /* Perform cleanup steps */ object_postload(lib); + /* Ensure dependencies are available */ node_t * item; - while (item = list_pop(lib->dependencies)) { + while ((item = list_pop(lib->dependencies))) { - elf_t * lib = open_object(item->value); + elf_t * _lib = open_object(item->value); - if (!lib) { + if (!_lib) { + /* Missing dependencies are fatal to this process, but + * not to the entire application. */ free((void *)load_addr); last_error = "Failed to load a dependency."; + lib->loaded = 0; return NULL; } - if (!lib->loaded) { - do_actual_load(item->value, lib, 0); + if (!_lib->loaded) { + do_actual_load(item->value, _lib, 0); TRACE_LD("Loaded %s at 0x%x", item->value, lib->base); } } + /* Perform relocations */ TRACE_LD("Relocating %s", filename); object_relocate(lib); + /* We're done with the file. */ fclose(lib->file); + /* If there were constructors, call them */ if (lib->ctors) { for (size_t i = 0; i < lib->ctors_size; i++) { TRACE_LD(" 0x%x()", lib->ctors[i]); @@ -507,6 +623,7 @@ static void * do_actual_load(const char * filename, elf_t * lib, int flags) { } } + /* If there was an init_array, call everything in it */ if (lib->init_array) { for (size_t i = 0; i < lib->init_array_size; i++) { TRACE_LD(" 0x%x()", lib->init_array[i]); @@ -514,14 +631,18 @@ static void * do_actual_load(const char * filename, elf_t * lib, int flags) { } } + /* If the library has an init function, call that last. */ if (lib->init) { lib->init(); } - return (void *)lib; + lib->loaded = 1; + /* And return an object for the loaded library */ + return (void *)lib; } +/* exposed dlopen() method */ static void * dlopen_ld(const char * filename, int flags) { TRACE_LD("dlopen(%s,0x%x)", filename, flags); @@ -536,23 +657,36 @@ static void * dlopen_ld(const char * filename, int flags) { } void * ret = do_actual_load(filename, lib, flags); + if (!ret) { + /* Dependency load failure, remove us from hash */ + hashmap_remove(objects_map, (void*)filename); + } + TRACE_LD("Loaded %s at 0x%x", filename, lib->base); return ret; } +/* exposed dlclose() method - XXX not fully implemented */ static int dlclose_ld(elf_t * lib) { /* TODO close dependencies? Make sure nothing references this. */ free((void *)lib->base); return 0; } +/* exposed dlerror() method */ static char * dlerror_ld(void) { - /* TODO actually do this */ char * this_error = last_error; last_error = NULL; return this_error; } +/* Specially used by libc */ +static void * _argv_value = NULL; +static char * argv_value(void) { + return _argv_value; +} + +/* Exported methods (dlfcn) */ typedef struct { char * name; void * symbol; @@ -562,6 +696,7 @@ ld_exports_t ld_builtin_exports[] = { {"dlsym", object_find_symbol}, {"dlclose", dlclose_ld}, {"dlerror", dlerror_ld}, + {"__get_argv", argv_value}, {NULL, NULL}, }; @@ -575,21 +710,27 @@ int main(int argc, char * argv[]) { file = argv[2]; } + _argv_value = argv+arg_offset; + + /* Enable tracing if requested */ char * trace_ld_env = getenv("LD_DEBUG"); - if (trace_ld_env && (!strcmp(trace_ld_env,"1") || !strcmp(trace_ld_env,"yes"))) { + if ((trace_ld_env && (!strcmp(trace_ld_env,"1") || !strcmp(trace_ld_env,"yes")))) { __trace_ld = 1; } + /* Initialize hashmaps for symbols, GLOB_DATs, and objects */ dumb_symbol_table = hashmap_create(10); glob_dat = hashmap_create(10); objects_map = hashmap_create(10); + /* Setup symbols for built-in exports */ ld_exports_t * ex = ld_builtin_exports; while (ex->name) { hashmap_set(dumb_symbol_table, ex->name, ex->symbol); ex++; } + /* Open the requested main object */ elf_t * main_obj = open_object(file); _main_obj = main_obj; @@ -598,12 +739,12 @@ int main(int argc, char * argv[]) { return 1; } - size_t main_size = object_calculate_size(main_obj); + /* Load the main object */ uintptr_t end_addr = object_load(main_obj, 0x0); object_postload(main_obj); - object_find_copy_relocations(main_obj); + /* Load library dependencies */ hashmap_t * libs = hashmap_create(10); while (end_addr & 0xFFF) { @@ -615,13 +756,15 @@ int main(int argc, char * argv[]) { TRACE_LD("Loading dependencies."); node_t * item; - while (item = list_pop(main_obj->dependencies)) { + while ((item = list_pop(main_obj->dependencies))) { while (end_addr & 0xFFF) { end_addr++; } char * lib_name = item->value; + /* Reject libg.so */ if (!strcmp(lib_name, "libg.so")) goto nope; + elf_t * lib = open_object(lib_name); if (!lib) { fprintf(stderr, "Failed to load dependency '%s'.\n", lib_name); @@ -637,7 +780,7 @@ int main(int argc, char * argv[]) { fclose(lib->file); - /* Execute constructors */ + /* Store constructors for later execution */ if (lib->ctors || lib->init_array) { list_insert(ctor_libs, lib); } @@ -645,10 +788,13 @@ int main(int argc, char * argv[]) { list_insert(init_libs, lib); } + lib->loaded = 1; + nope: free(item); } + /* Relocate the main object */ TRACE_LD("Relocating main object"); object_relocate(main_obj); TRACE_LD("Placing heap at end"); @@ -656,6 +802,7 @@ nope: end_addr++; } + /* Call constructors for loaded dependencies */ char * ld_no_ctors = getenv("LD_DISABLE_CTORS"); if (ld_no_ctors && (!strcmp(ld_no_ctors,"1") || !strcmp(ld_no_ctors,"yes"))) { TRACE_LD("skipping ctors because LD_DISABLE_CTORS was set"); @@ -684,6 +831,7 @@ nope: lib->init(); } + /* If main object had constructors, call them. */ if (main_obj->init_array) { for (size_t i = 0; i < main_obj->init_array_size; i++) { TRACE_LD(" 0x%x()", main_obj->init_array[i]); @@ -695,12 +843,21 @@ nope: main_obj->init(); } + main_obj->loaded = 1; + + /* Move heap start (kind of like a weird sbrk) */ { char * args[] = {(char*)end_addr}; syscall_system_function(9, args); } - TRACE_LD("Jumping to entry point"); + /* Set heap functions for later usage */ + if (hashmap_has(dumb_symbol_table, "malloc")) _malloc = hashmap_get(dumb_symbol_table, "malloc"); + if (hashmap_has(dumb_symbol_table, "free")) _free = hashmap_get(dumb_symbol_table, "free"); + _malloc_minimum = 0x40000000; + + /* Jump to the entry for the main object */ + TRACE_LD("Jumping to entry point"); entry_point_t entry = (entry_point_t)main_obj->header.e_entry; entry(argc-arg_offset,argv+arg_offset,environ); diff --git a/modules/README.md b/modules/README.md new file mode 100644 index 00000000..a92692e1 --- /dev/null +++ b/modules/README.md @@ -0,0 +1,91 @@ +# Kernel Modules + +The Toaru kernel supports loadable modules which provide most of the device driver support. + +A simple module requires a load and unload method, which are exposed along with a module +name through the `MODULE_DEF` macro available from ``. + +```c +#include + +static int load(void) { + /* Run on module installation */ + return 0; +} + +static int unload(void) { + /* Clean up for removal */ + return 0; +} + +MODULE_DEF(example_mod, load, unload); +``` + +## Module Dependencies + +If your module depends on another module being loaded, list each dependency using the `MODULE_DEPENDS` macro: + +```c +MODULE_DEF(extension_mod, load, unload); +MODULE_DEPENDS(example_mod); +``` + +Currently, dependencies are tested at load time, but the kernel will not load dependencies for you. + +Dependency lists can be parsed by external tools to ensure modules are properly linked. + +## Kernel Functions + +All non-static kernel functions are available for use in modules. +For example, the logging functions may be used: + +```c +#include +#include + +static int load(void) { + debug_print(WARNING, "Hello, world."); + return 0; +} + +static int unload(void) { + return 0; +} + +MODULE_DEF(printing_mod, load, unload); +``` + +## Background Tasks + +Device drivers, such as those for network devices, may want to create a background process to manage tasks. +This can be done through the `create_kernel_tasklet` interface at device startup. + +```c +#include +#include + +static void tasklet_run(void * data, char * name) { + /* Perform tasklet activities */ + while (1) { + do_thing(); + } +} + +static int load(void) { + create_kernel_tasklet(tasklet_run, "[demo-tasklet]", NULL); + return 0; +} + +static int unload(void) { + /* Maybe clean up your tasklet here. */ + return 0; +} + +MODULE_DEF(tasklet_mod, load, unload); +``` + +## Caveats + +- Currently, unloading modules is not supported. +- Modules which are expected to be loaded at runtime should be very careful of memory allocations they make, as they happen in a context which may not be shared with other processes. If you wish to make use of memory mappings, ensure that you are creating a new kernel tasklet to perform work. Attempting to access mapped memory from an interrupt handler or a device driver may not be possible if it was mapped at module installation. + diff --git a/modules/ac97.c b/modules/ac97.c index a5cf1256..042f7418 100644 --- a/modules/ac97.c +++ b/modules/ac97.c @@ -2,20 +2,20 @@ * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md * Copyright (C) 2015 Michael Gerow - * Copyright (C) 2015 Kevin Lange + * Copyright (C) 2015-2018 K. Lange * * Driver for the Intel AC'97. * * See . */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include /* Utility macros */ #define N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -53,7 +53,7 @@ #define AC97_X_SR_CELV (1 << 1) /* Current equals last valid */ #define AC97_X_SR_LVBCI (1 << 2) /* Last valid buffer completion interrupt */ #define AC97_X_SR_BCIS (1 << 3) /* Buffer completion interrupt status */ -#define AC97_X_SR_FIFOE (1 << 3) /* FIFO error */ +#define AC97_X_SR_FIFOE (1 << 4) /* FIFO error */ /* Mixer IO port offsets */ #define AC97_RESET 0x00 @@ -135,22 +135,26 @@ static void find_ac97(uint32_t device, uint16_t vendorid, uint16_t deviceid, voi #define DIVISION 0x1000 static int irq_handler(struct regs * regs) { uint16_t sr = inports(_device.nabmbar + AC97_PO_SR); - if (sr & AC97_X_SR_LVBCI) { - outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_LVBCI); - } else if (sr & AC97_X_SR_BCIS) { + if (!sr) return 0; + + if (sr & AC97_X_SR_BCIS) { size_t f = (_device.lvi + 2) % AC97_BDL_LEN; for (size_t i = 0; i < AC97_BDL_BUFFER_LEN * sizeof(*_device.bufs[0]); i += DIVISION) { snd_request_buf(&_snd, DIVISION, (uint8_t *)_device.bufs[f] + i); - switch_task(1); + //switch_task(1); } _device.lvi = (_device.lvi + 1) % AC97_BDL_LEN; outportb(_device.nabmbar + AC97_PO_LVI, _device.lvi); - outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_BCIS); + } else if (sr & AC97_X_SR_LVBCI) { + debug_print(NOTICE, "ac97 irq is lvbci"); } else if (sr & AC97_X_SR_FIFOE) { - outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_FIFOE); + debug_print(NOTICE, "ac97 irq is fifoe"); } else { + /* don't handle it */ return 0; } + debug_print(NOTICE, "ac97 status register: 0x%4x", sr); + outports(_device.nabmbar + AC97_PO_SR, sr & 0x1E); irq_ack(_device.irq); return 1; @@ -237,8 +241,8 @@ static int init(void) { } _device.nabmbar = pci_read_field(_device.pci_device, AC97_NABMBAR, 2) & ((uint32_t) -1) << 1; _device.nambar = pci_read_field(_device.pci_device, PCI_BAR0, 4) & ((uint32_t) -1) << 1; - _device.irq = pci_read_field(_device.pci_device, PCI_INTERRUPT_LINE, 1); - irq_install_handler(_device.irq, irq_handler); + _device.irq = pci_get_interrupt(_device.pci_device); + irq_install_handler(_device.irq, irq_handler, "ac97"); /* Enable all matter of interrupts */ outportb(_device.nabmbar + AC97_PO_CR, AC97_X_CR_FEIE | AC97_X_CR_IOCE); @@ -283,6 +287,7 @@ static int init(void) { /* Start things playing */ outportb(_device.nabmbar + AC97_PO_CR, inportb(_device.nabmbar + AC97_PO_CR) | AC97_X_CR_RPBM); + debug_print(NOTICE, "AC97 initialized successfully"); return 0; diff --git a/modules/ata.c b/modules/ata.c index 131f43da..9ff97bf4 100644 --- a/modules/ata.c +++ b/modules/ata.c @@ -1,24 +1,24 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * ATA Disk Driver * * Provides raw block access to an (Parallel) ATA drive. */ -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include /* TODO: Move this to mod/ata.h */ -#include +#include + +#include static char ata_drive_char = 'a'; static int cdrom_number = 0; @@ -451,7 +451,7 @@ static void ata_device_init(struct ata_device * dev) { } -static void atapi_device_init(struct ata_device * dev) { +static int atapi_device_init(struct ata_device * dev) { dev->is_atapi = 1; @@ -541,16 +541,18 @@ static void atapi_device_init(struct ata_device * dev) { dev->atapi_lba = lba; dev->atapi_sector_size = blocks; + if (!lba) return 1; + debug_print(WARNING, "Finished! LBA = %x; block length = %x", lba, blocks); - return; + return 0; atapi_error_read: debug_print(ERROR, "ATAPI error; no medium?"); - return; + return 1; atapi_error: debug_print(ERROR, "ATAPI early error; unsure"); - return; + return 1; } @@ -589,7 +591,9 @@ static int ata_device_detect(struct ata_device * dev) { char devname[64]; sprintf((char *)&devname, "/dev/cdrom%d", cdrom_number); - atapi_device_init(dev); + if (atapi_device_init(dev)) { + return 0; + } fs_node_t * node = atapi_device_create(dev); vfs_mount(devname, node); @@ -820,8 +824,8 @@ static int ata_initialize(void) { /* Locate ATA device via PCI */ pci_scan(&find_ata_pci, -1, &ata_pci); - irq_install_handler(14, ata_irq_handler); - irq_install_handler(15, ata_irq_handler_s); + irq_install_handler(14, ata_irq_handler, "ide master"); + irq_install_handler(15, ata_irq_handler_s, "ide slave"); atapi_waiter = list_create(); diff --git a/modules/ataold.c b/modules/ataold.c index 05206f95..f043da47 100644 --- a/modules/ataold.c +++ b/modules/ataold.c @@ -1,21 +1,21 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * ATA Disk Driver * * Provides raw block access to an (Parallel) ATA drive. */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include /* TODO: Move this to mod/ata.h */ -#include +#include static char ata_drive_char = 'a'; diff --git a/modules/crash.c b/modules/crash.c deleted file mode 100644 index 81bae5ed..00000000 --- a/modules/crash.c +++ /dev/null @@ -1,33 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include - -DEFINE_SHELL_FUNCTION(crash, "Dereference NULL.") { - fprintf(tty, "*0x0 = %x\n", *((int *)0x00)); - *((int *)0x0) = 0x42; - fprintf(tty, "*0x0 = %x\n", *((int *)0x00)); - return 0; -} - -DEFINE_SHELL_FUNCTION(assert_false, "assert(0)") { - assert(0); - return 0; -} - -static int crash_init(void) { - BIND_SHELL_FUNCTION(crash); - BIND_SHELL_FUNCTION(assert_false); - return 0; -} - -static int crash_fini(void) { - return 0; -} - -MODULE_DEF(crash, crash_init, crash_fini); -MODULE_DEPENDS(debugshell); diff --git a/modules/debug_shell.c b/modules/debug_sh.c similarity index 93% rename from modules/debug_shell.c rename to modules/debug_sh.c index 5d8bac25..e5608598 100644 --- a/modules/debug_shell.c +++ b/modules/debug_sh.c @@ -1,26 +1,28 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * Kernel Debug Shell */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include +#include +#include + +#include /* * This is basically the same as a userspace buffered/unbuffered @@ -114,7 +116,11 @@ static void debug_shell_run_sh(void * data, char * name) { while (argv[argc]) { argc++; } - system(argv[0], argc, argv); /* Run shell */ + char * env[] = { + "LD_LIBRARY_PATH=/lib", + NULL + }; + system(argv[0], argc, argv, env); /* Run shell */ task_exit(42); } @@ -316,6 +322,10 @@ static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, fprintf(tty, " BAR4: 0x%8x", pci_read_field(device, PCI_BAR4, 4)); fprintf(tty, " BAR6: 0x%8x\n", pci_read_field(device, PCI_BAR5, 4)); + fprintf(tty, " IRQ Line: %d", pci_read_field(device, 0x3C, 1)); + fprintf(tty, " IRQ Pin: %d", pci_read_field(device, 0x3D, 1)); + fprintf(tty, " Interrupt: %d", pci_get_interrupt(device)); + fprintf(tty, " Status: 0x%4x\n", pci_read_field(device, PCI_STATUS, 2)); } static int shell_pci(fs_node_t * tty, int argc, char * argv[]) { @@ -323,6 +333,23 @@ static int shell_pci(fs_node_t * tty, int argc, char * argv[]) { return 0; } +static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) { + *((uint32_t *)extra) = device; + } +} +static int shell_frob_piix(fs_node_t * tty, int argc, char * argv[]) { + uint32_t pci_isa = 0; + pci_scan(&find_isa_bridge, -1, &pci_isa); + if (pci_isa) { + fprintf(tty, "PCI-to-ISA interrupt mappings by line:\n"); + for (int i = 0; i < 4; ++i) { + fprintf(tty, "Line %d: 0x%2x\n", i+1, pci_read_field(pci_isa, 0x60+i, 1)); + } + } + return 0; +} + static int shell_uid(fs_node_t * tty, int argc, char * argv[]) { if (argc < 2) { fprintf(tty, "uid=%d\n", current_process->user); @@ -455,6 +482,7 @@ static int shell_modules(fs_node_t * tty, int argc, char * argv[]) { fprintf(tty, "\n"); } + free(hash_keys); return 0; } @@ -655,6 +683,8 @@ static struct shell_command shell_commands[] = { "Disable VGA text mode cursor."}, {"exit", &shell_exit, "Quit the shell."}, + {"piix", &shell_frob_piix, + "frob piix"}, {NULL, NULL, NULL} }; diff --git a/modules/dospart.c b/modules/dospart.c index d955326a..a7af5816 100644 --- a/modules/dospart.c +++ b/modules/dospart.c @@ -1,13 +1,13 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #define SECTORSIZE 512 diff --git a/modules/e1000.c b/modules/e1000.c index 5bca0d60..d546a903 100644 --- a/modules/e1000.c +++ b/modules/e1000.c @@ -1,17 +1,20 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2017 Kevin Lange + * Copyright (C) 2017-2018 K. Lange */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define E1000_LOG_LEVEL NOTICE static uint32_t e1000_device_pci = 0x00000000; static int e1000_irq = 0; @@ -112,6 +115,8 @@ static uint8_t* get_mac() { #define E1000_REG_TXDESCHEAD 0x3810 #define E1000_REG_TXDESCTAIL 0x3818 +#define E1000_REG_RXADDR 0x5400 + #define RCTL_EN (1 << 1) /* Receiver Enable */ #define RCTL_SBP (1 << 2) /* Store Bad Packets */ #define RCTL_UPE (1 << 3) /* Unicast Promiscuous Enabled */ @@ -183,6 +188,20 @@ static void find_e1000(uint32_t device, uint16_t vendorid, uint16_t deviceid, vo } } +static void write_mac(void) { + + uint32_t low; + uint32_t high; + + memcpy(&low, &mac[0], 4); + memcpy(&high,&mac[4], 2); + memset((uint8_t *)&high + 2, 0, 2); + high |= 0x80000000; + + write_command(E1000_REG_RXADDR + 0, low); + write_command(E1000_REG_RXADDR + 4, high); +} + static void read_mac(void) { if (has_eeprom) { uint32_t t; @@ -196,7 +215,7 @@ static void read_mac(void) { mac[4] = t & 0xFF; mac[5] = t >> 8; } else { - uint8_t * mac_addr = (uint8_t *)(mem_base + 0x5400); + uint8_t * mac_addr = (uint8_t *)(mem_base + E1000_REG_RXADDR); for (int i = 0; i < 6; ++i) { mac[i] = mac_addr[i]; } @@ -207,15 +226,15 @@ static int irq_handler(struct regs *r) { uint32_t status = read_command(0xc0); - irq_ack(e1000_irq); - if (!status) { return 0; } + irq_ack(e1000_irq); + if (status & 0x04) { /* Start link */ - debug_print(NOTICE, "start link"); + debug_print(E1000_LOG_LEVEL, "start link"); } else if (status & 0x10) { /* ?? */ } else if (status & ((1 << 6) | (1 << 7))) { @@ -248,7 +267,7 @@ static int irq_handler(struct regs *r) { static void send_packet(uint8_t* payload, size_t payload_size) { tx_index = read_command(E1000_REG_TXDESCTAIL); - debug_print(NOTICE,"sending packet 0x%x, %d desc[%d]", payload, payload_size, tx_index); + debug_print(E1000_LOG_LEVEL,"sending packet 0x%x, %d desc[%d]", payload, payload_size, tx_index); memcpy(tx_virt[tx_index], payload, payload_size); tx[tx_index].length = payload_size; @@ -299,34 +318,59 @@ static void init_tx(void) { static void e1000_init(void * data, char * name) { + debug_print(E1000_LOG_LEVEL, "enabling bus mastering"); uint16_t command_reg = pci_read_field(e1000_device_pci, PCI_COMMAND, 2); command_reg |= (1 << 2); command_reg |= (1 << 0); pci_write_field(e1000_device_pci, PCI_COMMAND, 2, command_reg); - debug_print(NOTICE, "mem base: 0x%x", mem_base); + debug_print(E1000_LOG_LEVEL, "mem base: 0x%x", mem_base); eeprom_detect(); - debug_print(NOTICE, "has_eeprom = %d", has_eeprom); + debug_print(E1000_LOG_LEVEL, "has_eeprom = %d", has_eeprom); read_mac(); + write_mac(); - debug_print(NOTICE, "device mac %2x:%2x:%2x:%2x:%2x:%2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - - /* initialize */ - write_command(E1000_REG_CTRL, (1 << 26)); - - /* wait */ + debug_print(E1000_LOG_LEVEL, "device mac %2x:%2x:%2x:%2x:%2x:%2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); unsigned long s, ss; + + uint32_t ctrl = read_command(E1000_REG_CTRL); + /* reset phy */ + write_command(E1000_REG_CTRL, ctrl | (0x80000000)); + read_command(E1000_REG_STATUS); relative_time(0, 10, &s, &ss); sleep_until((process_t *)current_process, s, ss); switch_task(0); - debug_print(NOTICE, "back from sleep"); + + /* reset mac */ + write_command(E1000_REG_CTRL, ctrl | (0x04000000)); + read_command(E1000_REG_STATUS); + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + + /* Reload EEPROM */ + write_command(E1000_REG_CTRL, ctrl | (0x00002000)); + read_command(E1000_REG_STATUS); + relative_time(0, 20, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + + + /* initialize */ + write_command(E1000_REG_CTRL, ctrl | (1 << 26)); + + /* wait */ + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + debug_print(E1000_LOG_LEVEL, "back from sleep"); uint32_t status = read_command(E1000_REG_CTRL); status |= (1 << 5); /* set auto speed detection */ status |= (1 << 6); /* set link up */ status &= ~(1 << 3); /* unset link reset */ - status &= ~(1 << 31); /* unset phy reset */ + status &= ~(1UL << 31UL); /* unset phy reset */ status &= ~(1 << 7); /* unset invert loss-of-signal */ write_command(E1000_REG_CTRL, status); @@ -348,10 +392,11 @@ static void e1000_init(void * data, char * name) { net_queue = list_create(); rx_wait = list_create(); - e1000_irq = pci_read_field(e1000_device_pci, PCI_INTERRUPT_LINE, 1); - irq_install_handler(e1000_irq, irq_handler); + e1000_irq = pci_get_interrupt(e1000_device_pci); - debug_print(NOTICE, "Binding interrupt %d", e1000_irq); + irq_install_handler(e1000_irq, irq_handler, "e1000"); + + debug_print(E1000_LOG_LEVEL, "Binding interrupt %d", e1000_irq); for (int i = 0; i < 128; ++i) { write_command(0x5200 + i * 4, 0); @@ -383,7 +428,7 @@ static void e1000_init(void * data, char * name) { switch_task(0); int link_is_up = (read_command(E1000_REG_STATUS) & (1 << 1)); - debug_print(NOTICE,"e1000 done. has_eeprom = %d, link is up = %d, irq=%d", has_eeprom, link_is_up, e1000_irq); + debug_print(E1000_LOG_LEVEL,"e1000 done. has_eeprom = %d, link is up = %d, irq=%d", has_eeprom, link_is_up, e1000_irq); init_netif_funcs(get_mac, dequeue_packet, send_packet, "Intel E1000"); } @@ -392,7 +437,7 @@ static int init(void) { pci_scan(&find_e1000, -1, &e1000_device_pci); if (!e1000_device_pci) { - debug_print(WARNING, "No e1000 device found."); + debug_print(E1000_LOG_LEVEL, "No e1000 device found."); return 1; } @@ -408,7 +453,7 @@ static int init(void) { for (int i = 0; i < E1000_NUM_RX_DESC; ++i) { rx_virt[i] = (void*)kvmalloc_p(8192 + 16, (uint32_t *)&rx[i].addr); - debug_print(INFO, "rx[%d] 0x%x → 0x%x", i, rx_virt[i], (uint32_t)rx[i].addr); + debug_print(E1000_LOG_LEVEL, "rx[%d] 0x%x → 0x%x", i, rx_virt[i], (uint32_t)rx[i].addr); rx[i].status = 0; } @@ -416,7 +461,7 @@ static int init(void) { for (int i = 0; i < E1000_NUM_TX_DESC; ++i) { tx_virt[i] = (void*)kvmalloc_p(8192+16, (uint32_t *)&tx[i].addr); - debug_print(INFO, "tx[%d] 0x%x → 0x%x", i, tx_virt[i], (uint32_t)tx[i].addr); + debug_print(E1000_LOG_LEVEL, "tx[%d] 0x%x → 0x%x", i, tx_virt[i], (uint32_t)tx[i].addr); tx[i].status = 0; tx[i].cmd = (1 << 0); } diff --git a/modules/ext2.c b/modules/ext2.c index 46ffbd3e..565ebce7 100644 --- a/modules/ext2.c +++ b/modules/ext2.c @@ -1,17 +1,17 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define EXT2_BGD_BLOCK 2 @@ -769,8 +769,8 @@ static unsigned int allocate_inode(ext2_fs_t * this) { return node_no; } -static void mkdir_ext2(fs_node_t * parent, char * name, uint16_t permission) { - if (!name) return; +static int mkdir_ext2(fs_node_t * parent, char * name, uint16_t permission) { + if (!name) return -EINVAL; ext2_fs_t * this = parent->device; @@ -779,7 +779,7 @@ static void mkdir_ext2(fs_node_t * parent, char * name, uint16_t permission) { if (check) { debug_print(WARNING, "A file by this name already exists: %s", name); free(check); - return; /* this should probably have a return value... */ + return -EEXIST; } /* Allocate an inode for it */ @@ -860,10 +860,11 @@ static void mkdir_ext2(fs_node_t * parent, char * name, uint16_t permission) { ext2_sync(this); + return 0; } -static void create_ext2(fs_node_t * parent, char * name, uint16_t permission) { - if (!name) return; +static int create_ext2(fs_node_t * parent, char * name, uint16_t permission) { + if (!name) return -EINVAL; ext2_fs_t * this = parent->device; @@ -872,7 +873,7 @@ static void create_ext2(fs_node_t * parent, char * name, uint16_t permission) { if (check) { debug_print(WARNING, "A file by this name already exists: %s", name); free(check); - return; /* this should probably have a return value... */ + return -EEXIST; } /* Allocate an inode for it */ @@ -921,6 +922,7 @@ static void create_ext2(fs_node_t * parent, char * name, uint16_t permission) { ext2_sync(this); + return 0; } static int chmod_ext2(fs_node_t * node, int mode) { @@ -1041,7 +1043,7 @@ static fs_node_t * finddir_ext2(fs_node_t *node, char *name) { return outnode; } -static void unlink_ext2(fs_node_t * node, char * name) { +static int unlink_ext2(fs_node_t * node, char * name) { /* XXX this is a very bad implementation */ ext2_fs_t * this = (ext2_fs_t *)node->device; @@ -1085,7 +1087,7 @@ static void unlink_ext2(fs_node_t * node, char * name) { free(inode); if (!direntry) { free(block); - return; + return -ENOENT; } direntry->inode = 0; @@ -1094,6 +1096,8 @@ static void unlink_ext2(fs_node_t * node, char * name) { free(block); ext2_sync(this); + + return 0; } @@ -1262,8 +1266,8 @@ static struct dirent * readdir_ext2(fs_node_t *node, uint32_t index) { return dirent; } -static void symlink_ext2(fs_node_t * parent, char * target, char * name) { - if (!name) return; +static int symlink_ext2(fs_node_t * parent, char * target, char * name) { + if (!name) return -EINVAL; ext2_fs_t * this = parent->device; @@ -1272,7 +1276,7 @@ static void symlink_ext2(fs_node_t * parent, char * target, char * name) { if (check) { debug_print(WARNING, "A file by this name already exists: %s", name); free(check); - return; /* this should probably have a return value... */ + return -EEXIST; /* this should probably have a return value... */ } /* Allocate an inode for it */ @@ -1332,6 +1336,8 @@ static void symlink_ext2(fs_node_t * parent, char * target, char * name) { free(inode); ext2_sync(this); + + return 0; } static int readlink_ext2(fs_node_t * node, char * buf, size_t size) { diff --git a/modules/hda.c b/modules/hda.c index eb79699c..83620b06 100644 --- a/modules/hda.c +++ b/modules/hda.c @@ -2,10 +2,10 @@ * Experimental Intel High-Definition Audio "driver" */ -#include -#include -#include -#include +#include +#include +#include +#include struct hda_device { uint32_t pci_device; diff --git a/modules/iso9660.c b/modules/iso9660.c index 2885f875..e37696f4 100644 --- a/modules/iso9660.c +++ b/modules/iso9660.c @@ -1,20 +1,21 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016 Kevin Lange + * Copyright (C) 2016-2018 K. Lange * * ISO 9660 filesystem driver (for CDs) */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include #define ISO_SECTOR_SIZE 2048 diff --git a/modules/lfbvideo.c b/modules/lfbvideo.c index f702e50a..cd3c18f3 100644 --- a/modules/lfbvideo.c +++ b/modules/lfbvideo.c @@ -1,68 +1,88 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * - * Bochs VBE / QEMU vga=std Graphics Driver + * Generic linear framebuffer driver. + * + * Supports several cases: + * - Bochs/QEMU/VirtualBox "Bochs VBE" with modesetting. + * - VMware SVGA with modesetting. + * - Linear framebuffers set by the bootloader with no modesetting. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../userspace/gui/terminal/terminal-font.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define PREFERRED_W 1024 +#define PREFERRED_H 768 #define PREFERRED_VY 4096 #define PREFERRED_B 32 -/* Generic (pre-set, 32-bit, linear frame buffer) */ -static void graphics_install_preset(uint16_t, uint16_t); +/* Exported to other modules */ uint16_t lfb_resolution_x = 0; uint16_t lfb_resolution_y = 0; uint16_t lfb_resolution_b = 0; uint32_t lfb_resolution_s = 0; +uint8_t * lfb_vid_memory = (uint8_t *)0xE0000000; +const char * lfb_driver_name = NULL; -/* BOCHS / QEMU VBE Driver */ -static void graphics_install_bochs(uint16_t, uint16_t); -static void bochs_set_y_offset(uint16_t y); -static uint16_t bochs_current_scroll(void); - +/* Where to send display size change signals */ static pid_t display_change_recipient = 0; -void lfb_set_resolution(uint16_t x, uint16_t y); +/* Driver-specific modesetting function */ +static void (*lfb_resolution_impl)(uint16_t,uint16_t) = NULL; -/* - * Address of the linear frame buffer. - * This can move, so it's a pointer instead of - * #define. +/* Called by ioctl on /dev/fb0 */ +void lfb_set_resolution(uint16_t x, uint16_t y) { + if (lfb_resolution_impl) { + lfb_resolution_impl(x,y); + if (display_change_recipient) { + send_signal(display_change_recipient, SIGWINEVENT, 1); + debug_print(WARNING, "Telling %d to SIGWINEVENT", display_change_recipient); + } + } +} + +/** + * Framebuffer control ioctls. + * Used by the compositor to get display sizes and by the + * resolution changer to initiate modesetting. */ -uint8_t * lfb_vid_memory = (uint8_t *)0xE0000000; - static int ioctl_vid(fs_node_t * node, int request, void * argp) { - /* TODO: Make this actually support multiple video devices */ - switch (request) { case IO_VID_WIDTH: + /* Get framebuffer width */ validate(argp); *((size_t *)argp) = lfb_resolution_x; return 0; case IO_VID_HEIGHT: + /* Get framebuffer height */ validate(argp); *((size_t *)argp) = lfb_resolution_y; return 0; case IO_VID_DEPTH: + /* Get framebuffer bit depth */ validate(argp); *((size_t *)argp) = lfb_resolution_b; return 0; + case IO_VID_STRIDE: + /* Get framebuffer scanline stride */ + validate(argp); + *((size_t *)argp) = lfb_resolution_s; + return 0; case IO_VID_ADDR: + /* Get framebuffer address - TODO: map the framebuffer? */ validate(argp); *((uintptr_t *)argp) = (uintptr_t)lfb_vid_memory; return 0; @@ -71,17 +91,41 @@ static int ioctl_vid(fs_node_t * node, int request, void * argp) { display_change_recipient = getpid(); return 0; case IO_VID_SET: + /* Initiate mode setting */ validate(argp); lfb_set_resolution(((struct vid_size *)argp)->width, ((struct vid_size *)argp)->height); return 0; - case IO_VID_STRIDE: - *((size_t *)argp) = lfb_resolution_s; + case IO_VID_DRIVER: + validate(argp); + memcpy(argp, lfb_driver_name, strlen(lfb_driver_name)); return 0; default: - return -1; /* TODO EINV... something or other */ + return -EINVAL; } } +/* Framebuffer device file initializer */ +static fs_node_t * lfb_video_device_create(void /* TODO */) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + sprintf(fnode->name, "fb0"); /* TODO */ + fnode->length = lfb_resolution_s * lfb_resolution_y; /* Size is framebuffer size in bytes */ + fnode->flags = FS_BLOCKDEVICE; /* Framebuffers are block devices */ + fnode->mask = 0660; /* Only accessible to root user/group */ + fnode->ioctl = ioctl_vid; /* control function defined above */ + return fnode; +} + +/** + * Framebuffer fatal error presentation. + * + * This is called by a kernel hook to render fatal error messages + * (panic / oops / bsod) to the graphraical framebuffer. Mostly, + * that means the "out of memory" error. Bescause this is a fatal + * error condition, we don't care much about speed, so we can do + * silly things like ready from the framebuffer, which we do to + * produce a vignetting and desaturation effect. + */ static int vignette_at(int x, int y) { int amount = 0; int level = 100; @@ -92,23 +136,28 @@ static int vignette_at(int x, int y) { return amount; } -#define char_height 12 -#define char_width 8 +#include "../apps/terminal-font.h" +/* XXX Why is this not defined in the font header... */ +#define char_height 20 +#define char_width 9 + +/* Set point in framebuffer */ static void set_point(int x, int y, uint32_t value) { uint32_t * disp = (uint32_t *)lfb_vid_memory; uint32_t * cell = &disp[y * (lfb_resolution_s / 4) + x]; *cell = value; } +/* Draw text on framebuffer */ static void write_char(int x, int y, int val, uint32_t color) { if (val > 128) { val = 4; } - uint8_t * c = number_font[val]; + uint16_t * c = large_font[val]; for (uint8_t i = 0; i < char_height; ++i) { for (uint8_t j = 0; j < char_width; ++j) { - if (c[i] & (1 << (8-j))) { + if (c[i] & (1 << (15-j))) { set_point(x+j,y+i,color); } } @@ -161,43 +210,62 @@ static void lfb_video_panic(char ** msgs) { } y += char_height; } - } -static fs_node_t * lfb_video_device_create(void /* TODO */) { - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - sprintf(fnode->name, "fb0"); /* TODO */ - fnode->length = lfb_resolution_x * lfb_resolution_y * (lfb_resolution_b / 8); - fnode->flags = FS_BLOCKDEVICE; - fnode->mask = 0660; - fnode->ioctl = ioctl_vid; - return fnode; +static uint32_t framebuffer_func(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) { + char * buf = malloc(4096); + + if (lfb_driver_name) { + sprintf(buf, + "Driver:\t%s\n" + "XRes:\t%d\n" + "YRes:\t%d\n" + "BitsPerPixel:\t%d\n" + "Stride:\t%d\n" + "Address:\t0x%x\n", + lfb_driver_name, + lfb_resolution_x, + lfb_resolution_y, + lfb_resolution_b, + lfb_resolution_s, + lfb_vid_memory); + } else { + sprintf(buf, "Driver:\tnone\n"); + } + + size_t _bsize = strlen(buf); + if (offset > _bsize) { + free(buf); + return 0; + } + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + free(buf); + return size; } -static void finalize_graphics(uint16_t x, uint16_t y, uint16_t b, uint32_t s) { - lfb_resolution_x = x; - lfb_resolution_s = s; - lfb_resolution_y = y; - lfb_resolution_b = b; +static struct procfs_entry framebuffer_entry = { + 0, + "framebuffer", + framebuffer_func, +}; + +/* Install framebuffer device */ +static void finalize_graphics(const char * driver) { + lfb_driver_name = driver; fs_node_t * fb_device = lfb_video_device_create(); vfs_mount("/dev/fb0", fb_device); debug_video_crash = lfb_video_panic; + + int (*procfs_install)(struct procfs_entry *) = (int (*)(struct procfs_entry *))(uintptr_t)hashmap_get(modules_get_symbols(),"procfs_install"); + + if (procfs_install) { + procfs_install(&framebuffer_entry); + } } /* Bochs support {{{ */ -static uintptr_t current_scroll = 0; - -static void bochs_set_y_offset(uint16_t y) { - outports(0x1CE, 0x9); - outports(0x1CF, y); - current_scroll = y; -} - -static uint16_t bochs_current_scroll(void) { - return current_scroll; -} - static void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { if ((v == 0x1234 && d == 0x1111) || (v == 0x80EE && d == 0xBEEF) || @@ -209,22 +277,7 @@ static void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra } } -static void (*lfb_resolution_impl)(uint16_t,uint16_t) = NULL; - -void lfb_set_resolution(uint16_t x, uint16_t y) { - - if (lfb_resolution_impl) { - lfb_resolution_impl(x,y); - if (display_change_recipient) { - send_signal(display_change_recipient, SIGWINEVENT); - debug_print(WARNING, "Telling %d to SIGWINEVENT", display_change_recipient); - } - } - -} - -static void res_change_bochs(uint16_t x, uint16_t y) { - +static void bochs_set_resolution(uint16_t x, uint16_t y) { outports(0x1CE, 0x04); outports(0x1CF, 0x00); /* Uh oh, here we go. */ @@ -253,9 +306,9 @@ static void res_change_bochs(uint16_t x, uint16_t y) { lfb_resolution_x = x; lfb_resolution_s = x * 4; lfb_resolution_y = y; + lfb_resolution_b = 32; } - static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) { uint32_t vid_memsize; debug_print(NOTICE, "Setting up BOCHS/QEMU graphics controller..."); @@ -267,44 +320,28 @@ static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) } outports(0x1CF, 0xB0C4); i = inports(0x1CF); - res_change_bochs(resolution_x, resolution_y); + bochs_set_resolution(resolution_x, resolution_y); resolution_x = lfb_resolution_x; /* may have changed */ pci_scan(bochs_scan_pci, -1, &lfb_vid_memory); - lfb_resolution_impl = &res_change_bochs; + lfb_resolution_impl = &bochs_set_resolution; - if (lfb_vid_memory) { - /* Enable the higher memory */ - uintptr_t fb_offset = (uintptr_t)lfb_vid_memory; - for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); - } - - goto mem_found; - } else { - /* XXX: Massive hack */ - - uint32_t * text_vid_mem = (uint32_t *)0xA0000; - text_vid_mem[0] = 0xA5ADFACE; - - for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) { - /* Enable the higher memory */ - for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); - } - - /* Go find it */ - for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) { - if (((uintptr_t *)x)[0] == 0xA5ADFACE) { - lfb_vid_memory = (uint8_t *)x; - goto mem_found; - } - } - } + if (!lfb_vid_memory) { + debug_print(ERROR, "Failed to locate video memory."); + return; + } + + /* Enable the higher memory */ + uintptr_t fb_offset = (uintptr_t)lfb_vid_memory; + for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { + page_t * p = get_page(i, 1, kernel_directory); + dma_frame(p, 0, 1, i); + p->pat = 1; + p->writethrough = 1; + p->cachedisable = 1; } -mem_found: outports(0x1CE, 0x0a); i = inports(0x1CF); if (i > 1) { @@ -316,75 +353,33 @@ mem_found: for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + vid_memsize; i += 0x1000) { dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); } - finalize_graphics(resolution_x, resolution_y, PREFERRED_B, resolution_x * 4); + + finalize_graphics("bochs"); } -/* }}} end bochs support */ - static void graphics_install_preset(uint16_t w, uint16_t h) { - debug_print(NOTICE, "Graphics were pre-configured (thanks, bootloader!), locating video memory..."); - uint16_t b = 32; /* If you are 24 bit, go away, we really do not support you. */ - - if (mboot_ptr && (mboot_ptr->flags & (1 << 12))) { - /* hello world */ - lfb_vid_memory = (void *)mboot_ptr->framebuffer_addr; - w = mboot_ptr->framebuffer_width; - h = mboot_ptr->framebuffer_height; - - debug_print(WARNING, "Mode was set by bootloader: %dx%d bpp should be 32, framebuffer is at 0x%x", w, h, (uintptr_t)lfb_vid_memory); - - for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + w * h * 4; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); - } - goto mem_found; + if (!(mboot_ptr && (mboot_ptr->flags & (1 << 12)))) { + debug_print(ERROR, "Failed to locate preset video memory - missing multiboot header."); + return; } - /* XXX: Massive hack */ - uint32_t * herp = (uint32_t *)0xA0000; - herp[0] = 0xA5ADFACE; - herp[1] = 0xFAF42943; + /* Extract framebuffer information from multiboot */ + lfb_vid_memory = (void *)mboot_ptr->framebuffer_addr; + lfb_resolution_x = mboot_ptr->framebuffer_width; + lfb_resolution_y = mboot_ptr->framebuffer_height; + lfb_resolution_s = mboot_ptr->framebuffer_pitch; + lfb_resolution_b = 32; - if (lfb_vid_memory) { - for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + 0xFF0000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); - } - if (((uintptr_t *)lfb_vid_memory)[0] == 0xA5ADFACE && ((uintptr_t *)lfb_vid_memory)[1] == 0xFAF42943) { - debug_print(INFO, "Was able to locate video memory at 0x%x without dicking around.", lfb_vid_memory); - goto mem_found; - } + debug_print(WARNING, "Mode was set by bootloader: %dx%d bpp should be 32, framebuffer is at 0x%x", w, h, (uintptr_t)lfb_vid_memory); + + for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + w * h * 4; i += 0x1000) { + page_t * p = get_page(i, 1, kernel_directory); + dma_frame(p, 0, 1, i); + p->pat = 1; + p->writethrough = 1; + p->cachedisable = 1; } - - for (int i = 2; i < 1000; i += 2) { - herp[i] = 0xFF00FF00; - herp[i+1] = 0x00FF00FF; - } - - for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) { - /* Enable the higher memory */ - for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); - } - - /* Go find it */ - for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) { - if (((uintptr_t *)x)[0] == 0xA5ADFACE && ((uintptr_t *)x)[1] == 0xFAF42943) { - lfb_vid_memory = (uint8_t *)x; - debug_print(INFO, "Had to futz around, but found video memory at 0x%x", lfb_vid_memory); - goto mem_found; - } - } - } - - for (int i = 2; i < 1000; i += 2) { - herp[i] = 0xFF00FF00; - herp[i+1] = 0xFF00FF00; - } - - debug_print(WARNING, "Failed to locate video memory. This could end poorly."); - -mem_found: - finalize_graphics(w,h,b,w*4); - + finalize_graphics("preset"); } #define SVGA_IO_BASE (vmware_io) @@ -421,7 +416,7 @@ static uint32_t vmware_read(int reg) { return inportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE); } -static void vmware_set_mode(uint16_t w, uint16_t h) { +static void vmware_set_resolution(uint16_t w, uint16_t h) { vmware_write(SVGA_REG_ENABLE, 0); vmware_write(SVGA_REG_ID, 0); vmware_write(SVGA_REG_WIDTH, w); @@ -434,11 +429,10 @@ static void vmware_set_mode(uint16_t w, uint16_t h) { lfb_resolution_x = w; lfb_resolution_s = bpl; lfb_resolution_y = h; - + lfb_resolution_b = 32; } static void graphics_install_vmware(uint16_t w, uint16_t h) { - debug_print(WARNING, "Please note that the `vmware` display driver is experimental."); pci_scan(vmware_scan_pci, -1, &vmware_io); if (!vmware_io) { @@ -448,15 +442,8 @@ static void graphics_install_vmware(uint16_t w, uint16_t h) { debug_print(WARNING, "vmware io base: 0x%x", vmware_io); } - vmware_write(SVGA_REG_ID, 0); - vmware_write(SVGA_REG_WIDTH, w); - vmware_write(SVGA_REG_HEIGHT, h); - vmware_write(SVGA_REG_BITS_PER_PIXEL, 32); - vmware_write(SVGA_REG_ENABLE, 1); - - uint32_t bpl = vmware_read(SVGA_REG_BYTES_PER_LINE); - - lfb_resolution_impl = &vmware_set_mode; + vmware_set_resolution(w,h); + lfb_resolution_impl = &vmware_set_resolution; uint32_t fb_addr = vmware_read(SVGA_REG_FB_START); debug_print(WARNING, "vmware fb address: 0x%x", fb_addr); @@ -469,10 +456,14 @@ static void graphics_install_vmware(uint16_t w, uint16_t h) { uintptr_t fb_offset = (uintptr_t)lfb_vid_memory; for (uintptr_t i = fb_offset; i <= fb_offset + fb_size; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + page_t * p = get_page(i, 1, kernel_directory); + dma_frame(p, 0, 1, i); + p->pat = 1; + p->writethrough = 1; + p->cachedisable = 1; } - finalize_graphics(w,h,32,bpl); + finalize_graphics("vmware"); } struct disp_mode { @@ -495,7 +486,6 @@ static void auto_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) } } - static int init(void) { if (mboot_ptr->vbe_mode_info) { @@ -512,8 +502,8 @@ static int init(void) { uint16_t x, y; if (argc < 3) { - x = 1024; - y = 768; + x = PREFERRED_W; + y = PREFERRED_H; } else { x = atoi(argv[1]); y = atoi(argv[2]); @@ -521,7 +511,7 @@ static int init(void) { if (!strcmp(argv[0], "auto")) { /* Attempt autodetection */ - debug_print(WARNING, "Autodetect is in beta, this may not work."); + debug_print(NOTICE, "Automatically detecting display driver..."); struct disp_mode mode = {x,y,0}; pci_scan(auto_scan_pci, -1, &mode); if (!mode.set) { @@ -530,10 +520,12 @@ static int init(void) { } else if (!strcmp(argv[0], "qemu")) { /* Bochs / Qemu Video Device */ graphics_install_bochs(x,y); - } else if (!strcmp(argv[0],"preset")) { - graphics_install_preset(x,y); } else if (!strcmp(argv[0],"vmware")) { + /* VMware SVGA */ graphics_install_vmware(x,y); + } else if (!strcmp(argv[0],"preset")) { + /* Set by bootloader (UEFI) */ + graphics_install_preset(x,y); } else { debug_print(WARNING, "Unrecognized video adapter: %s", argv[0]); } diff --git a/modules/net.c b/modules/net.c index 1c8e6d62..90eb0d35 100644 --- a/modules/net.c +++ b/modules/net.c @@ -1,15 +1,18 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include static hashmap_t * dns_cache; static list_t * dns_waiters = NULL; @@ -29,6 +32,61 @@ static struct netif _netif = {0}; static int tasklet_pid = 0; +uint32_t get_primary_dns(void); + +static uint32_t netif_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char * buf = malloc(4096); + + struct netif * netif = &_netif; + char ip[16]; + ip_ntoa(netif->source, ip); + char dns[16]; + ip_ntoa(get_primary_dns(), dns); + char gw[16]; + ip_ntoa(netif->gateway, gw); + + if (netif->hwaddr[0] == 0 && + netif->hwaddr[1] == 0 && + netif->hwaddr[2] == 0 && + netif->hwaddr[3] == 0 && + netif->hwaddr[4] == 0 && + netif->hwaddr[5] == 0) { + + sprintf(buf, "no network\n"); + } else { + sprintf(buf, + "ip:\t%s\n" + "mac:\t%2x:%2x:%2x:%2x:%2x:%2x\n" + "device:\t%s\n" + "dns:\t%s\n" + "gateway:\t%s\n" + , + ip, + netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5], + netif->driver, + dns, + gw + ); + } + + size_t _bsize = strlen(buf); + if (offset > _bsize) { + free(buf); + return 0; + } + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + free(buf); + return size; +} + +static struct procfs_entry netif_entry = { + 0, /* filled by install */ + "netif", + netif_func, +}; + void init_netif_funcs(get_mac_func mac_func, get_packet_func get_func, send_packet_func send_func, char * device) { _netif.get_mac = mac_func; _netif.get_packet = get_func; @@ -36,6 +94,13 @@ void init_netif_funcs(get_mac_func mac_func, get_packet_func get_func, send_pack _netif.driver = device; memcpy(_netif.hwaddr, _netif.get_mac(), sizeof(_netif.hwaddr)); + if (!netif_entry.id) { + int (*procfs_install)(struct procfs_entry *) = (int (*)(struct procfs_entry *))(uintptr_t)hashmap_get(modules_get_symbols(),"procfs_install"); + if (procfs_install) { + procfs_install(&netif_entry); + } + } + if (!tasklet_pid) { tasklet_pid = create_kernel_tasklet(net_handler, "[net]", NULL); debug_print(NOTICE, "Network worker tasklet started with pid %d", tasklet_pid); @@ -337,6 +402,10 @@ static void socket_alert_waiters(struct socket * sock) { static int socket_check(fs_node_t * node) { struct socket * sock = node->device; + if (sock->bytes_available) { + return 0; + } + if (sock->packet_queue->length > 0) { return 0; } @@ -737,7 +806,7 @@ size_t net_recv(struct socket* socket, uint8_t* buffer, size_t len) { free(node); } - size_to_read = MIN(len, offset + socket->bytes_available); + size_to_read = MIN(len, socket->bytes_available); if (tcpdata->payload != 0) { memcpy(buffer + offset, tcpdata->payload + socket->bytes_read, size_to_read); @@ -746,8 +815,8 @@ size_t net_recv(struct socket* socket, uint8_t* buffer, size_t len) { offset += size_to_read; if (size_to_read < socket->bytes_available) { - socket->bytes_available = socket->bytes_available - size_to_read; - socket->bytes_read = size_to_read; + socket->bytes_available -= size_to_read; + socket->bytes_read += size_to_read; socket->current_packet = tcpdata; } else { socket->bytes_available = 0; diff --git a/modules/packetfs.c b/modules/packetfs.c index 86ed8215..15787314 100644 --- a/modules/packetfs.c +++ b/modules/packetfs.c @@ -1,14 +1,15 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + +#include #define MAX_PACKET_SIZE 1024 @@ -379,8 +380,8 @@ static fs_node_t * finddir_packetfs(fs_node_t * node, char * name) { return NULL; } -static void create_packetfs(fs_node_t *parent, char *name, uint16_t permission) { - if (!name) return; +static int create_packetfs(fs_node_t *parent, char *name, uint16_t permission) { + if (!name) return -EINVAL; pex_t * p = (pex_t *)parent->device; @@ -393,7 +394,7 @@ static void create_packetfs(fs_node_t *parent, char *name, uint16_t permission) if (!strcmp(name, t->name)) { spin_unlock(p->lock); /* Already exists */ - return; + return -EEXIST; } } @@ -412,14 +413,15 @@ static void create_packetfs(fs_node_t *parent, char *name, uint16_t permission) spin_unlock(p->lock); + return 0; } static void destroy_pex(pex_ex_t * p) { /* XXX */ } -static void unlink_packetfs(fs_node_t *parent, char *name) { - if (!name) return; +static int unlink_packetfs(fs_node_t *parent, char *name) { + if (!name) return -EINVAL; pex_t * p = (pex_t *)parent->device; @@ -441,9 +443,14 @@ static void unlink_packetfs(fs_node_t *parent, char *name) { if (i >= 0) { list_remove(p->exchanges, i); + } else { + spin_unlock(p->lock); + return -ENOENT; } spin_unlock(p->lock); + + return 0; } static fs_node_t * packetfs_manager(void) { diff --git a/modules/pcnet.c b/modules/pcnet.c index 86734625..6456c8ec 100644 --- a/modules/pcnet.c +++ b/modules/pcnet.c @@ -1,17 +1,18 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016 Kevin Lange + * Copyright (C) 2016-2018 K. Lange */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include static list_t * net_queue = NULL; static spin_lock_t net_queue_lock = { 0 }; @@ -208,8 +209,8 @@ static void pcnet_init(void * data, char * name) { pcnet_io_base = pci_read_field(pcnet_device_pci, PCI_BAR0, 4) & 0xFFFFFFF0; pcnet_mem_base = pci_read_field(pcnet_device_pci, PCI_BAR1, 4) & 0xFFFFFFF0; - pcnet_irq = pci_read_field(pcnet_device_pci, PCI_INTERRUPT_LINE, 1); - irq_install_handler(pcnet_irq, pcnet_irq_handler); + pcnet_irq = pci_get_interrupt(pcnet_device_pci); + irq_install_handler(pcnet_irq, pcnet_irq_handler, "pcnet"); debug_print(NOTICE, "irq line: %d", pcnet_irq); debug_print(NOTICE, "io base: 0x%x", pcnet_io_base); diff --git a/modules/pcspkr.c b/modules/pcspkr.c index 6a74b965..51cd0692 100644 --- a/modules/pcspkr.c +++ b/modules/pcspkr.c @@ -1,11 +1,11 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include +#include +#include +#include static void note(int length, int freq) { @@ -69,4 +69,3 @@ static int fini(void) { } MODULE_DEF(pcspkr, init, fini); -MODULE_DEPENDS(debugshell); diff --git a/modules/portio.c b/modules/portio.c new file mode 100644 index 00000000..7aeeb415 --- /dev/null +++ b/modules/portio.c @@ -0,0 +1,84 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * provides /dev/port + * + */ + +#include +#include +#include + +static uint32_t read_port(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + switch (size) { + case 1: + buffer[0] = inportb(offset); + break; + case 2: + ((uint16_t *)buffer)[0] = inports(offset); + break; + case 4: + ((uint32_t *)buffer)[0] = inportl(offset); + break; + default: + for (unsigned int i = 0; i < size; ++i) { + buffer[i] = inportb(offset + i); + } + break; + } + + return size; +} + +static uint32_t write_port(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + switch (size) { + case 1: + outportb(offset, buffer[0]); + break; + case 2: + outports(offset, ((uint16_t*)buffer)[0]); + break; + case 4: + outportl(offset, ((uint32_t*)buffer)[0]); + break; + default: + for (unsigned int i = 0; i < size; ++i) { + outportb(offset +i, buffer[i]); + } + break; + } + + return size; +} + +static fs_node_t * port_device_create(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "port"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + fnode->flags = FS_CHARDEVICE; + fnode->read = read_port; + fnode->write = write_port; + fnode->open = NULL; + fnode->close = NULL; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; + return fnode; +} + +static int port_initialize(void) { + vfs_mount("/dev/port", port_device_create()); + return 0; +} + +static int port_finalize(void) { + return 0; +} + +MODULE_DEF(portio, port_initialize, port_finalize); diff --git a/modules/procfs.c b/modules/procfs.c index 8e42e824..baf00be7 100644 --- a/modules/procfs.c +++ b/modules/procfs.c @@ -1,27 +1,22 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define PROCFS_STANDARD_ENTRIES (sizeof(std_entries) / sizeof(struct procfs_entry)) #define PROCFS_PROCDIR_ENTRIES (sizeof(procdir_entries) / sizeof(struct procfs_entry)) -struct procfs_entry { - int id; - char * name; - read_type_t func; -}; - static fs_node_t * procfs_generic_create(char * name, read_type_t read_func) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); @@ -86,6 +81,53 @@ static uint32_t proc_cmdline_func(fs_node_t *node, uint32_t offset, uint32_t siz return size; } +static size_t calculate_memory_usage(page_directory_t * src) { + size_t pages = 0; + for (uint32_t i = 0; i < 1024; ++i) { + if (!src->tables[i] || (uintptr_t)src->tables[i] == (uintptr_t)0xFFFFFFFF) { + continue; + } + if (kernel_directory->tables[i] == src->tables[i]) { + continue; + } + /* For each table */ + if (i * 0x1000 * 1024 < SHM_START) { + /* Ignore shared memory for now */ + for (int j = 0; j < 1024; ++j) { + /* For each frame in the table... */ + if (!src->tables[i]->pages[j].frame) { + continue; + } + pages++; + } + } + } + return pages; +} + +static size_t calculate_shm_resident(page_directory_t * src) { + size_t pages = 0; + for (uint32_t i = 0; i < 1024; ++i) { + if (!src->tables[i] || (uintptr_t)src->tables[i] == (uintptr_t)0xFFFFFFFF) { + continue; + } + if (kernel_directory->tables[i] == src->tables[i]) { + continue; + } + if (i * 0x1000 * 1024 < SHM_START) { + continue; + } + for (int j = 0; j < 1024; ++j) { + /* For each frame in the table... */ + if (!src->tables[i]->pages[j].frame) { + continue; + } + pages++; + } + } + return pages; +} + static uint32_t proc_status_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[2048]; process_t * proc = process_from_pid(node->inode); @@ -96,7 +138,7 @@ static uint32_t proc_status_func(fs_node_t *node, uint32_t offset, uint32_t size return 0; } - char state = process_is_ready(proc) ? 'R' : 'S'; + char state = proc->finished ? 'Z' : (process_is_ready(proc) ? 'R' : 'S'); char * name = proc->name + strlen(proc->name) - 1; while (1) { @@ -108,6 +150,11 @@ static uint32_t proc_status_func(fs_node_t *node, uint32_t offset, uint32_t size name--; } + /* Calculate process memory usage */ + int mem_usage = calculate_memory_usage(proc->thread.page_directory) * 4; + int shm_usage = calculate_shm_resident(proc->thread.page_directory) * 4; + int mem_permille = 1000 * (mem_usage + shm_usage) / memory_total(); + sprintf(buf, "Name:\t%s\n" /* name */ "State:\t%c\n" /* yeah, do this at some point */ @@ -122,7 +169,11 @@ static uint32_t proc_status_func(fs_node_t *node, uint32_t offset, uint32_t size "SC2:\t0x%x\n" "SC3:\t0x%x\n" "SC4:\t0x%x\n" + "UserStack:\t0x%x\n" "Path:\t%s\n" + "VmSize:\t %d kB\n" + "RssShmem:\t %d kB\n" + "MemPermille:\t %d\n" , name, state, @@ -137,7 +188,9 @@ static uint32_t proc_status_func(fs_node_t *node, uint32_t offset, uint32_t size proc->syscall_registers ? proc->syscall_registers->edx : 0, proc->syscall_registers ? proc->syscall_registers->esi : 0, proc->syscall_registers ? proc->syscall_registers->edi : 0, - proc->cmdline ? proc->cmdline[0] : "(none)" + proc->syscall_registers ? proc->syscall_registers->useresp : 0, + proc->cmdline ? proc->cmdline[0] : "(none)", + mem_usage, shm_usage, mem_permille ); size_t _bsize = strlen(buf); @@ -220,8 +273,41 @@ static fs_node_t * procfs_procdir_create(process_t * process) { return fnode; } +#define cpuid(in,a,b,c,d) do { asm volatile ("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(in)); } while(0) + static uint32_t cpuinfo_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - return 0; + char buf[1024]; + + unsigned long a, b, unused;; + cpuid(0,unused,b,unused,unused); + + char * _manu = "Unknown"; + int _model = 0, _family = 0; + + if (b == 0x756e6547) { + cpuid(1, a, b, unused, unused); + _manu = "Intel"; + _model = (a >> 4) & 0x0F; + _family = (a >> 8) & 0x0F; + } else if (b == 0x68747541) { + cpuid(1, a, unused, unused, unused); + _manu = "AMD"; + _model = (a >> 4) & 0x0F; + _family = (a >> 8) & 0x0F; + } + + sprintf(buf, + "Manufacturer: %s\n" + "Family: %d\n" + "Model: %d\n" + , _manu, _family, _model); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; } extern uintptr_t heap_end; @@ -232,6 +318,9 @@ static uint32_t meminfo_func(fs_node_t *node, uint32_t offset, uint32_t size, ui unsigned int total = memory_total(); unsigned int free = total - memory_use(); unsigned int kheap = (heap_end - kernel_heap_alloc_point) / 1024; + + + sprintf(buf, "MemTotal: %d kB\n" "MemFree: %d kB\n" @@ -246,6 +335,60 @@ static uint32_t meminfo_func(fs_node_t *node, uint32_t offset, uint32_t size, ui return size; } +static uint32_t pat_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char buf[1024]; + + uint64_t pat_values; + asm volatile ( "rdmsr" : "=A" (pat_values) : "c" (0x277) ); + + char * pat_names[] = { + "uncacheable (UC)", + "write combining (WC)", + "Reserved", + "Reserved", + "write through (WT)", + "write protected (WP)", + "write back (WB)", + "uncached (UC-)" + }; + + int pa_0 = (pat_values >> 0) & 0x7; + int pa_1 = (pat_values >> 8) & 0x7; + int pa_2 = (pat_values >> 16) & 0x7; + int pa_3 = (pat_values >> 24) & 0x7; + int pa_4 = (pat_values >> 32) & 0x7; + int pa_5 = (pat_values >> 40) & 0x7; + int pa_6 = (pat_values >> 48) & 0x7; + int pa_7 = (pat_values >> 56) & 0x7; + + sprintf(buf, + "PA0: %d %s\n" + "PA1: %d %s\n" + "PA2: %d %s\n" + "PA3: %d %s\n" + "PA4: %d %s\n" + "PA5: %d %s\n" + "PA6: %d %s\n" + "PA7: %d %s\n", + pa_0, pat_names[pa_0], + pa_1, pat_names[pa_1], + pa_2, pat_names[pa_2], + pa_3, pat_names[pa_3], + pa_4, pat_names[pa_4], + pa_5, pat_names[pa_5], + pa_6, pat_names[pa_6], + pa_7, pat_names[pa_7] + ); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; +} + + static uint32_t uptime_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { char buf[1024]; sprintf(buf, "%d.%3d\n", timer_ticks, timer_subticks); @@ -303,7 +446,7 @@ static uint32_t compiler_func(fs_node_t *node, uint32_t offset, uint32_t size, u if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; - memcpy(buffer, buf, size); + memcpy(buffer, buf + offset, size); return size; } @@ -344,68 +487,192 @@ static uint32_t mounts_func(fs_node_t *node, uint32_t offset, uint32_t size, uin mount_recurse(buf, fs_tree->root, 0); size_t _bsize = strlen(buf); - if (offset > _bsize) return 0; + if (offset > _bsize) { + free(buf); + return 0; + } if (size > _bsize - offset) size = _bsize - offset; - memcpy(buffer, buf, size); + memcpy(buffer, buf + offset, size); free(buf); return size; } -static uint32_t netif_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - char * buf = malloc(4096); +static uint32_t modules_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + list_t * hash_keys = hashmap_keys(modules_get_list()); + char * buf = malloc(hash_keys->length * 512); + unsigned int soffset = 0; + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + module_data_t * mod_info = hashmap_get(modules_get_list(), key); - /* In order to not directly depend on the network module, we dynamically locate the symbols we need. */ - void (*ip_ntoa)(uint32_t, char *) = (void (*)(uint32_t,char*))(uintptr_t)hashmap_get(modules_get_symbols(),"ip_ntoa"); + soffset += sprintf(&buf[soffset], "0x%x {.init=0x%x, .fini=0x%x} %s", + mod_info->bin_data, + mod_info->mod_info->initialize, + mod_info->mod_info->finalize, + mod_info->mod_info->name); - struct netif * (*get_netif)(void) = (struct netif *(*)(void))(uintptr_t)hashmap_get(modules_get_symbols(),"get_default_network_interface"); - - uint32_t (*get_dns)(void) = (uint32_t (*)(void))(uintptr_t)hashmap_get(modules_get_symbols(),"get_primary_dns"); - - if (get_netif) { - struct netif * netif = get_netif(); - char ip[16]; - ip_ntoa(netif->source, ip); - char dns[16]; - ip_ntoa(get_dns(), dns); - char gw[16]; - ip_ntoa(netif->gateway, gw); - - if (netif->hwaddr[0] == 0 && - netif->hwaddr[1] == 0 && - netif->hwaddr[2] == 0 && - netif->hwaddr[3] == 0 && - netif->hwaddr[4] == 0 && - netif->hwaddr[5] == 0) { - - sprintf(buf, "no network\n"); - } else { - sprintf(buf, - "ip:\t%s\n" - "mac:\t%2x:%2x:%2x:%2x:%2x:%2x\n" - "device:\t%s\n" - "dns:\t%s\n" - "gateway:\t%s\n" - , - ip, - netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5], - netif->driver, - dns, - gw - ); + if (mod_info->deps) { + unsigned int i = 0; + soffset += sprintf(&buf[soffset], " Deps: "); + while (i < mod_info->deps_length) { + /* Skip padding bytes */ + if (strlen(&mod_info->deps[i])) { + soffset += sprintf(&buf[soffset], "%s ", &mod_info->deps[i]); + } + i += strlen(&mod_info->deps[i]) + 1; + } } + + soffset += sprintf(&buf[soffset], "\n"); + } + free(hash_keys); + + size_t _bsize = strlen(buf); + if (offset > _bsize) { + free(buf); + return 0; + } + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + free(buf); + return size; +} + +extern hashmap_t * fs_types; /* from kernel/fs/vfs.c */ + +static uint32_t filesystems_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + list_t * hash_keys = hashmap_keys(fs_types); + char * buf = malloc(hash_keys->length * 512); + unsigned int soffset = 0; + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + soffset += sprintf(&buf[soffset], "%s\n", key); + } + free(hash_keys); + + size_t _bsize = strlen(buf); + if (offset > _bsize) { + free(buf); + return 0; + } + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + free(buf); + return size; +} + +static uint32_t loader_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char * buf = malloc(512); + + if (mboot_ptr->flags & MULTIBOOT_FLAG_LOADER) { + sprintf(buf, "%s\n", mboot_ptr->boot_loader_name); } else { - sprintf(buf, "no network\n"); + buf[0] = '\n'; + buf[1] = '\0'; } size_t _bsize = strlen(buf); - if (offset > _bsize) return 0; + if (offset > _bsize) { + free(buf); + return 0; + } if (size > _bsize - offset) size = _bsize - offset; - memcpy(buffer, buf, size); + memcpy(buffer, buf + offset, size); free(buf); return size; +} +extern char * get_irq_handler(int irq, int chain); + +static uint32_t irq_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char * buf = malloc(4096); + unsigned int soffset = 0; + + for (int i = 0; i < 16; ++i) { + soffset += sprintf(&buf[soffset], "irq %d: ", i); + for (int j = 0; j < 4; ++j) { + char * t = get_irq_handler(i, j); + if (!t) break; + soffset += sprintf(&buf[soffset], "%s%s", j ? "," : "", t); + } + soffset += sprintf(&buf[soffset], "\n"); + } + + size_t _bsize = strlen(buf); + if (offset > _bsize) { + free(buf); + return 0; + } + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + free(buf); + return size; +} + +/** + * Basically the same as the kdebug `pci` command. + */ +struct _pci_buf { + size_t offset; + char *buffer; +}; + +static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + + struct _pci_buf * b = extra; + + b->offset += sprintf(b->buffer + b->offset, "%2x:%2x.%d (%4x, %4x:%4x) %s %s\n", + (int)pci_extract_bus(device), + (int)pci_extract_slot(device), + (int)pci_extract_func(device), + (int)pci_find_type(device), + vendorid, + deviceid, + pci_vendor_lookup(vendorid), + pci_device_lookup(vendorid,deviceid)); + + b->offset += sprintf(b->buffer + b->offset, " BAR0: 0x%8x", pci_read_field(device, PCI_BAR0, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR1: 0x%8x", pci_read_field(device, PCI_BAR1, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR2: 0x%8x", pci_read_field(device, PCI_BAR2, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR3: 0x%8x", pci_read_field(device, PCI_BAR3, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR4: 0x%8x", pci_read_field(device, PCI_BAR4, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR6: 0x%8x\n", pci_read_field(device, PCI_BAR5, 4)); + + b->offset += sprintf(b->buffer + b->offset, " IRQ Line: %d", pci_read_field(device, 0x3C, 1)); + b->offset += sprintf(b->buffer + b->offset, " IRQ Pin: %d", pci_read_field(device, 0x3D, 1)); + b->offset += sprintf(b->buffer + b->offset, " Interrupt: %d", pci_get_interrupt(device)); + b->offset += sprintf(b->buffer + b->offset, " Status: 0x%4x\n", pci_read_field(device, PCI_STATUS, 2)); +} + +static void scan_count(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + size_t * count = extra; + (*count)++; +} + +static uint32_t pci_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + size_t count = 0; + pci_scan(&scan_count, -1, &count); + + struct _pci_buf b = {0,NULL}; + b.buffer = malloc(count * 1024); + + pci_scan(&scan_hit_list, -1, &b); + + size_t _bsize = b.offset; + if (offset > _bsize) { + free(b.buffer); + return 0; + } + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, b.buffer + offset, size); + free(b.buffer); + return size; } static struct procfs_entry std_entries[] = { @@ -416,9 +683,29 @@ static struct procfs_entry std_entries[] = { {-5, "version", version_func}, {-6, "compiler", compiler_func}, {-7, "mounts", mounts_func}, - {-8, "netif", netif_func}, + {-8, "modules", modules_func}, + {-9, "filesystems", filesystems_func}, + {-10,"loader", loader_func}, + {-11,"irq", irq_func}, + {-12,"pat", pat_func}, + {-13,"pci", pci_func}, }; +static list_t * extended_entries = NULL; +static int next_id = 0; + +int procfs_install(struct procfs_entry * entry) { + if (!extended_entries) { + extended_entries = list_create(); + next_id = -PROCFS_STANDARD_ENTRIES - 1; + } + + entry->id = next_id--; + list_insert(extended_entries, entry); + + return 0; +} + static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) { if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); @@ -453,7 +740,29 @@ static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) { strcpy(out->name, std_entries[index].name); return out; } - int i = index - PROCFS_STANDARD_ENTRIES + 1; + + index -= PROCFS_STANDARD_ENTRIES; + + if (extended_entries) { + if (index < extended_entries->length) { + size_t i = 0; + node_t * n = extended_entries->head; + while (i < index) { + n = n->next; + i++; + } + + struct procfs_entry * e = n->value; + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = e->id; + strcpy(out->name, e->name); + return out; + } + index -= extended_entries->length; + } + + int i = index + 1; debug_print(WARNING, "%d %d %d", i, index, PROCFS_STANDARD_ENTRIES); @@ -506,6 +815,14 @@ static fs_node_t * finddir_procfs_root(fs_node_t * node, char * name) { } } + foreach(node, extended_entries) { + struct procfs_entry * e = node->value; + if (!strcmp(name, e->name)) { + fs_node_t * out = procfs_generic_create(e->name, e->func); + return out; + } + } + return NULL; } diff --git a/modules/ps2kbd.c b/modules/ps2kbd.c index 04f2e6d9..6814f7c4 100644 --- a/modules/ps2kbd.c +++ b/modules/ps2kbd.c @@ -1,7 +1,7 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2015 Kevin Lange + * Copyright (C) 2011-2018 K. Lange * * Low-level keyboard interrupt driver. * @@ -10,13 +10,12 @@ * */ -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include #define KEY_DEVICE 0x60 #define KEY_PENDING 0x64 @@ -62,7 +61,7 @@ static int keyboard_install(void) { vfs_mount("/dev/kbd", keyboard_pipe); /* Install the interrupt handler */ - irq_install_handler(KEY_IRQ, keyboard_handler); + irq_install_handler(KEY_IRQ, keyboard_handler, "ps2 kbd"); return 0; } diff --git a/modules/ps2mouse.c b/modules/ps2mouse.c index 5e17f295..7d7aed75 100644 --- a/modules/ps2mouse.c +++ b/modules/ps2mouse.c @@ -1,17 +1,17 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * Mouse driver * */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include static uint8_t mouse_cycle = 0; static uint8_t mouse_byte[4]; @@ -168,6 +168,11 @@ static int mouse_install(void) { debug_print(NOTICE, "Initializing PS/2 mouse interface"); uint8_t status, result; IRQ_OFF; + + while ((inportb(0x64) & 1)) { + inportb(0x60); + } + mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); mouse_wait(1); outportb(MOUSE_STATUS, 0xA8); @@ -184,6 +189,7 @@ static int mouse_install(void) { mouse_read(); mouse_write(0xF4); mouse_read(); + /* Try to enable scroll wheel (but not buttons) */ if (!args_present("nomousescroll")) { mouse_write(0xF2); @@ -209,7 +215,15 @@ static int mouse_install(void) { } } - irq_install_handler(MOUSE_IRQ, mouse_handler); + /* keyboard scancode set */ + mouse_wait(1); + outportb(MOUSE_PORT, 0xF0); + mouse_wait(1); + outportb(MOUSE_PORT, 0x02); + mouse_wait(1); + mouse_read(); + + irq_install_handler(MOUSE_IRQ, mouse_handler, "ps2 mouse"); IRQ_RES; uint8_t tmp = inportb(0x61); @@ -217,6 +231,10 @@ static int mouse_install(void) { outportb(0x61, tmp & 0x7F); inportb(MOUSE_PORT); + while ((inportb(0x64) & 1)) { + inportb(0x60); + } + mouse_pipe->flags = FS_CHARDEVICE; mouse_pipe->ioctl = ioctl_mouse; diff --git a/modules/random.c b/modules/random.c index f01c4172..d75cef94 100644 --- a/modules/random.c +++ b/modules/random.c @@ -1,17 +1,16 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * Provides access to the kernel RNG * */ -#include -#include -#include - -#include +#include +#include +#include +#include static uint32_t read_random(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); static uint32_t write_random(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); diff --git a/modules/rtl.c b/modules/rtl.c index 4743371e..8581dc7a 100644 --- a/modules/rtl.c +++ b/modules/rtl.c @@ -1,17 +1,18 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* XXX move this to ipv4? */ extern size_t print_dns_name(fs_node_t * tty, struct dns_packet * dns, size_t offset); @@ -301,9 +302,9 @@ int init_rtl(void) { debug_print(NOTICE, "COMMAND register after: 0x%4x\n", command_reg); } - rtl_irq = pci_read_field(rtl_device_pci, PCI_INTERRUPT_LINE, 1); + rtl_irq = pci_get_interrupt(rtl_device_pci); debug_print(NOTICE, "Interrupt Line: %x\n", rtl_irq); - irq_install_handler(rtl_irq, rtl_irq_handler); + irq_install_handler(rtl_irq, rtl_irq_handler, "rtl8139"); uint32_t rtl_bar0 = pci_read_field(rtl_device_pci, PCI_BAR0, 4); uint32_t rtl_bar1 = pci_read_field(rtl_device_pci, PCI_BAR1, 4); @@ -405,7 +406,7 @@ int init_rtl(void) { static int init(void) { pci_scan(&find_rtl, -1, &rtl_device_pci); if (!rtl_device_pci) { - debug_print(ERROR, "No RTL 8139 found?"); + debug_print(NOTICE, "No RTL 8139 found"); return 1; } init_rtl(); diff --git a/modules/serial.c b/modules/serial.c index 457c8e3d..6772169e 100644 --- a/modules/serial.c +++ b/modules/serial.c @@ -1,18 +1,18 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * Serial communication device * */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #define SERIAL_PORT_A 0x3F8 #define SERIAL_PORT_B 0x2F8 @@ -149,6 +149,9 @@ static int check_serial(fs_node_t * node) { return selectcheck_fs(*pipe_for_port((int)node->device)); } +static int have_installed_ac = 0; +static int have_installed_bd = 0; + static fs_node_t * serial_device_create(int device) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); @@ -176,9 +179,15 @@ static fs_node_t * serial_device_create(int device) { serial_enable(device); if (device == SERIAL_PORT_A || device == SERIAL_PORT_C) { - irq_install_handler(SERIAL_IRQ_AC, serial_handler_ac); + if (!have_installed_ac) { + irq_install_handler(SERIAL_IRQ_AC, serial_handler_ac, "serial ac"); + have_installed_ac = 1; + } } else { - irq_install_handler(SERIAL_IRQ_BD, serial_handler_bd); + if (!have_installed_bd) { + irq_install_handler(SERIAL_IRQ_BD, serial_handler_bd, "serial bd"); + have_installed_bd = 1; + } } *pipe_for_port(device) = make_pipe(128); @@ -203,7 +212,21 @@ static int serial_mount_devices(void) { char * c; if ((c = args_value("logtoserial"))) { debug_file = ttyS0; - debug_level = atoi(c); + if (!strcmp(c,"INFO") || !strcmp(c,"info")) { + debug_level = INFO; + } else if (!strcmp(c,"NOTICE") || !strcmp(c,"notice")) { + debug_level = NOTICE; + } else if (!strcmp(c,"WARNING") || !strcmp(c,"warning")) { + debug_level = WARNING; + } else if (!strcmp(c,"ERROR") || !strcmp(c,"error")) { + debug_level = ERROR; + } else if (!strcmp(c,"CRITICAL") || !strcmp(c,"critical")) { + debug_level = CRITICAL; + } else if (!strcmp(c,"INSANE") || !strcmp(c,"insane")) { + debug_level = INSANE; + } else { + debug_level = atoi(c); + } debug_print(NOTICE, "Serial logging enabled at level %d.", debug_level); } diff --git a/modules/snd.c b/modules/snd.c index 29cd91a0..9621c77e 100644 --- a/modules/snd.c +++ b/modules/snd.c @@ -11,13 +11,13 @@ * really support multiple devices despite the interface suggesting it might... */ -#include +#include +#include +#include +#include -#include -#include -#include -#include -#include +#include +#include /* Utility macros */ #define N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) diff --git a/modules/test-write.c b/modules/test-write.c deleted file mode 100644 index 51c8af21..00000000 --- a/modules/test-write.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include -#include -#include - -DEFINE_SHELL_FUNCTION(testwrite, "Test write") { - - fs_node_t * f = NULL; - char * file = "/dev/hdb"; - - if (argc > 1) { - file = argv[1]; - } - - f = kopen(file, 0); - - if (!f) { - fprintf(tty, "No device: %s\n", file); - return 1; - } - - char * s = malloc(1024); - - sprintf(s, "Hello World!"); - - write_fs(f, 0, strlen(s), (uint8_t *)s); - write_fs(f, 2, strlen(s), (uint8_t *)s); - write_fs(f, 523, strlen(s), (uint8_t *)s); - - write_fs(f, 1024*12, 1024, (uint8_t *)s); - - free(s); - - return 0; -} - -static int init(void) { - BIND_SHELL_FUNCTION(testwrite); - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(testwrite, init, fini); -MODULE_DEPENDS(debugshell); diff --git a/modules/test.c b/modules/test.c deleted file mode 100644 index 52bfcc83..00000000 --- a/modules/test.c +++ /dev/null @@ -1,58 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include -#include -#include - -#include - -extern char * special_thing; - -char test_module_string[] = "I am a char[] in the module."; -char * test_module_string_ptr = "I am a char * in the module."; - -int a_function(void) { - debug_print(WARNING, ("I am an exported function in the module.")); - return 42; -} - -DEFINE_SHELL_FUNCTION(test_mod, "A function installed by a module!") { - fprintf(tty, "Hello world!\n"); - return 0; -} - -static int hello(void) { - debug_print(NOTICE, special_thing); - a_function(); - debug_print(NOTICE, test_module_string); - debug_print(NOTICE, test_module_string_ptr); - - hashmap_t * map = hashmap_create(10); - - debug_print(NOTICE, "Inserting into hashmap..."); - - hashmap_set(map, "hello", (void *)"cake"); - debug_print(NOTICE, "getting value: %s", hashmap_get(map, "hello")); - - hashmap_free(map); - free(map); - - debug_shell_install(&shell_test_mod_desc); - BIND_SHELL_FUNCTION(test_mod); - - return 25; -} - -static int goodbye(void) { - debug_print(NOTICE, "Goodbye!"); - return 0; -} - -MODULE_DEF(test, hello, goodbye); -MODULE_DEPENDS(debugshell); - diff --git a/modules/testb.c b/modules/testb.c deleted file mode 100644 index 3f8bb4af..00000000 --- a/modules/testb.c +++ /dev/null @@ -1,26 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include -#include - -extern int a_function(void); - -static int hello(void) { - debug_print(NOTICE, "Calling a_function from other module."); - a_function(); - return 0; -} - -static int goodbye(void) { - debug_print(NOTICE, "Goodbye!"); - return 0; -} - -MODULE_DEF(testb, hello, goodbye); -MODULE_DEPENDS(test); - diff --git a/modules/tmpfs.c b/modules/tmpfs.c index 99d839dd..311471d8 100644 --- a/modules/tmpfs.c +++ b/modules/tmpfs.c @@ -1,17 +1,16 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include -#include - -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include /* 4KB */ #define BLOCKSIZE 0x1000 @@ -54,7 +53,7 @@ static struct tmpfs_file * tmpfs_file_new(char * name) { return t; } -static void symlink_tmpfs(fs_node_t * parent, char * target, char * name) { +static int symlink_tmpfs(fs_node_t * parent, char * target, char * name) { struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; debug_print(NOTICE, "Creating TMPFS file (symlink) %s in %s", name, d->name); @@ -64,7 +63,7 @@ static void symlink_tmpfs(fs_node_t * parent, char * target, char * name) { if (!strcmp(name, t->name)) { spin_unlock(tmpfs_lock); debug_print(WARNING, "... already exists."); - return; /* Already exists */ + return -EEXIST; /* Already exists */ } } spin_unlock(tmpfs_lock); @@ -75,9 +74,15 @@ static void symlink_tmpfs(fs_node_t * parent, char * target, char * name) { debug_print(NOTICE, "symlink target is [%s]", target); t->target = strdup(target); + t->mask = 0777; + t->uid = current_process->user; + t->gid = current_process->user; + spin_lock(tmpfs_lock); list_insert(d->files, t); spin_unlock(tmpfs_lock); + + return 0; } static int readlink_tmpfs(fs_node_t * node, char * buf, size_t size) { @@ -88,12 +93,12 @@ static int readlink_tmpfs(fs_node_t * node, char * buf, size_t size) { } if (size < strlen(t->target) + 1) { - debug_print(WARNING, "Requested read size was only %d, need %d.", size, strlen(t->target)+1); + debug_print(INFO, "Requested read size was only %d, need %d.", size, strlen(t->target)+1); memcpy(buf, t->target, size); buf[size] = '\0'; return size-1; } else { - debug_print(WARNING, "Reading link target is [%s]", t->target); + debug_print(INFO, "Reading link target is [%s]", t->target); memcpy(buf, t->target, strlen(t->target) + 1); return strlen(t->target); } @@ -270,7 +275,7 @@ static int chmod_tmpfs(fs_node_t * node, int mode) { static int chown_tmpfs(fs_node_t * node, int uid, int gid) { struct tmpfs_file * t = (struct tmpfs_file *)(node->device); - debug_print(WARNING, "chown(..., %d, %d)", uid, gid); + debug_print(INFO, "chown(..., %d, %d)", uid, gid); t->uid = uid; t->gid = gid; @@ -281,10 +286,10 @@ static int chown_tmpfs(fs_node_t * node, int uid, int gid) { static void open_tmpfs(fs_node_t * node, unsigned int flags) { struct tmpfs_file * t = (struct tmpfs_file *)(node->device); - debug_print(WARNING, "---- Opened TMPFS file %s with flags 0x%x ----", t->name, flags); + debug_print(INFO, "---- Opened TMPFS file %s with flags 0x%x ----", t->name, flags); if (flags & O_TRUNC) { - debug_print(WARNING, "Truncating file %s", t->name); + debug_print(INFO, "Truncating file %s", t->name); for (size_t i = 0; i < t->block_count; ++i) { clear_frame((uintptr_t)t->blocks[i] * 0x1000); t->blocks[i] = 0; @@ -404,7 +409,7 @@ static fs_node_t * finddir_tmpfs(fs_node_t * node, char * name) { return NULL; } -static void unlink_tmpfs(fs_node_t * node, char * name) { +static int unlink_tmpfs(fs_node_t * node, char * name) { struct tmpfs_dir * d = (struct tmpfs_dir *)node->device; int i = -1, j = 0; spin_lock(tmpfs_lock); @@ -422,14 +427,17 @@ static void unlink_tmpfs(fs_node_t * node, char * name) { if (i >= 0) { list_remove(d->files, i); + } else { + spin_unlock(tmpfs_lock); + return -ENOENT; } spin_unlock(tmpfs_lock); - return; + return 0; } -static void create_tmpfs(fs_node_t *parent, char *name, uint16_t permission) { - if (!name) return; +static int create_tmpfs(fs_node_t *parent, char *name, uint16_t permission) { + if (!name) return -EINVAL; struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; debug_print(NOTICE, "Creating TMPFS file %s in %s", name, d->name); @@ -440,7 +448,7 @@ static void create_tmpfs(fs_node_t *parent, char *name, uint16_t permission) { if (!strcmp(name, t->name)) { spin_unlock(tmpfs_lock); debug_print(WARNING, "... already exists."); - return; /* Already exists */ + return -EEXIST; /* Already exists */ } } spin_unlock(tmpfs_lock); @@ -454,10 +462,12 @@ static void create_tmpfs(fs_node_t *parent, char *name, uint16_t permission) { spin_lock(tmpfs_lock); list_insert(d->files, t); spin_unlock(tmpfs_lock); + + return 0; } -static void mkdir_tmpfs(fs_node_t * parent, char * name, uint16_t permission) { - if (!name) return; +static int mkdir_tmpfs(fs_node_t * parent, char * name, uint16_t permission) { + if (!name) return -EINVAL; struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; debug_print(NOTICE, "Creating TMPFS directory %s (in %s)", name, d->name); @@ -468,7 +478,7 @@ static void mkdir_tmpfs(fs_node_t * parent, char * name, uint16_t permission) { if (!strcmp(name, t->name)) { spin_unlock(tmpfs_lock); debug_print(WARNING, "... already exists."); - return; /* Already exists */ + return -EEXIST; /* Already exists */ } } spin_unlock(tmpfs_lock); @@ -482,6 +492,8 @@ static void mkdir_tmpfs(fs_node_t * parent, char * name, uint16_t permission) { spin_lock(tmpfs_lock); list_insert(d->files, out); spin_unlock(tmpfs_lock); + + return 0; } static fs_node_t * tmpfs_from_dir(struct tmpfs_dir * d) { diff --git a/modules/usbuhci.c b/modules/usbuhci.c index d9873224..7cb0634f 100644 --- a/modules/usbuhci.c +++ b/modules/usbuhci.c @@ -1,13 +1,13 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include static uint32_t hub_device = 0; diff --git a/modules/vbox.c b/modules/vbox.c new file mode 100644 index 00000000..603ac752 --- /dev/null +++ b/modules/vbox.c @@ -0,0 +1,465 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016-2018 K. Lange + * + * VirtualBox Guest Additions driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VBOX_VENDOR_ID 0x80EE +#define VBOX_DEVICE_ID 0xCAFE + +static void vbox_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { + if (v == VBOX_VENDOR_ID && d == VBOX_DEVICE_ID) { + *((uint32_t *)extra) = device; + } +} + +#define VMM_GetMouseState 1 +#define VMM_SetMouseState 2 +#define VMM_SetPointerShape 3 +#define VMM_AcknowledgeEvents 41 +#define VMM_ReportGuestInfo 50 +#define VMM_GetDisplayChangeRequest 51 +#define VMM_ReportGuestCapabilities 55 +#define VMM_VideoSetVisibleRegion 72 + +#define VMMCAP_SeamlessMode (1 << 0) +#define VMMCAP_HostWindows (1 << 1) +#define VMMCAP_Graphics (1 << 2) + +#define VMMDEV_VERSION 0x00010003 +#define VBOX_REQUEST_HEADER_VERSION 0x10001 +struct vbox_header { + uint32_t size; + uint32_t version; + uint32_t requestType; + int32_t rc; + uint32_t reserved1; + uint32_t reserved2; +}; + +struct vbox_guest_info { + struct vbox_header header; + uint32_t version; + uint32_t ostype; +}; + +struct vbox_guest_caps { + struct vbox_header header; + uint32_t caps; +}; + +struct vbox_ack_events { + struct vbox_header header; + uint32_t events; +}; + +struct vbox_display_change { + struct vbox_header header; + uint32_t xres; + uint32_t yres; + uint32_t bpp; + uint32_t eventack; +}; + +struct vbox_mouse { + struct vbox_header header; + uint32_t features; + int32_t x; + int32_t y; +}; + +struct vbox_rtrect { + int32_t xLeft; + int32_t yTop; + int32_t xRight; + int32_t yBottom; +}; + +struct vbox_visibleregion { + struct vbox_header header; + uint32_t count; + struct vbox_rtrect rect[1]; +}; + +struct vbox_pointershape { + struct vbox_header header; + uint32_t flags; + uint32_t xHot; + uint32_t yHot; + uint32_t width; + uint32_t height; + unsigned char data[]; +}; + + +#define EARLY_LOG_DEVICE 0x504 +static uint32_t _vbox_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + for (unsigned int i = 0; i < size; ++i) { + outportb(EARLY_LOG_DEVICE, buffer[i]); + } + return size; +} +static fs_node_t vb = { .write = &_vbox_write }; + +static uint32_t vbox_device = 0; +static uint32_t vbox_port = 0x0; +static int vbox_irq = 0; + +static struct vbox_ack_events * vbox_irq_ack; +static uint32_t vbox_phys_ack; +static struct vbox_display_change * vbox_disp; +static uint32_t vbox_phys_disp; +static struct vbox_mouse * vbox_m; +static uint32_t vbox_phys_mouse; +static struct vbox_mouse * vbox_mg; +static uint32_t vbox_phys_mouse_get; +static struct vbox_visibleregion * vbox_visibleregion; +static uint32_t vbox_phys_visibleregion; +static struct vbox_pointershape * vbox_pointershape = NULL; +static uint32_t vbox_phys_pointershape; + +static volatile uint32_t * vbox_vmmdev = 0; + +static fs_node_t * mouse_pipe; +static fs_node_t * rect_pipe; +static fs_node_t * pointer_pipe; + +static int mouse_state; + +#define PACKETS_IN_PIPE 1024 +#define DISCARD_POINT 32 + +static int vbox_irq_handler(struct regs *r) { + if (!vbox_vmmdev[2]) return 0; + + vbox_irq_ack->events = vbox_vmmdev[2]; + outportl(vbox_port, vbox_phys_ack); + irq_ack(vbox_irq); + + outportl(vbox_port, vbox_phys_mouse_get); + + unsigned int x, y; + + if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y && vbox_mg->x && vbox_mg->y) { + x = ((unsigned int)vbox_mg->x * lfb_resolution_x) / 0xFFFF; + y = ((unsigned int)vbox_mg->y * lfb_resolution_y) / 0xFFFF; + } else { + x = vbox_mg->x; + y = vbox_mg->y; + } + + mouse_device_packet_t packet; + packet.magic = MOUSE_MAGIC; + packet.x_difference = x; + packet.y_difference = y; + packet.buttons = 0; + + mouse_device_packet_t bitbucket; + while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { + read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); + } + write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); + + outportl(vbox_port, vbox_phys_disp); + if (lfb_resolution_x && vbox_disp->xres && (vbox_disp->xres != lfb_resolution_x || vbox_disp->yres != lfb_resolution_y)) { + + lfb_set_resolution(vbox_disp->xres, vbox_disp->yres); + } + + return 1; +} + +void vbox_set_log(void) { + debug_file = &vb; +} + +#define VBOX_MOUSE_ON (1 << 0) | (1 << 4) +#define VBOX_MOUSE_OFF (0) + +static void mouse_on_off(unsigned int status) { + mouse_state = status; + + vbox_m->header.size = sizeof(struct vbox_mouse); + vbox_m->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_m->header.requestType = VMM_SetMouseState; + vbox_m->header.rc = 0; + vbox_m->header.reserved1 = 0; + vbox_m->header.reserved2 = 0; + vbox_m->features = status; + vbox_m->x = 0; + vbox_m->y = 0; + outportl(vbox_port, vbox_phys_mouse); +} + +static int ioctl_mouse(fs_node_t * node, int request, void * argp) { + if (request == 1) { + /* Disable */ + mouse_on_off(VBOX_MOUSE_OFF); + return 0; + } + if (request == 2) { + /* Enable */ + mouse_on_off(VBOX_MOUSE_ON); + return 0; + } + return -1; +} + +uint32_t write_pointer(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + + if (!mouse_state) { + return -1; + } + + memcpy(&vbox_pointershape->data[288], buffer, 48*48*4); + outportl(vbox_port, vbox_phys_pointershape); + + return size; +} + +uint32_t write_rectpipe(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + (void)node; + (void)offset; + + /* TODO should check size */ + + /* This is kinda special and always assumes everything was written at once. */ + uint32_t count = ((uint32_t *)buffer)[0]; + vbox_visibleregion->count = count; + + if (count > 254) count = 254; /* enforce maximum */ + +#if 0 + fprintf(&vb, "Writing %d rectangles\n", count); +#endif + + buffer += sizeof(uint32_t); + + for (unsigned int i = 0; i < count; ++i) { + memcpy(&vbox_visibleregion->rect[i], buffer, sizeof(struct vbox_rtrect)); +#if 0 + fprintf(&vb, "Rectangle %d is [%d,%d,%d,%d]\n", + i, + vbox_visibleregion->rect[i].xLeft, + vbox_visibleregion->rect[i].yTop, + vbox_visibleregion->rect[i].xRight, + vbox_visibleregion->rect[i].yBottom); +#endif + + buffer += sizeof(struct vbox_rtrect); + } + + vbox_visibleregion->header.size = sizeof(struct vbox_header) + sizeof(uint32_t) + sizeof(int32_t) * count * 4; + outportl(vbox_port, vbox_phys_visibleregion); + + return size; +} + +static int vbox_check(void) { + pci_scan(vbox_scan_pci, -1, &vbox_device); + + if (vbox_device) { + fprintf(&vb, "VirtualBox host detected, switching log to VirtualBox.\n"); + + if (args_present("vboxdebug")) { + vbox_set_log(); + } + fprintf(&vb, "HELLO WORLD\n"); + + uintptr_t t = pci_read_field(vbox_device, PCI_BAR0, 4); + if (t > 0) { + vbox_port = (t & 0xFFFFFFF0); + } + + uint16_t c = pci_read_field(vbox_device, PCI_COMMAND, 2); + fprintf(&vb, "Command register: 0x%4x\n", c); + if (!!(c & (1 << 10))) { + fprintf(&vb, "Interrupts are disabled\n"); + } + + + mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); + mouse_pipe->flags = FS_CHARDEVICE; + mouse_pipe->ioctl = ioctl_mouse; + + vfs_mount("/dev/absmouse", mouse_pipe); + + vbox_irq = pci_get_interrupt(vbox_device); + debug_print(WARNING, "(vbox) device IRQ is set to %d", vbox_irq); + fprintf(&vb, "irq line is %d\n", vbox_irq); + irq_install_handler(vbox_irq, vbox_irq_handler, "vbox"); + + uint32_t vbox_phys = 0; + struct vbox_guest_info * packet = (void*)kvmalloc_p(0x1000, &vbox_phys); + packet->header.size = sizeof(struct vbox_guest_info); + packet->header.version = VBOX_REQUEST_HEADER_VERSION; + packet->header.requestType = VMM_ReportGuestInfo; + packet->header.rc = 0; + packet->header.reserved1 = 0; + packet->header.reserved2 = 0; + packet->version = VMMDEV_VERSION; + packet->ostype = 0; + + outportl(vbox_port, vbox_phys); + + struct vbox_guest_caps * caps = (void*)kvmalloc_p(0x1000, &vbox_phys); + caps->header.size = sizeof(struct vbox_guest_caps); + caps->header.version = VBOX_REQUEST_HEADER_VERSION; + caps->header.requestType = VMM_ReportGuestCapabilities; + caps->header.rc = 0; + caps->header.reserved1 = 0; + caps->header.reserved2 = 0; + caps->caps = VMMCAP_Graphics | (args_present("novboxseamless") ? 0 : VMMCAP_SeamlessMode); + outportl(vbox_port, vbox_phys); + + vbox_irq_ack = (void*)kvmalloc_p(0x1000, &vbox_phys_ack); + vbox_irq_ack->header.size = sizeof(struct vbox_ack_events); + vbox_irq_ack->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_irq_ack->header.requestType = VMM_AcknowledgeEvents; + vbox_irq_ack->header.rc = 0; + vbox_irq_ack->header.reserved1 = 0; + vbox_irq_ack->header.reserved2 = 0; + vbox_irq_ack->events = 0; + + + vbox_disp = (void*)kvmalloc_p(0x1000, &vbox_phys_disp); + vbox_disp->header.size = sizeof(struct vbox_display_change); + vbox_disp->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_disp->header.requestType = VMM_GetDisplayChangeRequest; + vbox_disp->header.rc = 0; + vbox_disp->header.reserved1 = 0; + vbox_disp->header.reserved2 = 0; + vbox_disp->xres = 0; + vbox_disp->yres = 0; + vbox_disp->bpp = 0; + vbox_disp->eventack = 1; + + vbox_m = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse); + mouse_on_off(VBOX_MOUSE_ON); + + /* For use with later receives */ + vbox_mg = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse_get); + vbox_mg->header.size = sizeof(struct vbox_mouse); + vbox_mg->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_mg->header.requestType = VMM_GetMouseState; + vbox_mg->header.rc = 0; + vbox_mg->header.reserved1 = 0; + vbox_mg->header.reserved2 = 0; + + if (!args_present("novboxpointer")) { + vbox_pointershape = (void*)kvmalloc_p(0x4000, &vbox_phys_pointershape); + + if (vbox_pointershape) { + fprintf(&vb, "Got a valid set of pages to load up a cursor.\n"); + vbox_pointershape->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_pointershape->header.requestType = VMM_SetPointerShape; + vbox_pointershape->header.rc = 0; + vbox_pointershape->header.reserved1 = 0; + vbox_pointershape->header.reserved2 = 0; + vbox_pointershape->flags = (1 << 0) | (1 << 1) | (1 << 2); + vbox_pointershape->xHot = 26; + vbox_pointershape->yHot = 26; + vbox_pointershape->width = 48; + vbox_pointershape->height = 48; + + unsigned int mask_bytes = ((vbox_pointershape->width + 7) / 8) * vbox_pointershape->height; + + for (uint32_t i = 0; i < mask_bytes; ++i) { + vbox_pointershape->data[i] = 0x00; + } + + while (mask_bytes & 3) { + mask_bytes++; + } + int base = mask_bytes; + fprintf(&vb, "mask_bytes = %d\n", mask_bytes); + + vbox_pointershape->header.size = sizeof(struct vbox_pointershape) + (48*48*4)+mask_bytes; /* update later */ + + for (int i = 0; i < 48 * 48; ++i) { + vbox_pointershape->data[base+i*4] = 0x00; /* blue */ + vbox_pointershape->data[base+i*4+1] = 0x00; /* red */ + vbox_pointershape->data[base+i*4+2] = 0x00; /* green */ + vbox_pointershape->data[base+i*4+3] = 0x00; /* alpha */ + } + outportl(vbox_port, vbox_phys_pointershape); + + if (vbox_pointershape->header.rc < 0) { + fprintf(&vb, "Bad response code: -%d\n", -vbox_pointershape->header.rc); + } else { + /* Success, let's install the device file */ + fprintf(&vb, "Successfully initialized cursor, going to allow compositor to set it.\n"); + pointer_pipe = malloc(sizeof(fs_node_t)); + memset(pointer_pipe, 0, sizeof(fs_node_t)); + pointer_pipe->mask = 0666; + pointer_pipe->flags = FS_CHARDEVICE; + pointer_pipe->write = write_pointer; + + vfs_mount("/dev/vboxpointer", pointer_pipe); + } + } + } + + if (!args_present("novboxseamless")) { + vbox_visibleregion = (void*)kvmalloc_p(0x1000, &vbox_phys_visibleregion); + vbox_visibleregion->header.size = sizeof(struct vbox_header) + sizeof(uint32_t) + sizeof(int32_t) * 4; /* TODO + more for additional rects? */ + vbox_visibleregion->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_visibleregion->header.requestType = VMM_VideoSetVisibleRegion; + vbox_visibleregion->header.rc = 0; + vbox_visibleregion->header.reserved1 = 0; + vbox_visibleregion->header.reserved2 = 0; + vbox_visibleregion->count = 1; + vbox_visibleregion->rect[0].xLeft = 0; + vbox_visibleregion->rect[0].yTop = 0; + vbox_visibleregion->rect[0].xRight = 1440; + vbox_visibleregion->rect[0].yBottom = 900; + outportl(vbox_port, vbox_phys_visibleregion); + + rect_pipe = malloc(sizeof(fs_node_t)); + memset(rect_pipe, 0, sizeof(fs_node_t)); + rect_pipe->mask = 0666; + rect_pipe->flags = FS_CHARDEVICE; + rect_pipe->write = write_rectpipe; + + vfs_mount("/dev/vboxrects", rect_pipe); + } + + /* device memory region mapping? */ + { + uintptr_t t = pci_read_field(vbox_device, PCI_BAR1, 4); + fprintf(&vb, "mapping vmm_dev = 0x%x\n", t); + if (t > 0) { + vbox_vmmdev = (void *)(t & 0xFFFFFFF0); + } + uintptr_t fb_offset = (uintptr_t)vbox_vmmdev; + for (uintptr_t i = fb_offset; i <= fb_offset + 0x2000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + } + + vbox_vmmdev[3] = 0xFFFFFFFF; /* Enable all for now */ + } + + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(vboxguest, vbox_check, fini); +MODULE_DEPENDS(lfbvideo); diff --git a/modules/vboxguest.c b/modules/vboxguest.c deleted file mode 100644 index 5cf743f4..00000000 --- a/modules/vboxguest.c +++ /dev/null @@ -1,272 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016 Kevin Lange - * - * VirtualBox Guest Additions driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VBOX_VENDOR_ID 0x80EE -#define VBOX_DEVICE_ID 0xCAFE - -static void vbox_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { - if (v == VBOX_VENDOR_ID && d == VBOX_DEVICE_ID) { - *((uint32_t *)extra) = device; - } -} - -#define VMMDEV_VERSION 0x00010003 -#define VBOX_REQUEST_HEADER_VERSION 0x10001 -struct vbox_header { - uint32_t size; - uint32_t version; - uint32_t requestType; - int32_t rc; - uint32_t reserved1; - uint32_t reserved2; -}; - -struct vbox_guest_info { - struct vbox_header header; - uint32_t version; - uint32_t ostype; -}; - -struct vbox_guest_caps { - struct vbox_header header; - uint32_t caps; -}; - -struct vbox_ack_events { - struct vbox_header header; - uint32_t events; -}; - -struct vbox_display_change { - struct vbox_header header; - uint32_t xres; - uint32_t yres; - uint32_t bpp; - uint32_t eventack; -}; - -struct vbox_mouse { - struct vbox_header header; - uint32_t features; - int32_t x; - int32_t y; -}; - - -#define EARLY_LOG_DEVICE 0x504 -static uint32_t _vbox_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - for (unsigned int i = 0; i < size; ++i) { - outportb(EARLY_LOG_DEVICE, buffer[i]); - } - return size; -} -static fs_node_t vb = { .write = &_vbox_write }; - -static uint32_t vbox_device = 0; -static uint32_t vbox_port = 0x0; -static int vbox_irq = 0; - -static struct vbox_ack_events * vbox_irq_ack; -static uint32_t vbox_phys_ack; -static struct vbox_display_change * vbox_disp; -static uint32_t vbox_phys_disp; -static struct vbox_mouse * vbox_m; -static uint32_t vbox_phys_mouse; -static struct vbox_mouse * vbox_mg; -static uint32_t vbox_phys_mouse_get; -static volatile uint32_t * vbox_vmmdev = 0; - -static fs_node_t * mouse_pipe; - -#define PACKETS_IN_PIPE 1024 -#define DISCARD_POINT 32 - -static int vbox_irq_handler(struct regs *r) { - if (!vbox_vmmdev[2]) return 0; - - vbox_irq_ack->events = vbox_vmmdev[2]; - outportl(vbox_port, vbox_phys_ack); - irq_ack(vbox_irq); - - outportl(vbox_port, vbox_phys_mouse_get); - if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y && vbox_mg->x && vbox_mg->y) { - unsigned int x = ((unsigned int)vbox_mg->x * lfb_resolution_x) / 0xFFFF; - unsigned int y = ((unsigned int)vbox_mg->y * lfb_resolution_y) / 0xFFFF; - - mouse_device_packet_t packet; - packet.magic = MOUSE_MAGIC; - packet.x_difference = x; - packet.y_difference = y; - packet.buttons = 0; - - mouse_device_packet_t bitbucket; - while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { - read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); - } - write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); - } - - outportl(vbox_port, vbox_phys_disp); - if (lfb_resolution_x && vbox_disp->xres && (vbox_disp->xres != lfb_resolution_x || vbox_disp->yres != lfb_resolution_y)) { - - lfb_set_resolution(vbox_disp->xres, vbox_disp->yres); - } - return 1; -} - -void vbox_set_log(void) { - debug_file = &vb; -} - -#define VBOX_MOUSE_ON (1 << 0) | (1 << 4) -#define VBOX_MOUSE_OFF (0) - -static void mouse_on_off(unsigned int status) { - vbox_m->header.size = sizeof(struct vbox_mouse); - vbox_m->header.version = VBOX_REQUEST_HEADER_VERSION; - vbox_m->header.requestType = 2; - vbox_m->header.rc = 0; - vbox_m->header.reserved1 = 0; - vbox_m->header.reserved2 = 0; - vbox_m->features = status; - vbox_m->x = 0; - vbox_m->y = 0; - outportl(vbox_port, vbox_phys_mouse); -} - -static int ioctl_mouse(fs_node_t * node, int request, void * argp) { - if (request == 1) { - /* Disable */ - mouse_on_off(VBOX_MOUSE_OFF); - return 0; - } - if (request == 2) { - /* Enable */ - mouse_on_off(VBOX_MOUSE_ON); - return 0; - } - return -1; -} - -static int vbox_check(void) { - pci_scan(vbox_scan_pci, -1, &vbox_device); - - if (vbox_device) { - fprintf(&vb, "VirtualBox host detected, switching log to VirtualBox.\n"); - - if (args_present("vboxdebug")) { - vbox_set_log(); - } - - uintptr_t t = pci_read_field(vbox_device, PCI_BAR0, 4); - if (t > 0) { - vbox_port = (t & 0xFFFFFFF0); - } - - mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); - mouse_pipe->flags = FS_CHARDEVICE; - mouse_pipe->ioctl = ioctl_mouse; - - vfs_mount("/dev/absmouse", mouse_pipe); - - vbox_irq = pci_read_field(vbox_device, PCI_INTERRUPT_LINE, 1); - debug_print(WARNING, "(vbox) device IRQ is set to %d\n", vbox_irq); - irq_install_handler(vbox_irq, vbox_irq_handler); - - uint32_t vbox_phys = 0; - struct vbox_guest_info * packet = (void*)kvmalloc_p(0x1000, &vbox_phys); - packet->header.size = sizeof(struct vbox_guest_info); - packet->header.version = VBOX_REQUEST_HEADER_VERSION; - packet->header.requestType = 50; - packet->header.rc = 0; - packet->header.reserved1 = 0; - packet->header.reserved2 = 0; - packet->version = VMMDEV_VERSION; - packet->ostype = 0; - - outportl(vbox_port, vbox_phys); - - struct vbox_guest_caps * caps = (void*)kvmalloc_p(0x1000, &vbox_phys); - caps->header.size = sizeof(struct vbox_guest_caps); - caps->header.version = VBOX_REQUEST_HEADER_VERSION; - caps->header.requestType = 55; - caps->header.rc = 0; - caps->header.reserved1 = 0; - caps->header.reserved2 = 0; - caps->caps = 1 << 2; - outportl(vbox_port, vbox_phys); - - vbox_irq_ack = (void*)kvmalloc_p(0x1000, &vbox_phys_ack); - vbox_irq_ack->header.size = sizeof(struct vbox_ack_events); - vbox_irq_ack->header.version = VBOX_REQUEST_HEADER_VERSION; - vbox_irq_ack->header.requestType = 41; - vbox_irq_ack->header.rc = 0; - vbox_irq_ack->header.reserved1 = 0; - vbox_irq_ack->header.reserved2 = 0; - vbox_irq_ack->events = 0; - - vbox_disp = (void*)kvmalloc_p(0x1000, &vbox_phys_disp); - vbox_disp->header.size = sizeof(struct vbox_display_change); - vbox_disp->header.version = VBOX_REQUEST_HEADER_VERSION; - vbox_disp->header.requestType = 51; - vbox_disp->header.rc = 0; - vbox_disp->header.reserved1 = 0; - vbox_disp->header.reserved2 = 0; - vbox_disp->xres = 0; - vbox_disp->yres = 0; - vbox_disp->bpp = 0; - vbox_disp->eventack = 1; - - vbox_m = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse); - mouse_on_off(VBOX_MOUSE_ON); - - /* For use with later receives */ - vbox_mg = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse_get); - vbox_mg->header.size = sizeof(struct vbox_mouse); - vbox_mg->header.version = VBOX_REQUEST_HEADER_VERSION; - vbox_mg->header.requestType = 1; - vbox_mg->header.rc = 0; - vbox_mg->header.reserved1 = 0; - vbox_mg->header.reserved2 = 0; - - /* device memory region mapping? */ - { - uintptr_t t = pci_read_field(vbox_device, PCI_BAR1, 4); - if (t > 0) { - vbox_vmmdev = (void *)(t & 0xFFFFFFF0); - } - uintptr_t fb_offset = (uintptr_t)vbox_vmmdev; - for (uintptr_t i = fb_offset; i <= fb_offset + 0x2000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); - } - } - - vbox_vmmdev[3] = 0xFFFFFFFF; /* Enable all for now */ - } - - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(vboxguest, vbox_check, fini); -MODULE_DEPENDS(lfbvideo); diff --git a/modules/vgadbg.c b/modules/vgadbg.c index ef5445cd..de08e767 100644 --- a/modules/vgadbg.c +++ b/modules/vgadbg.c @@ -1,8 +1,7 @@ -#include -#include -#include - -#include +#include +#include +#include +#include static unsigned short * textmemptr = (unsigned short *)0xB8000; static void placech(unsigned char c, int x, int y, int attr) { diff --git a/modules/vgalog.c b/modules/vgalog.c index 1f288599..b21d295e 100644 --- a/modules/vgalog.c +++ b/modules/vgalog.c @@ -1,10 +1,9 @@ -#include -#include -#include +#include +#include +#include +#include -#include - -#include "../userspace/gui/terminal/lib/termemu.c" +#include "../lib/termemu.c" static unsigned short * textmemptr = (unsigned short *)0xB8000; static void placech(unsigned char c, int x, int y, int attr) { @@ -120,10 +119,6 @@ static void input_buffer_stuff(char * str) { return; } -static void set_term_font_size(float s) { - /* Do nothing */ -} - static void set_title(char * c) { /* Do nothing */ } @@ -146,12 +141,12 @@ term_callbacks_t term_callbacks = { term_scroll, term_redraw_cursor, input_buffer_stuff, - set_term_font_size, set_title, unsupported, unsupported_int, unsupported_int, term_set_csr_show, + NULL, }; diff --git a/modules/vidset.c b/modules/vidset.c index 5660998a..25bfb90e 100644 --- a/modules/vidset.c +++ b/modules/vidset.c @@ -1,18 +1,16 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016 Kevin Lange + * Copyright (C) 2016-2018 K. Lange * * Module to provide a debug shell command to set display mode. */ -#include -#include -#include -#include -#include - -#include -#include +#include +#include +#include +#include +#include +#include DEFINE_SHELL_FUNCTION(set_mode, "Set display mode") { if (argc < 3) { diff --git a/modules/vmware.c b/modules/vmware.c index e489b111..0bb8926e 100644 --- a/modules/vmware.c +++ b/modules/vmware.c @@ -1,34 +1,53 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2017 Kevin Lange + * Copyright (C) 2017-2018 K. Lange * - * VMWare absolute mouse driver. + * VMWare backdoor driver. * - * This device is also available by default in QEMU. + * Supports absolute mouse cursor and resolution setting. * - * Toggle off / back on with ioctl 1 and 2 respectively to /dev/vmmouse. + * Mouse: + * Toggle off / on with ioctl 1 and 2 respectively to /dev/vmmouse. + * Supports mouse buttons, unlike the one in VirtualBox. + * This device is also available by default in QEMU. * - * Actually supports mouse buttons, unlike the one in VirtualBox. + * Resolution setting: + * Enabled when the "vmware" LFB driver is active. Automatically + * resizes the display when the window size changes. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#define VMWARE_MAGIC 0x564D5868 -#define VMWARE_PORT 0x5658 +#define VMWARE_MAGIC 0x564D5868 /* hXMV */ +#define VMWARE_PORT 0x5658 +#define VMWARE_PORTHB 0x5659 #define PACKETS_IN_PIPE 1024 #define DISCARD_POINT 32 +#define CMD_GETVERSION 10 +#define CMD_MESSAGE 30 +#define CMD_ABSPOINTER_DATA 39 +#define CMD_ABSPOINTER_STATUS 40 +#define CMD_ABSPOINTER_COMMAND 41 + +#define ABSPOINTER_ENABLE 0x45414552 /* Q E A E */ +#define ABSPOINTER_RELATIVE 0xF5 +#define ABSPOINTER_ABSOLUTE 0x53424152 /* R A B S */ + +#define MESSAGE_RPCI 0x49435052 /* R P C I */ +#define MESSAGE_TCLO 0x4f4c4354 /* T C L O */ + /* -Wpedantic complains about unnamed unions */ #pragma GCC diagnostic ignored "-Wpedantic" @@ -57,68 +76,35 @@ typedef struct { uint32_t di; } vmware_cmd; -static void vmware_io(vmware_cmd * cmd) { - uint32_t dummy; - - /* Now how's THAT for a VM backdoor... */ - - asm volatile( - "pushl %%ebx\n" - "pushl %%eax\n" - "movl 20(%%eax), %%edi\n" /* Load data into registers */ - "movl 16(%%eax), %%esi\n" - "movl 12(%%eax), %%edx\n" - "movl 8(%%eax), %%ecx\n" - "movl 4(%%eax), %%ebx\n" - "movl (%%eax), %%eax\n" - "inl %%dx, %%eax\n" /* Then trip a magic i/o port */ - "xchgl %%eax, (%%esp)\n" - "movl %%edi, 20(%%eax)\n" /* Data also comes back out by registers */ - "movl %%esi, 16(%%eax)\n" - "movl %%edx, 12(%%eax)\n" - "movl %%ecx, 8(%%eax)\n" - "movl %%ebx, 4(%%eax)\n" - "popl (%%eax)\n" - "popl %%ebx\n" - : "=a"(dummy) - : "0"(cmd) - : "ecx", "edx", "esi", "edi", "memory" /* And vmware / qemu could trash anything they desire... */ - ); -} - +/** Low bandwidth backdoor */ static void vmware_send(vmware_cmd * cmd) { cmd->magic = VMWARE_MAGIC; cmd->port = VMWARE_PORT; - vmware_io(cmd); + asm volatile("in %%dx, %0" : "+a"(cmd->ax), "+b"(cmd->bx), "+c"(cmd->cx), "+d"(cmd->dx), "+S"(cmd->si), "+D"(cmd->di)); } -static void mouse_on(void) { - vmware_cmd cmd; +/** Output to high bandwidth backdoor */ +static void vmware_send_hb(vmware_cmd * cmd) { + cmd->magic = VMWARE_MAGIC; + cmd->port = VMWARE_PORTHB; - /* Enable */ - cmd.bx = 0x45414552; - cmd.command = 41; - vmware_send(&cmd); + asm volatile("cld; rep; outsb" : "+a"(cmd->ax), "+b"(cmd->bx), "+c"(cmd->cx), "+d"(cmd->dx), "+S"(cmd->si), "+D"(cmd->di)); +} - /* Status */ - cmd.bx = 0; - cmd.command = 40; - vmware_send(&cmd); +/** Input from high bandwidth backdoor */ +static void vmware_get_hb(vmware_cmd * cmd) { + cmd->magic = VMWARE_MAGIC; + cmd->port = VMWARE_PORTHB; - /* Read data (1) */ - cmd.bx = 1; - cmd.command = 39; - vmware_send(&cmd); - - debug_print(WARNING, "Enabled with version ID %x", cmd.ax); + asm volatile("cld; rep; insb" : "+a"(cmd->ax), "+b"(cmd->bx), "+c"(cmd->cx), "+d"(cmd->dx), "+S"(cmd->si), "+D"(cmd->di)); } static void mouse_off(void) { /* Disable the absolute mouse */ vmware_cmd cmd; - cmd.bx = 0xf5; - cmd.command = 41; + cmd.bx = ABSPOINTER_RELATIVE; + cmd.command = CMD_ABSPOINTER_COMMAND; vmware_send(&cmd); } @@ -131,10 +117,26 @@ static void mouse_absolute(void) { * falls back to the PS/2 (or USB, I guess) device anyway, * so instead of using that we just... turn it off. */ - vmware_cmd cmd; - cmd.bx = 0x53424152; /* request absolute */ - cmd.command = 41; /* request for abs/rel */ + + /* Enable */ + cmd.bx = ABSPOINTER_ENABLE; + cmd.command = CMD_ABSPOINTER_COMMAND; + vmware_send(&cmd); + + /* Status */ + cmd.bx = 0; + cmd.command = CMD_ABSPOINTER_STATUS; + vmware_send(&cmd); + + /* Read data (1) */ + cmd.bx = 1; + cmd.command = CMD_ABSPOINTER_DATA; + vmware_send(&cmd); + + /* Enable absolute */ + cmd.bx = ABSPOINTER_ABSOLUTE; + cmd.command = CMD_ABSPOINTER_COMMAND; vmware_send(&cmd); } @@ -147,13 +149,12 @@ static void vmware_mouse(void) { /* Read status byte. */ vmware_cmd cmd; cmd.bx = 0; - cmd.command = 40; + cmd.command = CMD_ABSPOINTER_STATUS; vmware_send(&cmd); if (cmd.ax == 0xffff0000) { /* Device error; turn it off and back on again. */ mouse_off(); - mouse_on(); mouse_absolute(); return; } @@ -167,7 +168,7 @@ static void vmware_mouse(void) { /* Read 4 bytes of data */ cmd.bx = 4; /* how many */ - cmd.command = 39; /* read */ + cmd.command = CMD_ABSPOINTER_DATA; /* read */ vmware_send(&cmd); /* @@ -180,46 +181,51 @@ static void vmware_mouse(void) { debug_print(INFO, "flags=%4x buttons=%4x", flags, buttons); debug_print(INFO, "x=%x y=%x z=%x", cmd.bx, cmd.cx, cmd.dx); + unsigned int x = 0; + unsigned int y = 0; + if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y) { /* * Just like the virtualbox stuff, this is based on a mapping * to the display resolution, independently scaled in * each dimension... */ - unsigned int x = ((unsigned int)cmd.bx * lfb_resolution_x) / 0xFFFF; - unsigned int y = ((unsigned int)cmd.cx * lfb_resolution_y) / 0xFFFF; - - mouse_device_packet_t packet; - packet.magic = MOUSE_MAGIC; - packet.x_difference = x; - packet.y_difference = y; - packet.buttons = 0; - - /* The particular bits for the buttons seem weird, but okay... */ - if (buttons & 0x20) { - packet.buttons |= LEFT_CLICK; - } - if (buttons & 0x10) { - packet.buttons |= RIGHT_CLICK; - } - if (buttons & 0x08) { - packet.buttons |= MIDDLE_CLICK; - } - - /* dx = z = scroll amount */ - if ((int8_t)cmd.dx > 0) { - packet.buttons |= MOUSE_SCROLL_DOWN; - } else if ((int8_t)cmd.dx < 0) { - packet.buttons |= MOUSE_SCROLL_UP; - } - - mouse_device_packet_t bitbucket; - while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { - read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); - } - write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); + x = ((unsigned int)cmd.bx * lfb_resolution_x) / 0xFFFF; + y = ((unsigned int)cmd.cx * lfb_resolution_y) / 0xFFFF; + } else { + x = cmd.bx; + y = cmd.cx; } + mouse_device_packet_t packet; + packet.magic = MOUSE_MAGIC; + packet.x_difference = x; + packet.y_difference = y; + packet.buttons = 0; + + /* The particular bits for the buttons seem weird, but okay... */ + if (buttons & 0x20) { + packet.buttons |= LEFT_CLICK; + } + if (buttons & 0x10) { + packet.buttons |= RIGHT_CLICK; + } + if (buttons & 0x08) { + packet.buttons |= MIDDLE_CLICK; + } + + /* dx = z = scroll amount */ + if ((int8_t)cmd.dx > 0) { + packet.buttons |= MOUSE_SCROLL_DOWN; + } else if ((int8_t)cmd.dx < 0) { + packet.buttons |= MOUSE_SCROLL_UP; + } + + mouse_device_packet_t bitbucket; + while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { + read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); + } + write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); } static int detect_device(void) { @@ -227,7 +233,7 @@ static int detect_device(void) { /* read version */ cmd.bx = ~VMWARE_MAGIC; - cmd.command = 10; + cmd.command = CMD_GETVERSION; vmware_send(&cmd); if (cmd.bx != VMWARE_MAGIC || cmd.ax == 0xFFFFFFFF) { @@ -239,21 +245,236 @@ static int detect_device(void) { return 1; } + +static int open_msg_channel(uint32_t proto) { + vmware_cmd cmd; + cmd.cx = CMD_MESSAGE | 0x00000000; /* CMD_MESSAGE */ + cmd.bx = proto; + vmware_send(&cmd); + + if ((cmd.cx & 0x10000) == 0) { + return -1; + } + + return cmd.dx >> 16; +} + +static void msg_close(int channel) { + vmware_cmd cmd = {0}; + cmd.cx = CMD_MESSAGE | 0x00060000; + cmd.bx = 0; + cmd.dx = channel << 16; + + vmware_send(&cmd); +} + +static int open_rpci_channel(void) { + return open_msg_channel(MESSAGE_RPCI); +} + +static int tclo_channel = -1; + +static int open_tclo_channel(void) { + if (tclo_channel != -1) { + msg_close(tclo_channel); + } + tclo_channel = open_msg_channel(MESSAGE_TCLO); + return tclo_channel; +} + +static int msg_send(int channel, char * msg, size_t size) { + { + vmware_cmd cmd = {0}; + cmd.cx = CMD_MESSAGE | 0x00010000; /* CMD_MESSAGE size */ + cmd.size = size; + cmd.dx = channel << 16; + vmware_send(&cmd); + + if (size == 0) return 0; + + if (((cmd.cx >> 16) & 0x0081) != 0x0081) { + return -2; + } + } + + { + vmware_cmd cmd = {0}; + cmd.bx = 0x0010000; + cmd.cx = size; + cmd.dx = channel << 16; + cmd.si = (uint32_t)msg; + vmware_send_hb(&cmd); + + if (!(cmd.bx & 0x0010000)) { + return -3; + } + } + + return 0; +} + +static int msg_recv(int channel, char * buf, size_t bufsize) { + size_t size; + { + vmware_cmd cmd = {0}; + cmd.cx = CMD_MESSAGE | 0x00030000; /* CMD_MESSAGE receive ize */ + cmd.dx = channel << 16; + vmware_send(&cmd); + + size = cmd.bx; + if (size == 0) return 0; + if (((cmd.cx >> 16) & 0x0083) != 0x0083) { + return -2; + } + if (size > bufsize) return -1; + } + + { + vmware_cmd cmd = {0}; + cmd.bx = 0x00010000; + cmd.cx = size; + cmd.dx = channel << 16; + cmd.di = (uint32_t)buf; + + vmware_get_hb(&cmd); + if (!(cmd.bx & 0x00010000)) { + return -3; + } + } + + { + vmware_cmd cmd = {0}; + cmd.cx = CMD_MESSAGE | 0x00050000; + cmd.bx = 0x0001; + cmd.dx = channel << 16; + + vmware_send(&cmd); + } + + return size; +} + +static int rpci_string(char * request) { + /* Open channel */ + int channel = open_rpci_channel(); + if (channel < 0) return channel; + + size_t size = strlen(request) + 1; + msg_send(channel, request, size); + + char buf[16]; + int recv_size = msg_recv(channel, buf, 16); + + msg_close(channel); + + if (recv_size < 0) return recv_size; + + return 0; +} + +static int attempt_scale(void) { + + int i; + int c = open_tclo_channel(); + if (c < 0) { + return 1; + } + + char buf[256]; + if ((i = msg_send(c, buf, 0)) < 0) { return 1; } + + int resend = 0; + + while (1) { + i = msg_recv(c, buf, 256); + if (i < 0) { + return 1; + } else if (i == 0) { + if (resend) { + if ((i = rpci_string("tools.capability.resolution_set 1")) < 0) { return 1; } + if ((i = rpci_string("tools.capability.resolution_server toolbox 1")) < 0) { return 1; } + if ((i = rpci_string("tools.capability.display_topology_set 1")) < 0) { return 1; } + if ((i = rpci_string("tools.capability.color_depth_set 1")) < 0) { return 1; } + if ((i = rpci_string("tools.capability.resolution_min 0 0")) < 0) { return 1; } + if ((i = rpci_string("tools.capability.unity 1")) < 0) { return 1; } + resend = 0; + } else { + unsigned long s, ss; + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + } + if ((i = msg_send(c, buf, 0)) < 0) { return 1; } + } else { + buf[i] = '\0'; + if (startswith(buf, "reset")) { + if ((i = msg_send(c, "OK ATR toolbox", strlen("OK ATR toolbox"))) < 0) { + return 1; + } + } else if (startswith(buf, "ping")) { + if ((i = msg_send(c, "OK ", strlen("OK "))) < 0) { + return 1; + } + } else if (startswith(buf, "Capabilities_Register")) { + if ((i = msg_send(c, "OK ", strlen("OK "))) < 0) { + return 1; + } + resend = 1; + } else if (startswith(buf, "Resolution_Set")) { + char * x = &buf[15]; + char * y = strstr(x," "); + if (!y) { + return 1; + } + *y = '\0'; + y++; + int _x = atoi(x); + int _y = atoi(y); + + if (lfb_resolution_x && _x && (_x != lfb_resolution_x || _y != lfb_resolution_y)) { + lfb_set_resolution(_x, _y); + } + + if ((i = msg_send(c, "OK ", strlen("OK "))) < 0) { + return 1; + } + + msg_close(c); + return 0; + } else { + if ((i = msg_send(c, "ERROR Unknown command", strlen("ERROR Unknown command"))) < 0) { + return 1; + } + } + } + } +} + +static void vmware_resize(void * data, char * name) { + while (1) { + attempt_scale(); + unsigned long s, ss; + relative_time(1, 0, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + } +} + static int ioctl_mouse(fs_node_t * node, int request, void * argp) { - if (request == 1) { - /* Disable */ - mouse_off(); - ps2_mouse_alternate = NULL; - return 0; + switch (request) { + case 1: + /* Disable */ + mouse_off(); + ps2_mouse_alternate = NULL; + return 0; + case 2: + /* Enable */ + ps2_mouse_alternate = vmware_mouse; + mouse_absolute(); + return 0; + default: + return -EINVAL; } - if (request == 2) { - /* Enable */ - ps2_mouse_alternate = vmware_mouse; - mouse_on(); - mouse_absolute(); - return 0; - } - return -1; } static int init(void) { @@ -274,9 +495,12 @@ static int init(void) { */ ps2_mouse_alternate = vmware_mouse; - mouse_on(); mouse_absolute(); + if (lfb_driver_name && !strcmp(lfb_driver_name, "vmware") && !args_present("novmwareresset")) { + create_kernel_tasklet(vmware_resize, "[vmware]", NULL); + } + } return 0; diff --git a/modules/xtest.c b/modules/xtest.c index ea66bb94..46ae5e91 100644 --- a/modules/xtest.c +++ b/modules/xtest.c @@ -1,14 +1,13 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange */ -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include static void xtest_a(void * data, char * name) { fs_node_t * tty = data; diff --git a/modules/zero.c b/modules/zero.c index 1a7f4a77..b2a9cd79 100644 --- a/modules/zero.c +++ b/modules/zero.c @@ -1,15 +1,15 @@ /* vim: tabstop=4 shiftwidth=4 noexpandtab * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange + * Copyright (C) 2014-2018 K. Lange * * Null Device * */ -#include -#include -#include +#include +#include +#include static uint32_t read_null(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); static uint32_t write_null(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); diff --git a/toolchain/activate.sh b/toolchain/activate.sh deleted file mode 100755 index f3d41a72..00000000 --- a/toolchain/activate.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -. $DIR/config.sh - -export PATH="$DIR/local/bin:$PATH" -export PKG_CONFIG_LIBDIR="$TOARU_SYSROOT/usr/lib/pkgconfig" -export PKG_CONFIG_SYSROOT_DIR="$TOARU_SYSROOT" -export TOOLCHAIN="$TOARU_SYSROOT/usr" diff --git a/toolchain/config.sh b/toolchain/config.sh deleted file mode 100755 index 929a868b..00000000 --- a/toolchain/config.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# PREFIX is the cross-compiler tools prefix -PREFIX=$DIR/local - -# TARGET is the platform triplet -TARGET=i686-pc-toaru - -# TOARU_SYSROOT is the system root, which is equivalent to the hard disk -export TOARU_SYSROOT=`readlink -f $DIR/../hdd` - -# VIRTPREFIX is where we put stuff from the perspective of the target system -# since most build scripts will default to /usr/local and we want just /usr... -VIRTPREFIX=/usr diff --git a/toolchain/cross-gcc.sh b/toolchain/cross-gcc.sh deleted file mode 100755 index 27cbe367..00000000 --- a/toolchain/cross-gcc.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash - -echo "This script is currently not functioning. Please check back later." -exit 1 - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -. $DIR/config.sh -. $DIR/util.sh -. $DIR/activate.sh - -pushd $DIR - -# Grab extras -./extras.sh - -MPC=mpc-0.9 -GMP=gmp-5.0.1 -MPFR=mpfr-3.0.1 -GCCV=4.6.4 -GCC=cross-gcc/gcc-$GCCV -BINUTILS=binutils-2.22 - -VIRTPREFIX=/usr -REALPREFIX=$TOARU_SYSROOT - -pushd tarballs > /dev/null - if [ ! -d "cross-gcc" ]; then - mkdir "cross-gcc" - fi - deco "gcc" "gcc-core-4.6.4.tar.gz -C cross-gcc" || bail - deco "g++" "gcc-g++-4.6.4.tar.gz -C cross-gcc" || bail - patc "gcc" "cross-gcc/gcc-4.6.4" || bail -popd - -if [ ! -d tarballs/$GCC/mpfr ]; then - mv tarballs/$MPFR tarballs/$GCC/mpfr -fi -if [ ! -d tarballs/$GCC/gmp ]; then - mv tarballs/$GMP tarballs/$GCC/gmp -fi -if [ ! -d tarballs/$GCC/mpc ]; then - mv tarballs/$MPC tarballs/$GCC/mpc -fi - -# Actual build process - -echo "Building GCC for native installation targetting $TARGET, installed into $TOARU_SYSROOT$VIRTPREFIX" - -pushd build || bail - if [ -d binutils-native ]; then - rm -rf binutils-native - fi - mkdir binutils-native - pushd binutils-native || bail - $DIR/tarballs/$BINUTILS/configure --prefix=$VIRTPREFIX --host=$TARGET --target=$TARGET || bail - make || bail - make DESTDIR=$REALPREFIX install || bail - popd - if [ -d gcc-native ]; then - rm -rf gcc-native - fi - mkdir gcc-native - pushd gcc-native || bail - make distclean - $DIR/tarballs/$GCC/configure --prefix=$VIRTPREFIX --host=$TARGET --target=$TARGET --disable-nls --enable-languages=c,c++ --disable-libssp --with-newlib || bail - make DESTDIR=$REALPREFIX all-gcc || bail - make DESTDIR=$REALPREFIX install-gcc || bail - make DESTDIR=$REALPREFIX all-target-libgcc || bail - make DESTDIR=$REALPREFIX install-target-libgcc || bail - touch $TOARU_SYSROOT/usr/include/fenv.h - make DESTDIR=$REALPREFIX all-target-libstdc++-v3 || bail - make DESTDIR=$REALPREFIX install-target-libstdc++-v3 || bail - popd - - TMP_INCFIX=$REALPREFIX$VIRTPREFIX/lib/gcc/$TARGET/$GCCV/include-fixed - - if [ -d $TMP_INCFIX ]; then - rm -r "$TMP_INCFIX" - fi - - pushd $REALPREFIX$VIRTPREFIX/bin || bail - $TARGET-strip * - popd - - pushd $REALPREFIX$VIRTPREFIX/libexec/gcc/$TARGET/$GCCV || bail - $TARGET-strip cc1 collect2 - popd - -popd diff --git a/toolchain/extras.sh b/toolchain/extras.sh deleted file mode 100755 index 5968edd7..00000000 --- a/toolchain/extras.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -. $DIR/util.sh - -pushd "$DIR" > /dev/null - - if [ ! -d tarballs ]; then - mkdir tarballs - fi - pushd tarballs > /dev/null - grab "mpc" "http://www.multiprecision.org/mpc/download" "mpc-0.9.tar.gz" - grab "mpfr" "http://www.mpfr.org/mpfr-3.0.1" "mpfr-3.0.1.tar.gz" - grab "gmp" "ftp://ftp.gmplib.org/pub/gmp-5.0.1" "gmp-5.0.1.tar.bz2" - rm -rf "gmp-5.0.1" "mpc-0.9" "mpfr-3.0.1" - deco "mpc" "mpc-0.9.tar.gz" - deco "mpfr" "mpfr-3.0.1.tar.gz" - deco "gmp" "gmp-5.0.1.tar.bz2" - patc "mpc" "mpc-0.9" - patc "mpfr" "mpfr-3.0.1" - patc "gmp" "gmp-5.0.1" - popd > /dev/null -popd > /dev/null diff --git a/toolchain/install-pycairo.sh b/toolchain/install-pycairo.sh deleted file mode 100755 index 156b8731..00000000 --- a/toolchain/install-pycairo.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $DIR/.. - -HDD_PATH=`pwd`/hdd - -if [ ! -d pycairo ]; then - echo "No pycairo source checkout, cloning..." - git clone https://github.com/klange/pycairo -fi - -pushd pycairo/src || exit 1 - touch config.h - make - cp _cairo.so $HDD_PATH/usr/python/lib/python3.6/_cairo.so - echo "from _cairo import *" > $HDD_PATH/usr/python/lib/python3.6/cairo.py -popd diff --git a/toolchain/install-python.sh b/toolchain/install-python.sh deleted file mode 100755 index aaad197b..00000000 --- a/toolchain/install-python.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $DIR/.. - -HDD_PATH=`pwd`/hdd - -which python3.6 > /dev/null || echo "You need Python 3.6 to cross-compile Python 3.6. You should build it locally or obtain it from your package manager if possible. A PPA for Ubuntu is available at ppa:jonathonf/python-3.6" -which python3.6 > /dev/null || exit 1 - -if [ ! -d toaru-python ]; then - echo "No Python source checkout, cloning..." - git clone https://github.com/klange/cpython toaru-python -fi - -echo "Installing dlfcn.h..." -mkdir -p hdd/usr/include -cp userspace/lib/dlfcn.h hdd/usr/include/ - -pushd toaru-python || exit 1 - echo "Configuring..." - - ./configure --disable-ipv6 --enable-shared --host=i686-pc-toaru --build=i686 --prefix=/usr/python ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no ac_cv_func_dlopen=yes ac_cv_func_wait3=no ac_cv_var_tzname=no ac_cv_func_unsetenv=no ac_cv_var_putenv=no ac_cv_header_sys_lock_h=no ac_cv_header_sys_param_h=no ac_cv_header_sys_resource_h=no ac_cv_header_libintl_h=no ac_cv_func_sigaction=no - - echo "Making..." - make - - echo "Installing..." - make DESTDIR=$HDD_PATH commoninstall bininstall || exit 1 - -popd - -pushd $HDD_PATH/usr/python/lib || exit 1 - - echo "Stripping shared library..." - chmod +w libpython3.6m.so - i686-pc-toaru-strip libpython3.6m.so - chmod -w libpython3.6m.so - - echo "Killing __pycache__ directories..." - rm -r ./python3.6/__pycache__ - rm -r ./python3.6/importlib/__pycache__ - - # Let's kill some other shit while we're in here - pushd python3.6 || exit 1 - echo "Cleaning up unused modules..." - rm -r test distutils tkinter multiprocessing ensurepip config-3.6m/libpython3.6m.a - popd - -popd - -pushd $HDD_PATH/usr - if [ ! -d bin ]; then - mkdir bin - fi - - pushd bin - - # Can never be too careful. - ln -s ../python/bin/python3.6 python3.6 - ln -s ../python/bin/python3.6 python3 - ln -s ../python/bin/python3.6 python - - popd - - pushd lib - - ln -s ../python/lib/libpython3.6m.so - - popd -popd diff --git a/toolchain/install.sh b/toolchain/install.sh deleted file mode 100755 index e31c817a..00000000 --- a/toolchain/install.sh +++ /dev/null @@ -1,230 +0,0 @@ -#!/bin/bash -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -. $DIR/config.sh -. $DIR/util.sh - -# Build everything by default. -BUILD_BINUTILS=true -BUILD_GCC=true -BUILD_NEWLIB=true -BUILD_LIBSTDCPP=true -BUILD_ZLIB=true -BUILD_FREETYPE=true -BUILD_PNG=true -BUILD_PIXMAN=true -BUILD_CAIRO=true -BUILD_NCURSES=true -BUILD_VIM=true - -#BUILD_BINUTILS=false -#BUILD_GCC=false -#BUILD_NEWLIB=false -#BUILD_LIBSTDCPP=false -#BUILD_ZLIB=false -#BUILD_FREETYPE=false -#BUILD_PNG=false -#BUILD_PIXMAN=false -#BUILD_CAIRO=false -#BUILD_NCURSES=false -#BUILD_VIM=false - -echo "Building a toolchain with a sysroot of $TOARU_SYSROOT with host binaries in $PREFIX targeting $TARGET" - -if [ ! -d build ]; then - mkdir build -fi - -pushd build - if $BUILD_BINUTILS; then - if [ ! -d binutils ]; then - mkdir binutils - fi - - unset PKG_CONFIG_LIBDIR - - pushd binutils - $DIR/tarballs/binutils-2.27/configure --target=$TARGET --prefix=$PREFIX --with-sysroot=$TOARU_SYSROOT --disable-werror || bail - make -j4 || bail - make install || bail - popd - - if [ ! -d binutils-elf ]; then - mkdir binutils-elf - fi - - pushd binutils-elf - $DIR/tarballs/binutils-2.27/configure --target=i686-elf --prefix=$PREFIX --disable-werror || bail - make -j4 || bail - make install || bail - popd - fi - - if $BUILD_GCC; then - if [ -d gcc ]; then - rm -rf gcc - fi - mkdir gcc - - unset PKG_CONFIG_LIBDIR - - pushd gcc - $DIR/tarballs/gcc-6.4.0/configure --target=i686-pc-toaru --prefix=$PREFIX --with-sysroot=$TOARU_SYSROOT --disable-nls --enable-languages=c,c++,go --disable-libssp --with-newlib || baiol - make -j4 all-gcc all-target-libgcc || bail - make install-gcc install-target-libgcc || bail - popd - - if [ -d gcc-elf ]; then - rm -rf gcc-elf - fi - mkdir gcc-elf - - pushd gcc-elf - $DIR/tarballs/gcc-6.4.0/configure --target=i686-elf --prefix=$PREFIX --disable-nls --enable-languages=c --disable-libssp --without-headers || baiol - make -j4 all-gcc all-target-libgcc || bail - make install-gcc install-target-libgcc || bail - popd - fi - - . $DIR/activate.sh - - if $BUILD_NEWLIB; then - if [ ! -d newlib ]; then - mkdir newlib - else - # Newlib is touchy about reconfigures - rm -r newlib - mkdir newlib - fi - pushd $DIR/tarballs/newlib-1.19.0 - find -type f -exec sed 's|--cygnus||g;s|cygnus||g' -i {} + || bail - popd - pushd $DIR/tarballs/newlib-1.19.0/newlib/libc/sys - autoconf || bail - pushd toaru - touch INSTALL NEWS README AUTHORS ChangeLog COPYING || bail - autoreconf || bail - yasm -f elf -o crt0.o crt0.s || bail - yasm -f elf -o crti.o crti.s || bail - yasm -f elf -o crtn.o crtn.s || bail - cp crt0.o ../ - cp crt0.o /tmp/__toaru_crt0.o - cp crti.o ../ - cp crti.o /tmp/__toaru_crti.o - cp crtn.o ../ - cp crtn.o /tmp/__toaru_crtn.o - popd - popd - pushd newlib - mkdir -p $TARGET/newlib/libc/sys - cp /tmp/__toaru_crt0.o $TARGET/newlib/libc/sys/crt0.o - rm /tmp/__toaru_crt0.o - cp /tmp/__toaru_crti.o $TARGET/newlib/libc/sys/crti.o - rm /tmp/__toaru_crti.o - cp /tmp/__toaru_crtn.o $TARGET/newlib/libc/sys/crtn.o - rm /tmp/__toaru_crtn.o - echo "" > $DIR/tarballs/newlib-1.19.0/newlib/libc/stdlib/malign.c - $DIR/tarballs/newlib-1.19.0/configure --target=$TARGET --prefix=$VIRTPREFIX --enable-newlib-io-c99-formats || bail - # Fix the damned tooldir - sed -s 's/prefix}\/i686-pc-toaru/prefix}/' Makefile > Makefile.tmp - mv Makefile.tmp Makefile - make -j || bail - make DESTDIR=$TOARU_SYSROOT install || bail - cp -r $DIR/patches/newlib/include/* $TOARU_SYSROOT/$VIRTPREFIX/include/ - cp $TARGET/newlib/libc/sys/crt0.o $TOARU_SYSROOT/$VIRTPREFIX/lib/ - cp $TARGET/newlib/libc/sys/crti.o $TOARU_SYSROOT/$VIRTPREFIX/lib/ - cp $TARGET/newlib/libc/sys/crtn.o $TOARU_SYSROOT/$VIRTPREFIX/lib/ - popd - fi - - if $BUILD_LIBSTDCPP; then - pushd gcc - # build libstdc++ - make -j all-target-libstdc++-v3 || bail - make install-target-libstdc++-v3 || bail - popd - fi - - if $BUILD_FREETYPE; then - if [ ! -d freetype ]; then - mkdir freetype - fi - pushd freetype - $DIR/tarballs/freetype-2.4.9/configure --host=$TARGET --prefix=$VIRTPREFIX || bail - make || bail - make DESTDIR=$TOARU_SYSROOT install || bail - popd - fi - - if $BUILD_ZLIB; then - # XXX zlib can not be built in a separate directory - pushd $DIR/tarballs/zlib*/ - CC=i686-pc-toaru-gcc ./configure --static --prefix=$VIRTPREFIX || bail - make || bail - make DESTDIR=$TOARU_SYSROOT install || bail - popd - fi - - if $BUILD_PNG; then - if [ ! -d libpng ]; then - mkdir libpng - fi - pushd libpng - $DIR/tarballs/libpng-1.5.13/configure --host=$TARGET --prefix=$VIRTPREFIX || bail - make || bail - make DESTDIR=$TOARU_SYSROOT install || bail - popd - fi - - if $BUILD_PIXMAN; then - if [ ! -d pixman ]; then - mkdir pixman - fi - pushd pixman - $DIR/tarballs/pixman-0.26.2/configure --host=$TARGET --prefix=$VIRTPREFIX || bail - make || bail - make DESTDIR=$TOARU_SYSROOT install || bail - popd - fi - - if $BUILD_CAIRO; then - if [ ! -d cairo ]; then - mkdir cairo - fi - pushd cairo - $DIR/tarballs/cairo-1.12.2/configure --host=$TARGET --prefix=$VIRTPREFIX --enable-ps=no --enable-pdf=no --enable-interpreter=no --enable-xlib=no || bail - cp $DIR/patches/cairo-Makefile test/Makefile - cp $DIR/patches/cairo-Makefile perf/Makefile - echo -e "\n\n#define CAIRO_NO_MUTEX 1" >> config.h - make || bail - make DESTDIR=$TOARU_SYSROOT install || bail - popd - fi - - if $BUILD_NCURSES; then - if [ ! -d ncurses ]; then - mkdir ncurses - fi - pushd ncurses - CPPFLAGS="-P" $DIR/tarballs/ncurses-5.9/configure --prefix=$VIRTPREFIX --host=$TARGET --with-terminfo-dirs=/usr/share/terminfo --with-default-terminfo-dir=/usr/share/terminfo --without-tests || bail - make || bail - make DESTDIR=$TOARU_SYSROOT install || bail - cp $DIR/../util/toaru.tic $TOARU_SYSROOT/$VIRTPREFIX/share/terminfo/t/toaru - cp $DIR/../util/toaru-vga.tic $TOARU_SYSROOT/$VIRTPREFIX/share/terminfo/t/toaru-vga - popd - fi - - if $BUILD_VIM; then - pushd $DIR/tarballs/vim73 - make distclean - ac_cv_sizeof_int=4 vim_cv_getcwd_broken=no vim_cv_memmove_handles_overlap=yes vim_cv_stat_ignores_slash=no vim_cv_tgetent=zero vim_cv_terminfo=yes vim_cv_toupper_broken=no vim_cv_tty_group=world ./configure --host=$TARGET --target=$TARGET --with-sysroot=$TOARU_SYSROOT --prefix=$VIRTPREFIX --with-tlib=ncurses --enable-gui=no --disable-gtktest --disable-xim --with-features=normal --disable-gpm --without-x --disable-netbeans --enable-multibyte - make || bail - make DESTDIR=$TOARU_SYSROOT install || bail - popd - fi - - pushd $TOARU_SYSROOT/usr/bin || bail - $TARGET-strip * - popd - -popd diff --git a/toolchain/legacy-automake.sh b/toolchain/legacy-automake.sh deleted file mode 100755 index b9af0fa0..00000000 --- a/toolchain/legacy-automake.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -. $DIR/config.sh -. $DIR/util.sh -. $DIR/activate.sh - -# Just in case -pushd $DIR - -pushd tarballs || bail - grab "automake" "http://ftp.gnu.org/gnu/automake" "automake-1.11.6.tar.gz" || bail - deco "automake" "automake-1.11.6.tar.gz" || bail -popd - -pushd build || bail - - if [ ! -d automake ]; then - mkdir automake - fi - - pushd automake || bail - $DIR/tarballs/automake-1.11.6/configure --prefix=$PREFIX - make - make install - pushd $PREFIX/share || bail - ln -s automake-1.11 automake - ln -s aclocal-1.11 aclocal - popd - popd - -popd - diff --git a/toolchain/patches/Mesa-7.5.2.patch b/toolchain/patches/Mesa-7.5.2.patch deleted file mode 100644 index e132246f..00000000 --- a/toolchain/patches/Mesa-7.5.2.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -rupN original/bin/config.sub new/bin/config.sub ---- original/bin/config.sub -+++ new/bin/config.sub -@@ -1263,7 +1263,8 @@ case $os in - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ diff --git a/toolchain/patches/cairo-1.12.2.patch b/toolchain/patches/cairo-1.12.2.patch deleted file mode 100644 index b458184b..00000000 --- a/toolchain/patches/cairo-1.12.2.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -rupN original/build/config.sub new/build/config.sub ---- original/build/config.sub 2012-03-08 15:09:13.000000000 -0500 -+++ new/build/config.sub 2012-05-17 11:40:42.308339450 -0400 -@@ -1338,6 +1338,7 @@ case $os in - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ diff --git a/toolchain/patches/cairo-Makefile b/toolchain/patches/cairo-Makefile deleted file mode 100644 index b1d36bee..00000000 --- a/toolchain/patches/cairo-Makefile +++ /dev/null @@ -1,7 +0,0 @@ -derp: - @echo "lol" - -all: derp -install: derp -distclean: derp -clean: derp diff --git a/toolchain/patches/cross-gcc/gcc-4.6.4.patch b/toolchain/patches/cross-gcc/gcc-4.6.4.patch deleted file mode 100644 index 86e2dde1..00000000 --- a/toolchain/patches/cross-gcc/gcc-4.6.4.patch +++ /dev/null @@ -1,109 +0,0 @@ -diff -rupN original/config.sub new/config.sub ---- original/config.sub 2010-05-25 08:22:07.000000000 -0500 -+++ new/config.sub 2011-04-24 19:55:22.000000000 -0500 -@@ -1298,6 +1298,7 @@ case $os in - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ -diff -rupN original/gcc/config/toaru.h new/gcc/config/toaru.h ---- original/gcc/config/toaru.h 1969-12-31 18:00:00.000000000 -0600 -+++ new/gcc/config/toaru.h 2011-04-24 19:51:58.000000000 -0500 -@@ -0,0 +1,20 @@ -+#undef TARGET_OS_CPP_BUILTINS -+#define TARGET_OS_CPP_BUILTINS() \ -+ do { \ -+ builtin_define_std ("toaru"); \ -+ builtin_define_std ("unix"); \ -+ builtin_assert ("system=toaru"); \ -+ builtin_assert ("system=unix"); \ -+ } while (0); -+ -+#undef STARTFILE_SPEC -+#define STARTFILE_SPEC "%{!shared: %{!pg:crt0.o%s}} crti.o%s %{!shared:crtbegin.o%s}" -+ -+#undef ENDFILE_SPEC -+#define ENDFILE_SPEC "%{!shared:crtend.o%s} crtn.o%s" -+ -+#undef LINK_SPEC -+#define LINK_SPEC "%{shared:-shared} %{!shared: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld.so}}}" -+ -+#undef TARGET_VERSION -+#define TARGET_VERSION fprintf(stderr, " (i386 toaru)"); -diff -rupN original/gcc/config.gcc new/gcc/config.gcc ---- original/gcc/config.gcc 2011-03-14 01:05:29.000000000 -0500 -+++ new/gcc/config.gcc 2011-04-24 20:04:11.000000000 -0500 -@@ -694,6 +694,12 @@ case ${target} in - *) echo 'Unknown thread configuration for VxWorks'; exit 1 ;; - esac - ;; -+*-*-toaru*) -+ extra_parts="crtbegin.o crtend.o" -+ gas=yes -+ gnu_ld=yes -+ default_use_cxa_atexit=yes -+ ;; - *-*-elf) - # Assume that newlib is being used and so __cxa_atexit is provided. - default_use_cxa_atexit=yes -@@ -1190,6 +1196,11 @@ hppa[12]*-*-hpux11*) - dwarf2=no - fi - ;; -+i[34567]86-*-toaru*) -+ tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h toaru.h" -+ tmake_file="${tmake_file} i386/t-i386elf t-svr4 i386/t-crtstuff" -+ use_fixproto=yes -+ ;; - i[34567]86-*-darwin*) - need_64bit_hwint=yes - need_64bit_isa=yes -diff -rupN original/libgcc/config.host new/libgcc/config.host ---- original/libgcc/config.host 2011-03-14 01:06:23.000000000 -0500 -+++ new/libgcc/config.host 2011-04-24 20:00:50.000000000 -0500 -@@ -345,6 +345,8 @@ x86_64-*-mingw*) - ;; - i[34567]86-*-interix3*) - ;; -+i[34567]86-*-toaru*) -+ ;; - ia64*-*-elf*) - extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtfastmath.o" - tmake_file="ia64/t-ia64" -diff -rupN original/libstdc++-v3/crossconfig.m4 new/libstdc++-v3/crossconfig.m4 ---- original/libstdc++-v3/crossconfig.m4 2011-02-04 01:26:57.000000000 -0600 -+++ new/libstdc++-v3/crossconfig.m4 2011-04-24 19:56:16.000000000 -0500 -@@ -249,6 +249,12 @@ case "${host}" in - AC_DEFINE(HAVE_ISNANL) - fi - ;; -+ *-toaru*) -+ AC_CHECK_HEADERS([sys/types.h local.h float.h]) -+ GLIBCXX_CHECK_BUILTIN_MATH_SUPPORT -+ GLIBCXX_CHECK_COMPLEX_MATH_SUPPORT -+ GLIBCXX_CHECK_STDLIB_SUPPORT -+ ;; - *-vxworks) - AC_DEFINE(HAVE_ACOSF) - AC_DEFINE(HAVE_ASINF) -diff -rupN original/gcc/gengtype.c new/gcc/gengtype.c ---- original/gcc/gengtype.c -+++ new/gcc/gengtype.c -@@ -3594,13 +3594,13 @@ write_field_root (outf_p f, pair_p v, type_p type, - int has_length, struct fileloc *line, const char *if_marked, - bool emit_pch, type_p field_type, const char *field_name) - { -+ struct pair newv; - /* If the field reference is relative to V, rather than to some - subcomponent of V, we can mark any subarrays with a single stride. - We're effectively treating the field as a global variable in its - own right. */ - if (v && type == v->type) - { -- struct pair newv; - - newv = *v; - newv.type = field_type; diff --git a/toolchain/patches/freetype-2.4.9.patch b/toolchain/patches/freetype-2.4.9.patch deleted file mode 100644 index 2fc9da11..00000000 --- a/toolchain/patches/freetype-2.4.9.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -rupN original/builds/unix/config.sub new/builds/unix/config.sub ---- original/builds/unix/config.sub 2012-03-08 15:09:13.000000000 -0500 -+++ new/builds/unix/config.sub 2012-05-17 11:40:42.308339450 -0400 -@@ -1343,6 +1343,7 @@ case $os in - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ diff --git a/toolchain/patches/gmp-5.0.1.patch b/toolchain/patches/gmp-5.0.1.patch deleted file mode 100644 index c7ff744b..00000000 --- a/toolchain/patches/gmp-5.0.1.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -rupN original/configfsf.sub new/configfsf.sub ---- original/configfsf.sub 2010-02-06 06:43:13.000000000 -0600 -+++ new/configfsf.sub 2012-04-23 16:18:31.000000000 -0500 -@@ -1252,6 +1252,7 @@ case $os in - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ diff --git a/toolchain/patches/libpng-1.5.13.patch b/toolchain/patches/libpng-1.5.13.patch deleted file mode 100644 index 789c4dfc..00000000 --- a/toolchain/patches/libpng-1.5.13.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -rupN original/config.sub new/config.sub ---- original/config.sub 2012-03-08 15:09:13.000000000 -0500 -+++ new/config.sub 2012-05-17 11:40:42.308339450 -0400 -@@ -1338,6 +1338,7 @@ case $os in - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ diff --git a/toolchain/patches/mpc-0.9.patch b/toolchain/patches/mpc-0.9.patch deleted file mode 100644 index 46220685..00000000 --- a/toolchain/patches/mpc-0.9.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -rupN original/config.sub new/config.sub ---- original/config.sub 2011-01-18 07:09:45.000000000 -0600 -+++ new/config.sub 2012-04-23 18:49:45.000000000 -0500 -@@ -1290,6 +1290,7 @@ case $os in - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ -+ | -toaru* \ - | -aos* | -aros* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ diff --git a/toolchain/patches/mpfr-3.0.1.patch b/toolchain/patches/mpfr-3.0.1.patch deleted file mode 100644 index 216bea97..00000000 --- a/toolchain/patches/mpfr-3.0.1.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -rupN original/config.sub new/config.sub ---- original/config.sub 2011-04-04 05:19:46.000000000 -0500 -+++ new/config.sub 2012-04-23 18:46:38.000000000 -0500 -@@ -1291,6 +1291,7 @@ case $os in - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ diff --git a/toolchain/patches/ncurses-5.9.patch b/toolchain/patches/ncurses-5.9.patch deleted file mode 100644 index cb504b46..00000000 --- a/toolchain/patches/ncurses-5.9.patch +++ /dev/null @@ -1,61 +0,0 @@ -diff -rupN ncurses-5.9/config.sub ncurses.new/config.sub ---- ncurses-5.9/config.sub 2010-09-10 15:25:58.000000000 -0700 -+++ ncurses.new/config.sub 2013-04-12 22:37:42.785340320 -0700 -@@ -1306,6 +1306,7 @@ case $os in - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ -diff -rupN ncurses-5.9/ncurses/tinfo/db_iterator.c ncurses.new/ncurses/tinfo/db_iterator.c ---- ncurses-5.9/ncurses/tinfo/db_iterator.c 2010-12-25 15:00:25.000000000 -0800 -+++ ncurses.new/ncurses/tinfo/db_iterator.c 2013-04-12 22:37:41.749340355 -0700 -@@ -90,7 +90,7 @@ NCURSES_EXPORT(void) - _nc_last_db(void) - { - if (ThisDbList != 0) { -- FreeAndNull(ThisDbList); -+ //FreeAndNull(ThisDbList); - } - ThisDbSize = 0; - } -diff -rupN ncurses-5.9/ncurses/tinfo/lib_termcap.c ncurses.new/ncurses/tinfo/lib_termcap.c ---- ncurses-5.9/ncurses/tinfo/lib_termcap.c 2010-12-25 11:27:12.000000000 -0800 -+++ ncurses.new/ncurses/tinfo/lib_termcap.c 2013-04-12 22:37:41.761340355 -0700 -@@ -166,18 +172,23 @@ NCURSES_SP_NAME(tgetent) (NCURSES_SP_DCL - if (backspace_if_not_bs != NULL) - BC = backspace_if_not_bs; - -+ -+#if 0 - if ((FIX_SGR0 = _nc_trim_sgr0(&(TerminalOf(SP_PARM)->type))) != 0) { - if (!strcmp(FIX_SGR0, exit_attribute_mode)) { - if (FIX_SGR0 != exit_attribute_mode) { -+ fprintf(stderr, "gonna free fix_sgr\n"); - free(FIX_SGR0); - } - FIX_SGR0 = 0; - } - } -+#endif - LAST_BUF = bufp; - LAST_USE = TRUE; - - SetNoPadding(SP_PARM); -+ - (void) NCURSES_SP_NAME(baudrate) (NCURSES_SP_ARG); /* sets ospeed as a side-effect */ - - /* LINT_PREPRO -diff -rupN ncurses-5.9/ncurses/tty/lib_twait.c ncurses.new/ncurses/tty/lib_twait.c ---- ncurses-5.9/ncurses/tty/lib_twait.c 2010-12-25 15:43:58.000000000 -0800 -+++ ncurses.new/ncurses/tty/lib_twait.c 2013-04-12 22:37:41.709340355 -0700 -@@ -52,6 +52,7 @@ - #undef true - #include - #endif -+# include - - #if USE_FUNC_POLL - # if HAVE_SYS_TIME_H diff --git a/toolchain/patches/newlib-1.19.0.patch b/toolchain/patches/newlib-1.19.0.patch deleted file mode 100644 index 4de82153..00000000 --- a/toolchain/patches/newlib-1.19.0.patch +++ /dev/null @@ -1,320 +0,0 @@ -diff -rupN _source/newlib-1.19.0/config.sub newlib-1.19.0/config.sub ---- _source/newlib-1.19.0/config.sub 2010-06-01 12:53:40.000000000 -0500 -+++ newlib-1.19.0/config.sub 2011-04-24 20:37:12.000000000 -0500 -@@ -1298,6 +1298,7 @@ case $os in - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ -diff -rupN _source/newlib-1.19.0/newlib/configure.host newlib-1.19.0/newlib/configure.host ---- _source/newlib-1.19.0/newlib/configure.host 2010-12-02 13:30:46.000000000 -0600 -+++ newlib-1.19.0/newlib/configure.host 2011-04-24 20:38:10.000000000 -0500 -@@ -418,6 +418,9 @@ case "${host}" in - h8500-*-elf*) - sys_dir=h8500hms - ;; -+ i[34567]86-*-toaru*) -+ sys_dir=toaru -+ ;; - i[34567]86-*-rdos*) - sys_dir=rdos - newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES" -@@ -543,6 +546,9 @@ esac - # THIS TABLE IS ALPHA SORTED. KEEP IT THAT WAY. - - case "${host}" in -+ *-*-toaru) -+ newlib_cflags="${newlib_cflags} -fPIC -DSIGNAL_PROVIDED -DMISSING_SYSCALL_NAMES -DMALLOC_PROVIDED -D_I386MACH_NEED_SOTYPE_FUNCTION" -+ ;; - *-*-cygwin*) - test -z "$cygwin_srcdir" && cygwin_srcdir=`cd ${srcdir}/../winsup/cygwin; pwd` - export cygwin_srcdir -diff -rupN _source/newlib-1.19.0/newlib/libc/include/sys/stat.h newlib-1.19.0/newlib/libc/include/sys/stat.h ---- _source/newlib-1.19.0/newlib/libc/include/sys/stat.h 2010-08-06 13:26:21.000000000 -0500 -+++ newlib-1.19.0/newlib/libc/include/sys/stat.h 2012-04-23 16:00:11.000000000 -0500 -@@ -150,8 +150,8 @@ int _EXFUN(mkfifo,( const char *__path, - int _EXFUN(stat,( const char *__path, struct stat *__sbuf )); - mode_t _EXFUN(umask,( mode_t __mask )); - --#if defined (__SPU__) || defined(__rtems__) || defined(__CYGWIN__) && !defined(__INSIDE_CYGWIN__) - int _EXFUN(lstat,( const char *__path, struct stat *__buf )); -+#if defined (__SPU__) || defined(__rtems__) || defined(__CYGWIN__) && !defined(__INSIDE_CYGWIN__) - int _EXFUN(mknod,( const char *__path, mode_t __mode, dev_t __dev )); - #endif - -diff -rupN _source/newlib-1.19.0/newlib/libc/include/sys/utime.h newlib-1.19.0/newlib/libc/include/sys/utime.h ---- _source/newlib-1.19.0/newlib/libc/include/sys/utime.h 2000-02-17 13:39:46.000000000 -0600 -+++ newlib-1.19.0/newlib/libc/include/sys/utime.h 2012-04-23 16:01:17.000000000 -0500 -@@ -15,6 +15,8 @@ struct utimbuf - time_t modtime; - }; - -+int utime(const char *filename, const struct utimbuf *times); -+ - #ifdef __cplusplus - }; - #endif -diff -rupN _source/newlib-1.19.0/newlib/libc/stdio/fseek.c newlib-1.19.0/newlib/libc/stdio/fseek.c ---- _source/newlib-1.19.0/newlib/libc/stdio/fseek.c 2009-12-17 13:43:43.000000000 -0600 -+++ newlib-1.19.0/newlib/libc/stdio/fseek.c 2011-04-29 19:33:10.000000000 -0500 -@@ -160,210 +160,6 @@ _DEFUN(_fseek_r, (ptr, fp, offset, whenc - return EOF; - } - -- /* -- * Change any SEEK_CUR to SEEK_SET, and check `whence' argument. -- * After this, whence is either SEEK_SET or SEEK_END. -- */ -- -- switch (whence) -- { -- case SEEK_CUR: -- /* -- * In order to seek relative to the current stream offset, -- * we have to first find the current stream offset a la -- * ftell (see ftell for details). -- */ -- _fflush_r (ptr, fp); /* may adjust seek offset on append stream */ -- if (fp->_flags & __SOFF) -- curoff = fp->_offset; -- else -- { -- curoff = seekfn (ptr, fp->_cookie, (_fpos_t) 0, SEEK_CUR); -- if (curoff == -1L) -- { -- _funlockfile (fp); -- __sfp_lock_release (); -- return EOF; -- } -- } -- if (fp->_flags & __SRD) -- { -- curoff -= fp->_r; -- if (HASUB (fp)) -- curoff -= fp->_ur; -- } -- else if (fp->_flags & __SWR && fp->_p != NULL) -- curoff += fp->_p - fp->_bf._base; -- -- offset += curoff; -- whence = SEEK_SET; -- havepos = 1; -- break; -- -- case SEEK_SET: -- case SEEK_END: -- havepos = 0; -- break; -- -- default: -- ptr->_errno = EINVAL; -- _funlockfile (fp); -- __sfp_lock_release (); -- return (EOF); -- } -- -- /* -- * Can only optimise if: -- * reading (and not reading-and-writing); -- * not unbuffered; and -- * this is a `regular' Unix file (and hence seekfn==__sseek). -- * We must check __NBF first, because it is possible to have __NBF -- * and __SOPT both set. -- */ -- -- if (fp->_bf._base == NULL) -- __smakebuf_r (ptr, fp); -- if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT)) -- goto dumb; -- if ((fp->_flags & __SOPT) == 0) -- { -- if (seekfn != __sseek -- || fp->_file < 0 --#ifdef __USE_INTERNAL_STAT64 -- || _fstat64_r (ptr, fp->_file, &st) --#else -- || _fstat_r (ptr, fp->_file, &st) --#endif -- || (st.st_mode & S_IFMT) != S_IFREG) -- { -- fp->_flags |= __SNPT; -- goto dumb; -- } --#ifdef HAVE_BLKSIZE -- fp->_blksize = st.st_blksize; --#else -- fp->_blksize = 1024; --#endif -- fp->_flags |= __SOPT; -- } -- -- /* -- * We are reading; we can try to optimise. -- * Figure out where we are going and where we are now. -- */ -- -- if (whence == SEEK_SET) -- target = offset; -- else -- { --#ifdef __USE_INTERNAL_STAT64 -- if (_fstat64_r (ptr, fp->_file, &st)) --#else -- if (_fstat_r (ptr, fp->_file, &st)) --#endif -- goto dumb; -- target = st.st_size + offset; -- } -- if ((long)target != target) -- { -- ptr->_errno = EOVERFLOW; -- _funlockfile (fp); -- __sfp_lock_release (); -- return EOF; -- } -- -- if (!havepos) -- { -- if (fp->_flags & __SOFF) -- curoff = fp->_offset; -- else -- { -- curoff = seekfn (ptr, fp->_cookie, 0L, SEEK_CUR); -- if (curoff == POS_ERR) -- goto dumb; -- } -- curoff -= fp->_r; -- if (HASUB (fp)) -- curoff -= fp->_ur; -- } -- -- /* -- * Compute the number of bytes in the input buffer (pretending -- * that any ungetc() input has been discarded). Adjust current -- * offset backwards by this count so that it represents the -- * file offset for the first byte in the current input buffer. -- */ -- -- if (HASUB (fp)) -- { -- curoff += fp->_r; /* kill off ungetc */ -- n = fp->_up - fp->_bf._base; -- curoff -= n; -- n += fp->_ur; -- } -- else -- { -- n = fp->_p - fp->_bf._base; -- curoff -= n; -- n += fp->_r; -- } -- -- /* -- * If the target offset is within the current buffer, -- * simply adjust the pointers, clear EOF, undo ungetc(), -- * and return. -- */ -- -- if (target >= curoff && target < curoff + n) -- { -- register int o = target - curoff; -- -- fp->_p = fp->_bf._base + o; -- fp->_r = n - o; -- if (HASUB (fp)) -- FREEUB (ptr, fp); -- fp->_flags &= ~__SEOF; -- memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); -- _funlockfile (fp); -- __sfp_lock_release (); -- return 0; -- } -- -- /* -- * The place we want to get to is not within the current buffer, -- * but we can still be kind to the kernel copyout mechanism. -- * By aligning the file offset to a block boundary, we can let -- * the kernel use the VM hardware to map pages instead of -- * copying bytes laboriously. Using a block boundary also -- * ensures that we only read one block, rather than two. -- */ -- -- curoff = target & ~(fp->_blksize - 1); -- if (seekfn (ptr, fp->_cookie, curoff, SEEK_SET) == POS_ERR) -- goto dumb; -- fp->_r = 0; -- fp->_p = fp->_bf._base; -- if (HASUB (fp)) -- FREEUB (ptr, fp); -- fp->_flags &= ~__SEOF; -- n = target - curoff; -- if (n) -- { -- if (__srefill_r (ptr, fp) || fp->_r < n) -- goto dumb; -- fp->_p += n; -- fp->_r -= n; -- } -- memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); -- _funlockfile (fp); -- __sfp_lock_release (); -- return 0; -- -- /* -- * We get here if we cannot optimise the seek ... just -- * do it. Allow the seek function to change fp->_bf._base. -- */ -- - dumb: - if (_fflush_r (ptr, fp) - || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) -diff -rupN _source/newlib-1.19.0/newlib/libc/stdlib/mallocr.c newlib-1.19.0/newlib/libc/stdlib/mallocr.c ---- _source/newlib-1.19.0/newlib/libc/stdlib/mallocr.c 2010-05-31 14:15:41.000000000 -0500 -+++ newlib-1.19.0/newlib/libc/stdlib/mallocr.c 2011-04-30 21:28:46.000000000 -0500 -@@ -609,8 +609,11 @@ do { - operating system immediately after a free(). - */ - -+#define HAVE_MMAP 0 -+#define HAVE_MREMAP 0 -+ - #ifndef HAVE_MMAP --#define HAVE_MMAP 1 -+#define HAVE_MMAP 0 - #endif - - /* -diff -rupN _source/newlib-1.19.0/newlib/libc/sys/configure newlib-1.19.0/newlib/libc/sys/configure ---- _source/newlib-1.19.0/newlib/libc/sys/configure 2010-12-16 15:59:03.000000000 -0600 -+++ newlib-1.19.0/newlib/libc/sys/configure 2011-04-24 20:39:58.000000000 -0500 -@@ -798,6 +798,7 @@ sysvi386 - sysvnecv70 - tic80 - w65 -+toaru - z8ksim' - - # Initialize some variables set by options. -@@ -11820,6 +11827,8 @@ subdirs="$subdirs a29khif" - ;; - w65) subdirs="$subdirs w65" - ;; -+ toaru) subdirs="$subdirs toaru" -+ ;; - z8ksim) subdirs="$subdirs z8ksim" - ;; - esac; -diff -rupN _source/newlib-1.19.0/newlib/libc/sys/configure.in newlib-1.19.0/newlib/libc/sys/configure.in ---- _source/newlib-1.19.0/newlib/libc/sys/configure.in 2010-02-24 14:59:55.000000000 -0600 -+++ newlib-1.19.0/newlib/libc/sys/configure.in 2011-04-24 20:37:33.000000000 -0500 -@@ -45,6 +45,7 @@ if test -n "${sys_dir}"; then - sysvnecv70) AC_CONFIG_SUBDIRS(sysvnecv70) ;; - tic80) AC_CONFIG_SUBDIRS(tic80) ;; - w65) AC_CONFIG_SUBDIRS(w65) ;; -+ toaru) AC_CONFIG_SUBDIRS(toaru) ;; - z8ksim) AC_CONFIG_SUBDIRS(z8ksim) ;; - esac; - fi diff --git a/toolchain/patches/newlib/setjmp.S b/toolchain/patches/newlib/setjmp.S deleted file mode 100644 index c443bdd9..00000000 --- a/toolchain/patches/newlib/setjmp.S +++ /dev/null @@ -1,91 +0,0 @@ -/* This is file is a merger of SETJMP.S and LONGJMP.S */ -/* - * This file was modified to use the __USER_LABEL_PREFIX__ and - * __REGISTER_PREFIX__ macros defined by later versions of GNU cpp by - * Joel Sherrill (joel@OARcorp.com) - * Slight change: now includes i386mach.h for this (Werner Almesberger) - * - * Copyright (C) 1991 DJ Delorie - * All rights reserved. - * - * Redistribution and use in source and binary forms is permitted - * provided that the above copyright notice and following paragraph are - * duplicated in all such forms. - * - * This file is distributed WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - - /* - ** jmp_buf: - ** eax ebx ecx edx esi edi ebp esp eip - ** 0 4 8 12 16 20 24 28 32 - */ - - #include "i386mach.h" - - .global SYM (setjmp) - .global SYM (longjmp) - SOTYPE_FUNCTION(setjmp) - SOTYPE_FUNCTION(longjmp) - -SYM (setjmp): - - pushl ebp - movl esp,ebp - - pushl edi - movl 8 (ebp),edi - - movl eax,0 (edi) - movl ebx,4 (edi) - movl ecx,8 (edi) - movl edx,12 (edi) - movl esi,16 (edi) - - movl -4 (ebp),eax - movl eax,20 (edi) - - movl 0 (ebp),eax - movl eax,24 (edi) - - movl esp,eax - addl $12,eax - movl eax,28 (edi) - - movl 4 (ebp),eax - movl eax,32 (edi) - - popl edi - movl $0,eax - leave - ret - -SYM (longjmp): - pushl ebp - movl esp,ebp - - movl 8(ebp),edi /* get jmp_buf */ - movl 12(ebp),eax /* store retval in j->eax */ - testl eax,eax - jne 0f - incl eax -0: - movl eax,0(edi) - - movl 24(edi),ebp - - /*__CLI */ - movl 28(edi),esp - - pushl 32(edi) - - movl 0(edi),eax - movl 4(edi),ebx - movl 8(edi),ecx - movl 12(edi),edx - movl 16(edi),esi - movl 20(edi),edi - /*__STI */ - - ret diff --git a/toolchain/patches/newlib/toaru/Makefile.am b/toolchain/patches/newlib/toaru/Makefile.am deleted file mode 100644 index 37098ac3..00000000 --- a/toolchain/patches/newlib/toaru/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -AUTOMAKE_OPTIONS = cygnus -INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) -AM_CCASFLAGS = $(INCLUDES) - -noinst_LIBRARIES = lib.a - -lib_a_SOURCES = syscalls.c klmalloc.c pwent.c -lib_a_CCASFLAGS = $(AM_CCASFLAGS) -lib_a_CFLAGS = $(AM_CFLAGS) - -all: crt0.o crti.o crtn.o - -ACLOCAL_AMFLAGS = -I ../../.. -I ../../../.. -CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host - diff --git a/toolchain/patches/newlib/toaru/Makefile.in b/toolchain/patches/newlib/toaru/Makefile.in deleted file mode 100644 index cec708e0..00000000 --- a/toolchain/patches/newlib/toaru/Makefile.in +++ /dev/null @@ -1,421 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = . -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/configure $(am__configure_deps) \ - $(srcdir)/../../../../mkinstalldirs -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/../../../acinclude.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(SHELL) $(top_srcdir)/../../../../mkinstalldirs -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -LIBRARIES = $(noinst_LIBRARIES) -ARFLAGS = cru -lib_a_AR = $(AR) $(ARFLAGS) -lib_a_LIBADD = -am_lib_a_OBJECTS = lib_a-syscalls.$(OBJEXT) lib_a-klmalloc.$(OBJEXT) -lib_a_OBJECTS = $(am_lib_a_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = -am__depfiles_maybe = -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -SOURCES = $(lib_a_SOURCES) -ETAGS = etags -CTAGS = ctags -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCAS = @CCAS@ -CCASFLAGS = @CCASFLAGS@ -CCDEPMODE = @CCDEPMODE@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -NEWLIB_CFLAGS = @NEWLIB_CFLAGS@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -READELF = @READELF@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -VERSION = @VERSION@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -aext = @aext@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -libm_machine_dir = @libm_machine_dir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lpfx = @lpfx@ -machine_dir = @machine_dir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -newlib_basedir = @newlib_basedir@ -oext = @oext@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sys_dir = @sys_dir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -AUTOMAKE_OPTIONS = cygnus -INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) -AM_CCASFLAGS = $(INCLUDES) -noinst_LIBRARIES = lib.a -lib_a_SOURCES = syscalls.c klmalloc.c -lib_a_CCASFLAGS = $(AM_CCASFLAGS) -lib_a_CFLAGS = $(AM_CFLAGS) -ACLOCAL_AMFLAGS = -I ../../.. -I ../../../.. -CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .o .obj -am--refresh: - @: -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --cygnus'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --cygnus \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --cygnus Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --cygnus Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -clean-noinstLIBRARIES: - -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) -lib.a: $(lib_a_OBJECTS) $(lib_a_DEPENDENCIES) - -rm -f lib.a - $(lib_a_AR) lib.a $(lib_a_OBJECTS) $(lib_a_LIBADD) - $(RANLIB) lib.a - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -.c.o: - $(COMPILE) -c $< - -.c.obj: - $(COMPILE) -c `$(CYGPATH_W) '$<'` - -lib_a-syscalls.o: syscalls.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-syscalls.o `test -f 'syscalls.c' || echo '$(srcdir)/'`syscalls.c - -lib_a-syscalls.obj: syscalls.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-syscalls.obj `if test -f 'syscalls.c'; then $(CYGPATH_W) 'syscalls.c'; else $(CYGPATH_W) '$(srcdir)/syscalls.c'; fi` - -lib_a-klmalloc.o: klmalloc.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-klmalloc.o `test -f 'klmalloc.c' || echo '$(srcdir)/'`klmalloc.c - -lib_a-klmalloc.obj: klmalloc.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-klmalloc.obj `if test -f 'klmalloc.c'; then $(CYGPATH_W) 'klmalloc.c'; else $(CYGPATH_W) '$(srcdir)/klmalloc.c'; fi` - -lib_a-pwent.obj: pwent.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-pwent.obj `if test -f 'pwent.c'; then $(CYGPATH_W) 'pwent.c'; else $(CYGPATH_W) '$(srcdir)/pwent.c'; fi` - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -check-am: -check: check-am -all-am: Makefile $(LIBRARIES) -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ - clean-generic clean-noinstLIBRARIES ctags distclean \ - distclean-compile distclean-generic distclean-tags dvi dvi-am \ - html html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am - - -all: crt0.o crti.o crtn.o - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/toolchain/patches/newlib/toaru/aclocal.m4 b/toolchain/patches/newlib/toaru/aclocal.m4 deleted file mode 100644 index 73cba657..00000000 --- a/toolchain/patches/newlib/toaru/aclocal.m4 +++ /dev/null @@ -1,992 +0,0 @@ -# generated automatically by aclocal 1.11.1 -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],, -[m4_warning([this file was generated for autoconf 2.67. -You have another version of autoconf. It may work, but is not guaranteed to. -If you have problems, you may need to regenerate the build system entirely. -To do so, use the procedure documented by the package, typically `autoreconf'.])]) - -# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_AUTOMAKE_VERSION(VERSION) -# ---------------------------- -# Automake X.Y traces this macro to ensure aclocal.m4 has been -# generated from the m4 files accompanying Automake X.Y. -# (This private macro should not be called outside this file.) -AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.11' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.11.1], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) - -# _AM_AUTOCONF_VERSION(VERSION) -# ----------------------------- -# aclocal traces this macro to find the Autoconf version. -# This is a private macro too. Using m4_define simplifies -# the logic in aclocal, which can simply ignore this definition. -m4_define([_AM_AUTOCONF_VERSION], []) - -# AM_SET_CURRENT_AUTOMAKE_VERSION -# ------------------------------- -# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. -# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. -AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.11.1])dnl -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) - -# AM_AUX_DIR_EXPAND -*- Autoconf -*- - -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to -# `$srcdir', `$srcdir/..', or `$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is `.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -AC_DEFUN([AM_AUX_DIR_EXPAND], -[dnl Rely on autoconf to set up CDPATH properly. -AC_PREREQ([2.50])dnl -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 9 - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[AC_PREREQ(2.52)dnl - ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) - -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 10 - -# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be -# written in clear, in which case automake, when reading aclocal.m4, -# will think it sees a *use*, and therefore will trigger all it's -# C support machinery. Also note that it means that autoscan, seeing -# CC etc. in the Makefile, will ask for an AC_PROG_CC use... - - -# _AM_DEPENDENCIES(NAME) -# ---------------------- -# See how the compiler implements dependency checking. -# NAME is "CC", "CXX", "GCJ", or "OBJC". -# We try a few techniques and use that to set a single cache variable. -# -# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was -# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular -# dependency, and given that the user is not expected to run this macro, -# just rely on AC_PROG_CC. -AC_DEFUN([_AM_DEPENDENCIES], -[AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -ifelse([$1], CC, [depcc="$CC" am_compiler_list=], - [$1], CXX, [depcc="$CXX" am_compiler_list=], - [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], UPC, [depcc="$UPC" am_compiler_list=], - [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named `D' -- because `-MD' means `put the output - # in D'. - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - am__universal=false - m4_case([$1], [CC], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac], - [CXX], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac]) - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with - # Solaris 8's {/usr,}/bin/sh. - touch sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # after this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvisualcpp | msvcmsys) - # This compiler won't grok `-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) - - -# AM_SET_DEPDIR -# ------------- -# Choose a directory name for dependency files. -# This macro is AC_REQUIREd in _AM_DEPENDENCIES -AC_DEFUN([AM_SET_DEPDIR], -[AC_REQUIRE([AM_SET_LEADING_DOT])dnl -AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl -]) - - -# AM_DEP_TRACK -# ------------ -AC_DEFUN([AM_DEP_TRACK], -[AC_ARG_ENABLE(dependency-tracking, -[ --disable-dependency-tracking speeds up one-time build - --enable-dependency-tracking do not reject slow dependency extractors]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH])dnl -_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl -]) - -# Generate code to set up dependency tracking. -*- Autoconf -*- - -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -#serial 5 - -# _AM_OUTPUT_DEPENDENCY_COMMANDS -# ------------------------------ -AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], -[{ - # Autoconf 2.62 quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac - shift - for mf - do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named `Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running `make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # When using ansi2knr, U may be empty or an underscore; expand it - U=`sed -n 's/^U = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done - done -} -])# _AM_OUTPUT_DEPENDENCY_COMMANDS - - -# AM_OUTPUT_DEPENDENCY_COMMANDS -# ----------------------------- -# This macro should only be invoked once -- use via AC_REQUIRE. -# -# This code is only required when automatic dependency tracking -# is enabled. FIXME. This creates each `.P' file that we will -# need in order to bootstrap the dependency handling code. -AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], -[AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) -]) - -# Do all the work for Automake. -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 16 - -# This macro actually does too much. Some checks are only needed if -# your package does certain things. But this isn't really a big deal. - -# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) -# AM_INIT_AUTOMAKE([OPTIONS]) -# ----------------------------------------------- -# The call with PACKAGE and VERSION arguments is the old style -# call (pre autoconf-2.50), which is being phased out. PACKAGE -# and VERSION should now be passed to AC_INIT and removed from -# the call to AM_INIT_AUTOMAKE. -# We support both call styles for the transition. After -# the next Automake release, Autoconf can make the AC_INIT -# arguments mandatory, and then we can depend on a new Autoconf -# release and drop the old call support. -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_PREREQ([2.62])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) - AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) -AM_MISSING_PROG(AUTOCONF, autoconf) -AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) -AM_MISSING_PROG(AUTOHEADER, autoheader) -AM_MISSING_PROG(MAKEINFO, makeinfo) -AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl -AC_REQUIRE([AM_PROG_MKDIR_P])dnl -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES(CC)], - [define([AC_PROG_CC], - defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES(CXX)], - [define([AC_PROG_CXX], - defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES(OBJC)], - [define([AC_PROG_OBJC], - defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl -]) -_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl -dnl The `parallel-tests' driver may need to know about EXEEXT, so add the -dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro -dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. -AC_CONFIG_COMMANDS_PRE(dnl -[m4_provide_if([_AM_COMPILER_EXEEXT], - [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl -]) - -dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not -dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further -dnl mangled by Autoconf and run in a shell conditional statement. -m4_define([_AC_COMPILER_EXEEXT], -m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) - - -# When config.status generates a header, we must update the stamp-h file. -# This file resides in the same directory as the config header -# that is generated. The stamp files are numbered to have different names. - -# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the -# loop where config.status creates the headers, so we can generate -# our stamp files there. -AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], -[# Compute $1's index in $config_headers. -_am_arg=$1 -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) - -# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST(install_sh)]) - -# Copyright (C) 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 2 - -# Check whether the underlying file-system supports filenames -# with a leading dot. For instance MS-DOS doesn't. -AC_DEFUN([AM_SET_LEADING_DOT], -[rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null -AC_SUBST([am__leading_dot])]) - -# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- -# From Jim Meyering - -# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 5 - -# AM_MAINTAINER_MODE([DEFAULT-MODE]) -# ---------------------------------- -# Control maintainer-specific portions of Makefiles. -# Default is to disable them, unless `enable' is passed literally. -# For symmetry, `disable' may be passed as well. Anyway, the user -# can override the default with the --enable/--disable switch. -AC_DEFUN([AM_MAINTAINER_MODE], -[m4_case(m4_default([$1], [disable]), - [enable], [m4_define([am_maintainer_other], [disable])], - [disable], [m4_define([am_maintainer_other], [enable])], - [m4_define([am_maintainer_other], [enable]) - m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) -AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) - dnl maintainer-mode's default is 'disable' unless 'enable' is passed - AC_ARG_ENABLE([maintainer-mode], -[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful - (and sometimes confusing) to the casual installer], - [USE_MAINTAINER_MODE=$enableval], - [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) - AC_MSG_RESULT([$USE_MAINTAINER_MODE]) - AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) - MAINT=$MAINTAINER_MODE_TRUE - AC_SUBST([MAINT])dnl -] -) - -AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) - -# Check to see how 'make' treats includes. -*- Autoconf -*- - -# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 4 - -# AM_MAKE_INCLUDE() -# ----------------- -# Check to see how make treats includes. -AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo this is the am__doit target -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -AC_MSG_CHECKING([for style of include used by $am_make]) -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from `make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD - ;; - esac -fi -AC_SUBST([am__include]) -AC_SUBST([am__quote]) -AC_MSG_RESULT([$_am_result]) -rm -f confinc confmf -]) - -# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- - -# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 6 - -# AM_MISSING_PROG(NAME, PROGRAM) -# ------------------------------ -AC_DEFUN([AM_MISSING_PROG], -[AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) - - -# AM_MISSING_HAS_RUN -# ------------------ -# Define MISSING if not defined so far and test if it supports --run. -# If it does, set am_missing_run to use it, otherwise, to nothing. -AC_DEFUN([AM_MISSING_HAS_RUN], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac -fi -# Use eval to expand $SHELL -if eval "$MISSING --run true"; then - am_missing_run="$MISSING --run " -else - am_missing_run= - AC_MSG_WARN([`missing' script is too old or missing]) -fi -]) - -# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_MKDIR_P -# --------------- -# Check for `mkdir -p'. -AC_DEFUN([AM_PROG_MKDIR_P], -[AC_PREREQ([2.60])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, -dnl while keeping a definition of mkdir_p for backward compatibility. -dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. -dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of -dnl Makefile.ins that do not define MKDIR_P, so we do our own -dnl adjustment using top_builddir (which is defined more often than -dnl MKDIR_P). -AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl -case $mkdir_p in - [[\\/$]]* | ?:[[\\/]]*) ;; - */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; -esac -]) - -# Helper functions for option handling. -*- Autoconf -*- - -# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 4 - -# _AM_MANGLE_OPTION(NAME) -# ----------------------- -AC_DEFUN([_AM_MANGLE_OPTION], -[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) - -# _AM_SET_OPTION(NAME) -# ------------------------------ -# Set option NAME. Presently that only means defining a flag for this option. -AC_DEFUN([_AM_SET_OPTION], -[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) - -# _AM_SET_OPTIONS(OPTIONS) -# ---------------------------------- -# OPTIONS is a space-separated list of Automake options. -AC_DEFUN([_AM_SET_OPTIONS], -[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) - -# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) -# ------------------------------------------- -# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. -AC_DEFUN([_AM_IF_OPTION], -[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) - -# Check to make sure that the build environment is sane. -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 5 - -# AM_SANITY_CHECK -# --------------- -AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) -# Just in case -sleep 1 -echo timestamp > conftest.file -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[[\\\"\#\$\&\'\`$am_lf]]*) - AC_MSG_ERROR([unsafe absolute working directory name]);; -esac -case $srcdir in - *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) - AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; -esac - -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[*]" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - rm -f conftest.file - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken -alias in your environment]) - fi - - test "$[2]" = conftest.file - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi -AC_MSG_RESULT(yes)]) - -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_STRIP -# --------------------- -# One issue with vendor `install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in `make install-strip', and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be `maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# Copyright (C) 2006, 2008 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 2 - -# _AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. -# This macro is traced by Automake. -AC_DEFUN([_AM_SUBST_NOTMAKE]) - -# AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Public sister of _AM_SUBST_NOTMAKE. -AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) - -# Check how to create a tarball. -*- Autoconf -*- - -# Copyright (C) 2004, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 2 - -# _AM_PROG_TAR(FORMAT) -# -------------------- -# Check how to create a tarball in format FORMAT. -# FORMAT should be one of `v7', `ustar', or `pax'. -# -# Substitute a variable $(am__tar) that is a command -# writing to stdout a FORMAT-tarball containing the directory -# $tardir. -# tardir=directory && $(am__tar) > result.tar -# -# Substitute a variable $(am__untar) that extract such -# a tarball read from stdin. -# $(am__untar) < result.tar -AC_DEFUN([_AM_PROG_TAR], -[# Always define AMTAR for backward compatibility. -AM_MISSING_PROG([AMTAR], [tar]) -m4_if([$1], [v7], - [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], - [m4_case([$1], [ustar],, [pax],, - [m4_fatal([Unknown tar format])]) -AC_MSG_CHECKING([how to create a $1 tar archive]) -# Loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' -_am_tools=${am_cv_prog_tar_$1-$_am_tools} -# Do not fold the above two line into one, because Tru64 sh and -# Solaris sh will not grok spaces in the rhs of `-'. -for _am_tool in $_am_tools -do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; - do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi -done -rm -rf conftest.dir - -AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) -AC_MSG_RESULT([$am_cv_prog_tar_$1])]) -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) # _AM_PROG_TAR - -m4_include([../../../acinclude.m4]) diff --git a/toolchain/patches/newlib/toaru/configure.in b/toolchain/patches/newlib/toaru/configure.in deleted file mode 100644 index 6a2c11b7..00000000 --- a/toolchain/patches/newlib/toaru/configure.in +++ /dev/null @@ -1,9 +0,0 @@ -AC_PREREQ(2.59) -AC_INIT([newlib], [NEWLIB_VERSION]) -AC_CONFIG_SRCDIR([crt0.s]) -AC_CONFIG_SRCDIR([crti.s]) -AC_CONFIG_SRCDIR([crtn.s]) -AC_CONFIG_AUX_DIR(../../../..) -NEWLIB_CONFIGURE(../../..) -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/toolchain/patches/newlib/toaru/lib.a b/toolchain/patches/newlib/toaru/lib.a deleted file mode 100644 index 850e6707..00000000 Binary files a/toolchain/patches/newlib/toaru/lib.a and /dev/null differ diff --git a/toolchain/patches/newlib/toaru/sys/errno.h b/toolchain/patches/newlib/toaru/sys/errno.h deleted file mode 100644 index 6b2c3826..00000000 --- a/toolchain/patches/newlib/toaru/sys/errno.h +++ /dev/null @@ -1,32 +0,0 @@ -/* errno is not a global variable, because that would make using it - non-reentrant. Instead, its address is returned by the function - __errno. */ - -#ifndef _SYS_ERRNO_H_ -#ifdef __cplusplus -extern "C" { -#endif -#define _SYS_ERRNO_H_ - -#include - -#ifndef _REENT_ONLY -#define errno (*__errno()) -extern int *__errno _PARAMS ((void)); -#endif - -/* Please don't use these variables directly. - Use strerror instead. */ -extern __IMPORT _CONST char * _CONST _sys_errlist[]; -extern __IMPORT int _sys_nerr; - -#define __errno_r(ptr) ((ptr)->_errno) - -#include - -#define __ELASTERROR 2000 /* Users can add values starting here */ - -#ifdef __cplusplus -} -#endif -#endif /* _SYS_ERRNO_H */ diff --git a/toolchain/patches/newlib/toaru/syscalls.c b/toolchain/patches/newlib/toaru/syscalls.c deleted file mode 100644 index 567f5f7d..00000000 --- a/toolchain/patches/newlib/toaru/syscalls.c +++ /dev/null @@ -1,740 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2014 Kevin Lange - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include <_ansi.h> -#include - -#include "syscall.h" -#include - -#include - -extern void *malloc(size_t size); -extern void free(void *ptr); -extern void *calloc(size_t nmemb, size_t size); -extern void *realloc(void *ptr, size_t size); - -extern void _init(); -extern void _fini(); - -DEFN_SYSCALL1(exit, 0, int); -DEFN_SYSCALL1(print, 1, const char *); -DEFN_SYSCALL3(open, 2, const char *, int, int); -DEFN_SYSCALL3(read, 3, int, char *, int); -DEFN_SYSCALL3(write, 4, int, char *, int); -DEFN_SYSCALL1(close, 5, int); -DEFN_SYSCALL2(gettimeofday, 6, void *, void *); -DEFN_SYSCALL3(execve, 7, char *, char **, char **); -DEFN_SYSCALL0(fork, 8); -DEFN_SYSCALL0(getpid, 9); -DEFN_SYSCALL1(sbrk, 10, int); -DEFN_SYSCALL0(getgraphicsaddress, 11); -DEFN_SYSCALL1(uname, 12, void *); -DEFN_SYSCALL5(openpty, 13, int *, int *, char *, void *, void *); -DEFN_SYSCALL3(lseek, 14, int, int, int); -DEFN_SYSCALL2(fstat, 15, int, void *); -DEFN_SYSCALL1(setgraphicsoffset, 16, int); -DEFN_SYSCALL1(wait, 17, unsigned int); -DEFN_SYSCALL0(getgraphicswidth, 18); -DEFN_SYSCALL0(getgraphicsheight, 19); -DEFN_SYSCALL0(getgraphicsdepth, 20); -DEFN_SYSCALL0(mkpipe, 21); -DEFN_SYSCALL2(dup2, 22, int, int); -DEFN_SYSCALL0(getuid, 23); -DEFN_SYSCALL1(setuid, 24, unsigned int); -DEFN_SYSCALL1(kernel_string_XXX, 25, char *); -DEFN_SYSCALL0(reboot, 26); -DEFN_SYSCALL3(readdir, 27, int, int, void *); -DEFN_SYSCALL1(chdir, 28, char *); -DEFN_SYSCALL2(getcwd, 29, char *, size_t); -DEFN_SYSCALL3(clone, 30, uintptr_t, uintptr_t, void *); -DEFN_SYSCALL1(sethostname, 31, char *); -DEFN_SYSCALL1(gethostname, 32, char *); -DEFN_SYSCALL0(mousedevice, 33); -DEFN_SYSCALL2(mkdir, 34, char *, unsigned int); -DEFN_SYSCALL2(shm_obtain, 35, char *, size_t *); -DEFN_SYSCALL1(shm_release, 36, char *); -DEFN_SYSCALL2(send_signal, 37, uint32_t, uint32_t); -DEFN_SYSCALL2(signal, 38, uint32_t, void *); -DEFN_SYSCALL2(share_fd, 39, int, int); -DEFN_SYSCALL1(get_fd, 40, int); -DEFN_SYSCALL0(gettid, 41); -DEFN_SYSCALL0(yield, 42); -DEFN_SYSCALL2(system_function, 43, int, char **); -DEFN_SYSCALL1(open_serial, 44, int); -DEFN_SYSCALL2(sleepabs, 45, unsigned long, unsigned long); -DEFN_SYSCALL2(nanosleep, 46, unsigned long, unsigned long); -DEFN_SYSCALL3(ioctl, 47, int, int, void *); -DEFN_SYSCALL2(access, 48, char *, int); -DEFN_SYSCALL2(stat, 49, char *, void *); -DEFN_SYSCALL2(chmod, 50, char *, mode_t); -DEFN_SYSCALL1(umask, 51, mode_t); -DEFN_SYSCALL1(unlink, 52, char *); -DEFN_SYSCALL3(waitpid, 53, int, int *, int); -DEFN_SYSCALL1(pipe, 54, int *); -DEFN_SYSCALL5(mount, SYS_MOUNT, char *, char *, char *, unsigned long, void *); -DEFN_SYSCALL2(symlink, SYS_SYMLINK, char *, char *); -DEFN_SYSCALL3(readlink, SYS_READLINK, char *, char *, int); -DEFN_SYSCALL2(lstat, SYS_LSTAT, char *, void *); -DEFN_SYSCALL2(fswait, SYS_FSWAIT, int, int *); -DEFN_SYSCALL3(fswait2, SYS_FSWAIT2, int, int *,int); -DEFN_SYSCALL3(chown, SYS_CHOWN, char *, int, int); - -static int toaru_debug_stubs_enabled(void) { - static int checked = 0; - static int enabled = 0; - if (!checked) { - char * t = getenv("TOARU_DEBUG_STUBS"); - checked = 1; - if (t && !strcmp(t,"1")) { - enabled = 1; - } - } - return enabled; -} - -#define DEBUG_STUB(...) \ - if (toaru_debug_stubs_enabled()) { \ - fprintf(stderr, "\033[1;32mUserspace Debug\033[0m pid%d ", getpid()); fprintf(stderr, __VA_ARGS__); \ - } - - -extern char ** environ; - -int ioctl(int fd, int request, void * argp); - -#define DEFAULT_PATH ".:/bin:/usr/bin" - -// --- Process Control --- - -int _exit(int val){ - _fini(); - return syscall_exit(val); -} - -int execve(const char *name, char * const argv[], char * const envp[]) { - return syscall_execve((char*)name,(char**)argv,(char**)envp); -} - -int execvp(const char *file, char *const argv[]) { - if (file && (!strstr(file, "/"))) { - /* We don't quite understand "$PATH", so... */ - char * path = getenv("PATH"); - if (!path) { - path = DEFAULT_PATH; - } - char * xpath = strdup(path); - int found = 0; - char * p, * tokens[10], * last; - int i = 0; - for ((p = strtok_r(xpath, ":", &last)); p; p = strtok_r(NULL, ":", &last)) { - int r; - struct stat stat_buf; - char * exe = malloc(strlen(p) + strlen(file) + 2); - strcpy(exe, p); - strcat(exe, "/"); - strcat(exe, file); - - r = stat(exe, &stat_buf); - if (r != 0) { - continue; - } - if (!(stat_buf.st_mode & 0111)) { - continue; /* XXX not technically correct; need to test perms */ - } - return execve(exe, argv, environ); - } - free(xpath); - errno = ENOENT; - return -1; - } else if (file) { - return execve(file, argv, environ); - } - errno = ENOENT; - return -1; -} - -int execv(const char * file, char *const argv[]) { - return execve(file,argv,environ); -} - -/* - * getpid -- only one process, so just return 1. - */ -int getpid() { - return syscall_getpid(); -} - -/* Fork. Duh. */ -int fork(void) { - return syscall_fork(); -} - -int uname(struct utsname *__name) { - return syscall_uname((void *)__name); -} - - -/* - * kill -- go out via exit... - */ -int kill(int pid, int sig) { - return syscall_send_signal(pid, sig); -} - -sighandler_t signal(int signum, sighandler_t handler) { - return (sighandler_t)syscall_signal(signum, (void *)handler); -} - -#if 0 -int raise(int sig) { - kill(getpid(), sig); - return 0; -} -#endif - -int waitpid(int pid, int *status, int options) { - /* XXX: status, options? */ - int i = syscall_waitpid(pid, status, options); - if (i < 0) { - errno = -i; - return -1; - } - return i; -} - -int wait(int *status) { - return waitpid(-1, status, 0); -} - -// --- I/O --- - -int isatty(int fd) { - int dtype = ioctl(fd, IOCTLDTYPE, NULL); - if (dtype == IOCTL_DTYPE_TTY) return 1; - errno = EINVAL; - return 0; -} - - -int close(int file) { - return syscall_close(file); -} - -int link(char *old, char *new) { - DEBUG_STUB("[debug] pid %d: link(%s, %s);\n", getpid(), old, new); - errno = EMLINK; - return -1; -} - -int lseek(int file, int ptr, int dir) { - return syscall_lseek(file,ptr,dir); -} - -int open(const char *name, int flags, ...) { - va_list argp; - int mode; - int result; - va_start(argp, flags); - if (flags & O_CREAT) mode = va_arg(argp, int); - va_end(argp); - - result = syscall_open(name, flags, mode); - if (result == -1) { - if (flags & O_CREAT) { - errno = EACCES; - } else { - errno = ENOENT; - } - } else if (result < 0) { - errno = -result; - } - return result; -} - -int read(int file, char *ptr, int len) { - return syscall_read(file,ptr,len); -} - -int creat(const char *path, mode_t mode) { - return open(path, O_WRONLY|O_CREAT|O_TRUNC, mode); -} - -int fstat(int file, struct stat *st) { - syscall_fstat(file, st); - return 0; -} - -int stat(const char *file, struct stat *st){ - int ret = syscall_stat((char *)file, (void *)st); - if (ret >= 0) { - return ret; - } else { - errno = ENOENT; /* meh */ - memset(st, 0x00, sizeof(struct stat)); - return ret;; - } -} - -int write(int file, char *ptr, int len) { - return syscall_write(file,ptr,len); -} - -/* - * sbrk: request a larger heap - * [the kernel will give this to us] - */ -caddr_t sbrk(int nbytes){ - return (caddr_t)syscall_sbrk(nbytes); -} - -// --- Other --- -int gettimeofday(struct timeval *p, void *z){ - return syscall_gettimeofday(p,z); -} - -int pipe(int fildes[2]) { - int ret = syscall_pipe((int *)fildes); - if (ret < 0) { - errno = -ret; - return -1; - } - return ret; -} - -char *getcwd(char *buf, size_t size) { - if (!buf) buf = malloc(size); - return (char *)syscall_getcwd(buf, size); -} - -char *getwd(char *buf) { - return getcwd(buf, 256); -} - -int lstat(const char *path, struct stat *st) { - int ret = syscall_lstat((char *)path, (void *)st); - if (ret >= 0) { - return ret; - } else { - errno = -ret; - memset(st, 0x00, sizeof(struct stat)); - return ret; - } -} - -int mkdir(const char *pathname, mode_t mode) { - int ret = syscall_mkdir((char *)pathname, mode); - if (ret < 0) { - errno = -ret; - return -1; - } - return ret; -} - -int chdir(const char *path) { - return syscall_chdir((char*)path); -} - -unsigned int sleep(unsigned int seconds) { - syscall_nanosleep(seconds, 0); - return 0; -} - -int usleep(useconds_t usec) { - syscall_nanosleep(0, usec / 10000); - return 0; -} - - -char _username[256]; -char *getlogin(void) { -#define LINE_LEN 4096 - FILE * passwd = fopen("/etc/passwd", "r"); - char line[LINE_LEN]; - - int uid = syscall_getuid(); - - while (fgets(line, LINE_LEN, passwd) != NULL) { - - line[strlen(line)-1] = '\0'; - - char *p, *tokens[10], *last; - int i = 0; - for ((p = strtok_r(line, ":", &last)); p; - (p = strtok_r(NULL, ":", &last)), i++) { - if (i < 511) tokens[i] = p; - } - tokens[i] = NULL; - - if (atoi(tokens[2]) == uid) { - memcpy(_username, tokens[0], strlen(tokens[0])+1); - break; - } - } - fclose(passwd); - - return (char *)&_username; -} - -int dup2(int oldfd, int newfd) { - return syscall_dup2(oldfd, newfd); -} - -DIR * opendir (const char * dirname) { - int fd = open(dirname, O_RDONLY); - if (fd == -1) { - return NULL; - } - - DIR * dir = (DIR *)malloc(sizeof(DIR)); - dir->fd = fd; - dir->cur_entry = -1; - return dir; -} - -int closedir (DIR * dir) { - if (dir && (dir->fd != -1)) { - return close(dir->fd); - } else { - return -1; - } -} - -struct dirent * readdir (DIR * dirp) { - static struct dirent ent; - - int ret = syscall_readdir(dirp->fd, ++dirp->cur_entry, &ent); - if (ret != 0) { - memset(&ent, 0, sizeof(struct dirent)); - return NULL; - } - - return &ent; -} - -void pre_main(int (*main)(int,char**), int argc, char * argv[]) { - unsigned int x = 0; - unsigned int nulls = 0; - for (x = 0; 1; ++x) { - if (!argv[x]) { - ++nulls; - if (nulls == 2) { - break; - } - continue; - } - if (nulls == 1) { - environ = &argv[x]; - break; - } - } - _init(); - _exit(main(argc, argv)); -} - - -/* XXX Unimplemented functions */ -unsigned int alarm(unsigned int seconds) { - DEBUG_STUB("alarm(%s);\n", seconds); - return 0; -} - -clock_t times(struct tms *buf) { - /* TODO: times() */ - return -1; -} - - -int fcntl(int fd, int cmd, ...) { - if (cmd == F_GETFD || cmd == F_SETFD) { - return 0; - } - DEBUG_STUB("[user/debug] Unsupported operation [fcntl]\n"); - /* Not supported */ - return -1; -} - -mode_t umask(mode_t mask) { - return syscall_umask(mask); -} - -int chmod(const char *path, mode_t mode) { - int result = syscall_chmod((char *)path, mode); - if (result < 0) { - errno = -result; - result = -1; - } - return result; -} - -int unlink(char *name) { - return syscall_unlink(name); -} - -int access(const char *pathname, int mode) { - int result = syscall_access((char *)pathname, mode); - if (result < 0) { - errno = ENOENT; /* XXX */ - } - return result; -} - -long pathconf(char *path, int name) { - DEBUG_STUB("[user/debug] Unsupported operation [pathconf]\n"); - /* Not supported */ - return 0; -} - - -int utime(const char *filename, const struct utimbuf *times) { - DEBUG_STUB("[user/debug] Unsupported operation [utime]\n"); - return 0; -} - -int chown(const char *path, uid_t owner, gid_t group) { - int result = syscall_chown((char *)path, owner, group); - if (result < 0) { - errno = -result; - result = -1; - } - return result; -} - -int rmdir(const char *pathname) { - DEBUG_STUB("[user/debug] Unsupported operation [rmdir]\n"); - return 0; -} - - -char *ttyname(int fd) { - errno = ENOTTY; - return NULL; -} - -long sysconf(int name) { - switch (name) { - case 8: - return 4096; - case 11: - return 10000; - default: - DEBUG_STUB("sysconf(%d);\n", name); - return -1; - } -} - -int ioctl(int fd, int request, void * argp) { - return syscall_ioctl(fd, request, argp); -} - -/* termios */ -speed_t cfgetispeed(const struct termios * tio) { - return 0; -} -speed_t cfgetospeed(const struct termios * tio) { - return 0; -} - -int cfsetispeed(struct termios * tio, speed_t speed) { - /* hahahaha, yeah right */ - return 0; -} - -int cfsetospeed(struct termios * tio, speed_t speed) { - return 0; -} - -int tcdrain(int i) { - DEBUG_STUB("tcdrain(%d)\n", i); - return 0; -} - -int tcflow(int fd, int arg) { - return ioctl(fd, TCXONC, arg); -} - -int tcflush(int fd, int arg) { - return ioctl(fd, TCFLSH, arg); -} - -pid_t tcgetsid(int fd) { - DEBUG_STUB("tcgetsid(%d)\n", fd); - return getpid(); -} - -int tcsendbreak(int fd, int arg) { - return ioctl(fd, TCSBRK, arg); -} - -int tcgetattr(int fd, struct termios * tio) { - return ioctl(fd, TCGETS, tio); -} - -int tcsetattr(int fd, int actions, struct termios * tio) { - switch (actions) { - case TCSANOW: - return ioctl(fd, TCSETS, tio); - case TCSADRAIN: - return ioctl(fd, TCSETSW, tio); - case TCSAFLUSH: - return ioctl(fd, TCSETSF, tio); - default: - return 0; - } -} - -int tcsetpgrp(int fd, pid_t pgrp) { - return ioctl(fd, TIOCSPGRP, &pgrp); -} - -pid_t tcgetpgrp(int fd) { - pid_t pgrp; - ioctl(fd, TIOCGPGRP, &pgrp); - return pgrp; -} - -int fpathconf(int file, int name) { - DEBUG_STUB("fpathconf(%d,%d)\n", file, name); - return 0; -} - -int setuid(uid_t uid) { - return syscall_setuid(uid); -} - -int getuid() { - return syscall_getuid(); -} - -int getgid() { - return getuid(); -} - -int getpgrp() { - /* XXX */ - return getgid(); -} - -int geteuid() { - return getuid(); -} - -int getegid() { - return getgid(); -} - -int getgroups(int size, gid_t list[]) { - DEBUG_STUB("getgroups(...);\n"); - return 0; -} - -pid_t wait3(int *status, int options, void *rusage) { - return wait(status); -} - -int dup(int oldfd) { - return dup2(oldfd, -1); -} - -int sched_yield(void) { - return syscall_yield(); -} - -int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { - DEBUG_STUB("sigprocmask(%d, 0x%x, 0x%x);\n", how, set, oldset); - return -1; -} - -int sigsuspend(const sigset_t * mask) { - DEBUG_STUB("sigsuspend(0x%x);\n", mask); - syscall_yield(); - return -1; -} - -int setpgid(pid_t pid, pid_t pgid) { - DEBUG_STUB("setpgid(%d,%d);\n", pid, pgid); - return -1; -} - -int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { - - sighandler_t old; - - if (act) { - old = signal(signum, act->sa_handler); - } else { - /* We don't have a way to query, so we need to set to something, then - * set back to whatever it was... XXX */ - old = signal(signum, NULL); - signal(signum, old); - } - - if (oldact) { - oldact->sa_handler = old; - } - - if (act) { - DEBUG_STUB("sigaction(%d,...,0x%x);\n", signum, act->sa_flags); - } - - return 0; -} - -pid_t getppid() { - DEBUG_STUB("getppid()\n"); - return 0; -} - - -void sync() { - DEBUG_STUB("sync();\n"); -} - -int mount(char * source, char * target, char * type, unsigned long flags, void * data) { - int r = syscall_mount(source, target, type, flags, data); - - if (r < 0) { - errno = -r; - return -1; - } - - return r; -} - -int symlink(char * target, char * name) { - int r = syscall_symlink(target, name); - - if (r < 0) { - errno = -r; - return -1; - } - - return r; -} - -int readlink(char * name, char * buf, size_t len) { - int r = syscall_readlink(name, buf, len); - - if (r < 0) { - errno = -r; - return -1; - } - - return r; -} diff --git a/toolchain/patches/newlib/wcswidth.c b/toolchain/patches/newlib/wcswidth.c deleted file mode 100644 index 13909ea1..00000000 --- a/toolchain/patches/newlib/wcswidth.c +++ /dev/null @@ -1,17 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -#include -int wcswidth(const wchar_t * pwcs, size_t n) { - int width = 0; - for (; *pwcs && n-- > 0; ++pwcs) { - int w = wcwidth(*pwcs); - if (w < 0) { - return -1; - } else { - width += w; - } - } - return width; -} diff --git a/toolchain/patches/pixman-0.26.2.patch b/toolchain/patches/pixman-0.26.2.patch deleted file mode 100644 index d5d954f7..00000000 --- a/toolchain/patches/pixman-0.26.2.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff -rupN original/config.sub new/config.sub ---- original/config.sub 2012-03-08 15:09:13.000000000 -0500 -+++ new/config.sub 2012-05-17 11:40:42.308339450 -0400 -@@ -1338,6 +1338,7 @@ case $os in - | -sym* | -kopensolaris* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ -+ | -toaru* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ -diff -rupN original/pixman/pixman-utils.c new/pixman/pixman-utils.c ---- original/pixman/pixman-utils.c 2012-06-29 11:25:17.000000000 -0700 -+++ new/pixman/pixman-utils.c 2012-09-16 01:35:44.000000000 -0700 -@@ -41,7 +41,10 @@ - } cache [N_CACHED_FAST_PATHS]; - } cache_t; - --PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache); -+//PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache); -+// -+ -+cache_t fast_path_cache; - - pixman_bool_t - _pixman_lookup_composite_function (pixman_implementation_t *toplevel, -@@ -60,7 +63,7 @@ - int i; - - /* Check cache for fast paths */ -- cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache); -+ cache = &fast_path_cache; //PIXMAN_GET_THREAD_LOCAL (fast_path_cache); - - for (i = 0; i < N_CACHED_FAST_PATHS; ++i) - { diff --git a/toolchain/patches/vim73.patch b/toolchain/patches/vim73.patch deleted file mode 100644 index 69f28ff9..00000000 --- a/toolchain/patches/vim73.patch +++ /dev/null @@ -1,142 +0,0 @@ -diff -rupN vim73/src/auto/configure vim73.new/src/auto/configure ---- vim73/src/auto/configure 2010-08-13 07:17:15.000000000 -0700 -+++ vim73.new/src/auto/configure 2013-04-12 22:18:41.041376890 -0700 -@@ -316,7 +316,7 @@ $as_echo X"$as_dir" | - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" -- } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" -+ } || test -d "$as_dir" - - - } # as_fn_mkdir_p -@@ -11639,37 +11639,6 @@ _ACEOF - - - --{ $as_echo "$as_me:${as_lineno-$LINENO}: checking uint32_t is 32 bits" >&5 --$as_echo_n "checking uint32_t is 32 bits... " >&6; } --if test "$cross_compiling" = yes; then : -- as_fn_error "could not compile program using uint32_t." "$LINENO" 5 --else -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext --/* end confdefs.h. */ -- --#ifdef HAVE_STDINT_H --# include --#endif --#ifdef HAVE_INTTYPES_H --# include --#endif --main() { -- uint32_t nr1 = (uint32_t)-1; -- uint32_t nr2 = (uint32_t)0xffffffffUL; -- if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) exit(1); -- exit(0); --} --_ACEOF --if ac_fn_c_try_run "$LINENO"; then : -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 --$as_echo "ok" >&6; } --else -- as_fn_error "WRONG! uint32_t not defined correctly." "$LINENO" 5 --fi --rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext --fi -- - - - bcopy_test_prog=' -diff -rupN vim73/src/configure.in vim73.new/src/configure.in ---- vim73/src/configure.in 2010-08-13 07:15:17.000000000 -0700 -+++ vim73.new/src/configure.in 2013-04-12 22:18:41.049376887 -0700 -@@ -3180,7 +3180,7 @@ main() { - }], - AC_MSG_RESULT(ok), - AC_MSG_ERROR([WRONG! uint32_t not defined correctly.]), --AC_MSG_ERROR([could not compile program using uint32_t.])) -+AC_MSG_RESULT([assuming ok])) - - dnl Check for memmove() before bcopy(), makes memmove() be used when both are - dnl present, fixes problem with incompatibility between Solaris 2.4 and 2.5. -diff -rupN vim73/src/feature.h vim73.new/src/feature.h ---- vim73/src/feature.h 2010-07-27 12:45:42.000000000 -0700 -+++ vim73.new/src/feature.h 2013-04-12 22:18:41.033376891 -0700 -@@ -1012,7 +1012,7 @@ - * +system Use system() instead of fork/exec for starting a - * shell. Doesn't work for the GUI! - */ --/* #define USE_SYSTEM */ -+#define USE_SYSTEM - - /* - * +X11 Unix only. Include code for xterm title saving and X -@@ -1312,3 +1312,4 @@ - #ifdef FEAT_NORMAL - # define FEAT_PERSISTENT_UNDO - #endif -+#define SYS_VIMRC_FILE "/etc/vimrc" -diff -rupN vim73/src/fileio.c vim73.new/src/fileio.c ---- vim73/src/fileio.c 2010-08-14 05:20:54.000000000 -0700 -+++ vim73.new/src/fileio.c 2013-04-12 22:18:41.049376887 -0700 -@@ -7362,6 +7362,9 @@ vim_tempname(extra_char) - struct stat st; - # endif - -+ sprintf((char *)itmp, "/.vim-%ld", temp_count++); -+ return vim_strsave(itmp); -+ - /* - * This will create a directory for private use by this instance of Vim. - * This is done once, and the same directory is used for all temp files. -diff -rupN vim73/src/Makefile vim73.new/src/Makefile ---- vim73/src/Makefile 2010-08-15 05:56:15.000000000 -0700 -+++ vim73.new/src/Makefile 2013-04-12 22:18:41.041376890 -0700 -@@ -930,6 +930,9 @@ TOOLS = xxd/xxd$(EXEEXT) - # directories. This directory must exist. - #DESTDIR = ~/pkg/vim - -+DESTDIR=/usr/share/vim -+prefix=/usr -+ - ### Directory of the man pages - MAN1DIR = /man1 - -diff -rupN vim73/src/os_unix.c vim73.new/src/os_unix.c ---- vim73/src/os_unix.c 2010-08-08 06:14:04.000000000 -0700 -+++ vim73.new/src/os_unix.c 2013-04-12 22:18:41.049376887 -0700 -@@ -31,6 +31,33 @@ - - #include "vim.h" - -+#define POLLIN 0x0001 /* There is data to read */ -+#define POLLPRI 0x0002 /* There is urgent data to read */ -+#define POLLOUT 0x0004 /* Writing now will not block */ -+#define POLLERR 0x0008 /* Error condition */ -+#define POLLHUP 0x0010 /* Hung up */ -+#define POLLNVAL 0x0020 /* Invalid request: fd not open */ -+ -+struct pollfd { int fd; short events; short revents; }; -+ -+ /* fswait define used to be here */ -+#include -+ -+int poll(struct pollfd * ufds, long nfds, int timeout) { -+ if (nfds > 1) { fprintf(stderr, "Unexpectedly waiting on multiple file descriptors?\n"); } -+ if (nfds > 0) { -+ int fds[] = {ufds[0].fd}; -+ if (timeout == -1) { fflush(stderr); timeout = 100; } -+ int index = syscall_fswait2(1, fds, timeout); -+ if (index == 0) return 1; -+ if (index < 0) return 0; -+ return 0; -+ } else { -+ if (timeout > 0) { usleep(1000 * timeout); } -+ return 0; -+ } -+} -+ - #ifdef FEAT_MZSCHEME - # include "if_mzsch.h" - #endif diff --git a/toolchain/prepare.sh b/toolchain/prepare.sh deleted file mode 100755 index f2ee613b..00000000 --- a/toolchain/prepare.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash - -# Toolchain Installer for Debian-like systems. If you're running -# something else, you're pretty much on your own. - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -. $DIR/util.sh - -pushd "$DIR" > /dev/null - - if [ ! -d tarballs ]; then - mkdir tarballs - fi - pushd tarballs > /dev/null - $INFO "wget" "Pulling source packages..." - grab "gcc" "http://www.netgull.com/gcc/releases/gcc-6.4.0" "gcc-6.4.0.tar.gz" || bail - #grab "mpc" "http://www.multiprecision.org/mpc/download" "mpc-0.9.tar.gz" - #grab "mpfr" "http://www.mpfr.org/mpfr-3.0.1" "mpfr-3.0.1.tar.gz" - #grab "gmp" "ftp://ftp.gmplib.org/pub/gmp-5.0.1" "gmp-5.0.1.tar.gz" - grab "binutils" "http://ftp.gnu.org/gnu/binutils" "binutils-2.27.tar.gz" || bail - grab "newlib" "http://b.dakko.us/~klange/mirrors" "newlib-1.19.0.tar.gz" || bail - grab "freetype" "http://download.savannah.gnu.org/releases/freetype" "freetype-2.4.9.tar.gz" || bail - grab "zlib" "http://zlib.net/fossils" "zlib-1.2.8.tar.gz" || bail - grab "libpng" "http://b.dakko.us/~klange/mirrors" "libpng-1.5.13.tar.gz" || bail - grab "pixman" "http://www.cairographics.org/releases" "pixman-0.26.2.tar.gz" || bail - grab "cairo" "http://www.cairographics.org/releases" "cairo-1.12.2.tar.xz" || bail - grab "ncurses" "http://b.dakko.us/~klange/mirrors" "ncurses-5.9.tar.gz" || bail - grab "vim" "ftp://ftp.vim.org/pub/vim/unix" "vim-7.3.tar.bz2" || bail - $INFO "wget" "Pulled source packages." - rm -rf "binutils-2.27" "freetype-2.4.9" "gcc-6.4.0" "gmp-5.0.1" "libpng-1.5.13" "mpc-0.9" "mpfr-3.0.1" "newlib-1.19.0" "zlib-1.2.7" "pixman-0.28.2" "ncurses-5.9" "vim73" - $INFO "tar" "Decompressing..." - deco "gcc" "gcc-6.4.0.tar.gz" || bail - #deco "mpc" "mpc-0.9.tar.gz" - #deco "mpfr" "mpfr-3.0.1.tar.gz" - #deco "gmp" "gmp-5.0.1.tar.gz" - deco "binutils" "binutils-2.27.tar.gz" || bail - deco "newlib" "newlib-1.19.0.tar.gz" || bail - deco "freetype" "freetype-2.4.9.tar.gz" || bail - deco "zlib" "zlib-1.2.8.tar.gz" || bail - deco "libpng" "libpng-1.5.13.tar.gz" || bail - deco "pixman" "pixman-0.26.2.tar.gz" || bail - deco "cairo" "cairo-1.12.2.tar.xz" || bail - deco "ncurses" "ncurses-5.9.tar.gz" || bail - deco "vim" "vim-7.3.tar.bz2" || bail - $INFO "tar" "Decompressed source packages." - $INFO "patch" "Patching..." - patc "gcc" "gcc-6.4.0" || bail - #patc "mpc" "mpc-0.9" - #patc "mpfr" "mpfr-3.0.1" - #patc "gmp" "gmp-5.0.1" - patc "binutils" "binutils-2.27" || bail - patc "newlib" "newlib-1.19.0" || bail - patc "freetype" "freetype-2.4.9" || bail - patc "libpng" "libpng-1.5.13" || bail - patc "pixman" "pixman-0.26.2" || bail - patc "cairo" "cairo-1.12.2" || bail - patc "ncurses" "ncurses-5.9" || bail - patc "vim" "vim73" || bail - $INFO "patch" "Patched third-party software." - $INFO "--" "Running additional bits..." - installNewlibStuff "newlib-1.19.0" || bail - popd > /dev/null - - if [ ! -d build ]; then - mkdir build - fi - if [ ! -d local ]; then - mkdir local - fi - -popd > /dev/null diff --git a/toolchain/repatch-newlib.sh b/toolchain/repatch-newlib.sh deleted file mode 100755 index 2d97b64c..00000000 --- a/toolchain/repatch-newlib.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# Toolchain Installer for Debian-like systems. If you're running -# something else, you're pretty much on your own. - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -. $DIR/util.sh - -pushd "$DIR" > /dev/null - - if [ ! -d tarballs ]; then - mkdir tarballs - fi - pushd tarballs > /dev/null - rm -r newlib-1.19.0 - deco "newlib" "newlib-1.19.0.tar.gz" || bail - patc "newlib" "newlib-1.19.0" || bail - installNewlibStuff "newlib-1.19.0" || bail - popd > /dev/null - - if [ ! -d build ]; then - mkdir build - fi - if [ ! -d local ]; then - mkdir local - fi - -popd > /dev/null diff --git a/toolchain/toolchain-build.sh b/toolchain/toolchain-build.sh deleted file mode 100755 index 18597b6e..00000000 --- a/toolchain/toolchain-build.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/bash - -INSTALL_PACKAGES=true - -cd "$( dirname "${BASH_SOURCE[0]}" )" - -while test $# -gt 0; do - case "$1" in - -q|--quick) - INSTALL_PACKAGES=false - break - ;; - *) - break - ;; - esac -done - -unset CC - -if [[ "$INSTALL_PACKAGES" == "true" ]] ; then - - echo "I am going to install some system packages. I will probably need you to provide a password." - echo "If you don't want to do this and you're sure you have all of the required system packages, then interrupt the password prompt and run this script again with -q." - - if [ -f /etc/debian_version ]; then - sudo apt-get install yasm genext2fs build-essential wget libmpfr-dev libmpc-dev libgmp3-dev qemu autoconf automake texinfo pkg-config git ctags gperf - elif [ -f /etc/fedora-release ]; then - sudo dnf groupinstall 'Development Tools' - sudo dnf groupinstall 'Development Libraries' - sudo dnf install yasm mpfr-devel libmpc-devel gmp-devel gperf - echo "Warning: Fedora is unsupported in this script. Be careful!" - echo "For best results, follow the steps in the script manually." - echo "(Script will continue in 5 seconds)" - sleep 5 - else - echo "You are on an entirely unsupported system, please ensure you have the following packages:" - echo " - essential development packages for your platform (C headers, etc.)" - echo " - development headers for mpfr, libmpc, and gmp" - echo " - gcc" - echo " - YASM" - echo " - genext2fs" - echo " - autoconf/automake" - echo " - wget" - echo " - qemu" - echo " - texinfo" - echo " - pkg-config" - echo " - git" - echo " - ctags" - echo "(If you are on Arch, install: gcc yasm genext2fs base-devel wget mpfr libmpc gmp qemu autoconf automake texinfo pkg-config git ctags)" - echo "" - echo "... then run this script (toolchain/toolchain-build.sh) again with the -q flag." - exit 1 - fi -fi - -# Really quick, let's check our genext2fs before we start -if [ -z "$(genext2fs --help 2>&1 | grep -- "block-size")" ]; then - echo -e "\033[1;31mHold up!\033[0m" - echo "Your genext2fs does not support the -B (--block-size) argument." - echo "You can build a copy from the CVS HEAD which supports this:" - echo - echo " http://genext2fs.sourceforge.net/" - echo - exit 1 -fi - -# Build the toolchain: -unset PKG_CONFIG_LIBDIR -./prepare.sh -./install.sh -. activate.sh - -echo "Core toolchain build is complete." -echo "You should now activate the toolchain:" -echo "" -echo " . toolchain/activate.sh" -echo "" -echo "And then use Make to do a first-pass build of the kernel and userspace:" -echo "" -echo " make" -echo "" -echo "Then build Python and the core Python libraries:" -echo "" -echo " toolchain/install-python.sh" -echo " toolchain/install-pycairo.sh" -echo "" -echo "And then rebuild the hard disk:" -echo "" -echo " make clean-disk; make" -echo "" diff --git a/toolchain/util.sh b/toolchain/util.sh deleted file mode 100644 index edc1bd56..00000000 --- a/toolchain/util.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -BEG=$DIR/../util/mk-beg -END=$DIR/../util/mk-end -INFO=$DIR/../util/mk-info - -function grab () { - $BEG "wget" "Pulling $1... [$2/$3]" - if [ ! -f "$3" ]; then - wget -q "$2/$3" - $END "wget" "$1" - else - $END "-" "Already have a $1" - fi -} - -function deco () { - $BEG "tar" "Un-archiving $1..." - tar -xf $2 - $END "tar" "$1" -} - -function patc () { - $BEG "patch" "Patching $1..." - pushd "$2" > /dev/null - patch -p1 < $DIR/patches/$2.patch > /dev/null - popd > /dev/null - $END "patch" "$1" -} - -function installNewlibStuff () { - cp -r ../patches/newlib/toaru $1/newlib/libc/sys/toaru - cp -r ../patches/newlib/include/* $1/newlib/libc/sys/toaru/ - cp -r ../patches/newlib/setjmp.S $1/newlib/libc/machine/i386/setjmp.S - cp -r ../patches/newlib/wcwidth.c $1/newlib/libc/string/wcwidth.c - cp -r ../patches/newlib/wcswidth.c $1/newlib/libc/string/wcswidth.c -} - -function bail () { - echo -e "\033[1;31mBuild failed. Please check the logs above to see what went wrong.\033[0m" - exit 1 -} - diff --git a/userspace/core/clear.c b/userspace/core/clear.c deleted file mode 100644 index 7531be6a..00000000 --- a/userspace/core/clear.c +++ /dev/null @@ -1,19 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * clear - * - * Clears the terminal. - * This is a very dumb version and probably only works - * within the toaruOS terminal, but it might also work - * with an xterm or similar. - */ -#include - -int main(int argc, char ** argv) { - printf("\033[H\033[2J"); - fflush(stdout); - return 0; -} diff --git a/userspace/core/cpudet.c b/userspace/core/cpudet.c deleted file mode 100644 index 3de20613..00000000 --- a/userspace/core/cpudet.c +++ /dev/null @@ -1,378 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * Copyright (c) 2006-2007 - http://brynet.biz.tm - - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - */ - -/* You need to include a file with fairly(ish) compliant printf prototype, Decimal and String support like %s and %d and this is truely all you need! */ -#include /* for printf(); */ - -#define asm __asm__ - -/* Required Declarations */ -int do_intel(void); -int do_amd(void); -void printregs(int eax, int ebx, int ecx, int edx); - -#if defined(__PIC__) -#define cpuid(in, a, b, c, d) asm("xchg{l} {%%}ebx, %k1 \n cpuid \n xchg{l} {%%}ebx, %k1" \ - : "=a" (a), "=&r" (b), "=c" (c), "=d" (d) : "0" (in)) -#else -#define cpuid(in, a, b, c, d) asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in)); -#endif - - -/* Simply call this function detect_cpu(); */ -int main(void) { /* or main() if your trying to port this as an independant application */ - unsigned long ebx, unused; - cpuid(0, unused, ebx, unused, unused); - switch(ebx) { - case 0x756e6547: /* Intel Magic Code */ - do_intel(); - break; - case 0x68747541: /* AMD Magic Code */ - do_amd(); - break; - default: - printf("Unknown x86 CPU Detected\n"); - break; - } - return 0; -} - -/* Intel Specific brand list */ -char *Intel[] = { - "Brand ID Not Supported.", - "Intel(R) Celeron(R) processor", - "Intel(R) Pentium(R) III processor", - "Intel(R) Pentium(R) III Xeon(R) processor", - "Intel(R) Pentium(R) III processor", - "Reserved", - "Mobile Intel(R) Pentium(R) III processor-M", - "Mobile Intel(R) Celeron(R) processor", - "Intel(R) Pentium(R) 4 processor", - "Intel(R) Pentium(R) 4 processor", - "Intel(R) Celeron(R) processor", - "Intel(R) Xeon(R) Processor", - "Intel(R) Xeon(R) processor MP", - "Reserved", - "Mobile Intel(R) Pentium(R) 4 processor-M", - "Mobile Intel(R) Pentium(R) Celeron(R) processor", - "Reserved", - "Mobile Genuine Intel(R) processor", - "Intel(R) Celeron(R) M processor", - "Mobile Intel(R) Celeron(R) processor", - "Intel(R) Celeron(R) processor", - "Mobile Geniune Intel(R) processor", - "Intel(R) Pentium(R) M processor", - "Mobile Intel(R) Celeron(R) processor" -}; - -/* This table is for those brand strings that have two values depending on the processor signature. It should have the same number of entries as the above table. */ -char *Intel_Other[] = { - "Reserved", - "Reserved", - "Reserved", - "Intel(R) Celeron(R) processor", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Intel(R) Xeon(R) processor MP", - "Reserved", - "Reserved", - "Intel(R) Xeon(R) processor", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved" -}; - -/* Intel-specific information */ -int do_intel(void) { - printf("Intel Specific Features:\n"); - unsigned long eax, ebx, ecx, edx, max_eax, signature, unused; - int model, family, type, brand, stepping, reserved; - int extended_family = -1; - cpuid(1, eax, ebx, unused, unused); - model = (eax >> 4) & 0xf; - family = (eax >> 8) & 0xf; - type = (eax >> 12) & 0x3; - brand = ebx & 0xff; - stepping = eax & 0xf; - reserved = eax >> 14; - signature = eax; - printf("Type %d - ", type); - switch(type) { - case 0: - printf("Original OEM"); - break; - case 1: - printf("Overdrive"); - break; - case 2: - printf("Dual-capable"); - break; - case 3: - printf("Reserved"); - break; - } - printf("\n"); - printf("Family %d - ", family); - switch(family) { - case 3: - printf("i386"); - break; - case 4: - printf("i486"); - break; - case 5: - printf("Pentium"); - break; - case 6: - printf("Pentium Pro"); - break; - case 15: - printf("Pentium 4"); - } - printf("\n"); - if(family == 15) { - extended_family = (eax >> 20) & 0xff; - printf("Extended family %d\n", extended_family); - } - printf("Model %d - ", model); - switch(family) { - case 3: - break; - case 4: - switch(model) { - case 0: - case 1: - printf("DX"); - break; - case 2: - printf("SX"); - break; - case 3: - printf("487/DX2"); - break; - case 4: - printf("SL"); - break; - case 5: - printf("SX2"); - break; - case 7: - printf("Write-back enhanced DX2"); - break; - case 8: - printf("DX4"); - break; - } - break; - case 5: - switch(model) { - case 1: - printf("60/66"); - break; - case 2: - printf("75-200"); - break; - case 3: - printf("for 486 system"); - break; - case 4: - printf("MMX"); - break; - } - break; - case 6: - switch(model) { - case 1: - printf("Pentium Pro"); - break; - case 3: - printf("Pentium II Model 3"); - break; - case 5: - printf("Pentium II Model 5/Xeon/Celeron"); - break; - case 6: - printf("Celeron"); - break; - case 7: - printf("Pentium III/Pentium III Xeon - external L2 cache"); - break; - case 8: - printf("Pentium III/Pentium III Xeon - internal L2 cache"); - break; - } - break; - case 15: - break; - } - printf("\n"); - cpuid(0x80000000, max_eax, unused, unused, unused); - /* Quok said: If the max extended eax value is high enough to support the processor brand string - (values 0x80000002 to 0x80000004), then we'll use that information to return the brand information. - Otherwise, we'll refer back to the brand tables above for backwards compatibility with older processors. - According to the Sept. 2006 Intel Arch Software Developer's Guide, if extended eax values are supported, - then all 3 values for the processor brand string are supported, but we'll test just to make sure and be safe. */ - if(max_eax >= 0x80000004) { - printf("Brand: "); - if(max_eax >= 0x80000002) { - cpuid(0x80000002, eax, ebx, ecx, edx); - printregs(eax, ebx, ecx, edx); - } - if(max_eax >= 0x80000003) { - cpuid(0x80000003, eax, ebx, ecx, edx); - printregs(eax, ebx, ecx, edx); - } - if(max_eax >= 0x80000004) { - cpuid(0x80000004, eax, ebx, ecx, edx); - printregs(eax, ebx, ecx, edx); - } - printf("\n"); - } else if(brand > 0) { - printf("Brand %d - ", brand); - if(brand < 0x18) { - if(signature == 0x000006B1 || signature == 0x00000F13) { - printf("%s\n", Intel_Other[brand]); - } else { - printf("%s\n", Intel[brand]); - } - } else { - printf("Reserved\n"); - } - } - printf("Stepping: %d Reserved: %d\n", stepping, reserved); - return 0; -} - -/* Print Registers */ -void printregs(int eax, int ebx, int ecx, int edx) { - int j; - char string[17]; - string[16] = '\0'; - for(j = 0; j < 4; j++) { - string[j] = eax >> (8 * j); - string[j + 4] = ebx >> (8 * j); - string[j + 8] = ecx >> (8 * j); - string[j + 12] = edx >> (8 * j); - } - printf("%s", string); -} - -/* AMD-specific information */ -int do_amd(void) { - printf("AMD Specific Features:\n"); - unsigned long extended, eax, ebx, ecx, edx, unused; - int family, model, stepping, reserved; - cpuid(1, eax, unused, unused, unused); - model = (eax >> 4) & 0xf; - family = (eax >> 8) & 0xf; - stepping = eax & 0xf; - reserved = eax >> 12; - printf("Family: %d Model: %d [", family, model); - switch(family) { - case 4: - printf("486 Model %d", model); - break; - case 5: - switch(model) { - case 0: - case 1: - case 2: - case 3: - case 6: - case 7: - printf("K6 Model %d", model); - break; - case 8: - printf("K6-2 Model 8"); - break; - case 9: - printf("K6-III Model 9"); - break; - default: - printf("K5/K6 Model %d", model); - break; - } - break; - case 6: - switch(model) { - case 1: - case 2: - case 4: - printf("Athlon Model %d", model); - break; - case 3: - printf("Duron Model 3"); - break; - case 6: - printf("Athlon MP/Mobile Athlon Model 6"); - break; - case 7: - printf("Mobile Duron Model 7"); - break; - default: - printf("Duron/Athlon Model %d", model); - break; - } - break; - } - printf("]\n"); - cpuid(0x80000000, extended, unused, unused, unused); - if(extended == 0) { - return 0; - } - if(extended >= 0x80000002) { - unsigned int j; - printf("Detected Processor Name: "); - for(j = 0x80000002; j <= 0x80000004; j++) { - cpuid(j, eax, ebx, ecx, edx); - printregs(eax, ebx, ecx, edx); - } - printf("\n"); - } - if(extended >= 0x80000007) { - cpuid(0x80000007, unused, unused, unused, edx); - if(edx & 1) { - printf("Temperature Sensing Diode Detected!\n"); - } - } - printf("Stepping: %d Reserved: %d\n", stepping, reserved); - return 0; -} diff --git a/userspace/core/echo.c b/userspace/core/echo.c deleted file mode 100644 index e837634e..00000000 --- a/userspace/core/echo.c +++ /dev/null @@ -1,73 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * echo - * - * Prints its arguments (with some processing, ask --help) - * to standard out. - */ -#include -#include - -void usage() { - printf("echo [-n] [-e] [STRING]...\n" - " -n do not output a new line at the end\n" - " -e process escape sequences\n"); -} - -int main(int argc, char ** argv) { - int start = 1; - int use_newline = 1; - int process_escapes = 0; - - for (int i = start; i < argc; ++i) { - if (argv[i][0] != '-') { - start = i; - break; - } else { - if (argv[i][1] == 'h') { - usage(); - return 1; - } else if (argv[i][1] == 'n') { - use_newline = 0; - } else if (argv[i][1] == 'e') { - process_escapes = 1; - } - } - } - - for (int i = start; i < argc; ++i) { - if (process_escapes) { - for (int j = 0; j < strlen(argv[i]) - 1; ++j) { - if (argv[i][j] == '\\') { - if (argv[i][j+1] == 'e') { - argv[i][j] = '\033'; - for (int k = j + 1; k < strlen(argv[i]); ++k) { - argv[i][k] = argv[i][k+1]; - } - } - if (argv[i][j+1] == 'n') { - argv[i][j] = '\n'; - for (int k = j + 1; k < strlen(argv[i]); ++k) { - argv[i][k] = argv[i][k+1]; - } - } - } - } - } - printf("%s",argv[i]); - if (i != argc - 1) { - printf(" "); - } - } - - if (use_newline) { - printf("\n"); - } - - fflush(stdout); - return 0; -} diff --git a/userspace/core/env.c b/userspace/core/env.c deleted file mode 100644 index 40af0e39..00000000 --- a/userspace/core/env.c +++ /dev/null @@ -1,22 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include - -int main(int argc, char ** argv) { - unsigned int x = 0; - unsigned int nulls = 0; - for (x = 0; 1; ++x) { - if (!argv[x]) { - ++nulls; - if (nulls == 2) { - break; - } - continue; - } - if (nulls == 1) { - printf("%s\n", argv[x]); - } - } -} diff --git a/userspace/core/fgrep.c b/userspace/core/fgrep.c deleted file mode 100644 index 415753d2..00000000 --- a/userspace/core/fgrep.c +++ /dev/null @@ -1,42 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -/* - * Dump grep - */ -#include -#include -#include -#include - -#define LINE_SIZE 4096 - -int main(int argc, char ** argv) { - if (argc < 2) { - fprintf(stderr, "usage: %s thing-to-grep-for\n", argv[0]); - return 1; - } - - char * needle = argv[1]; - char buf[LINE_SIZE]; - int ret = 1; - - while (fgets(buf, LINE_SIZE, stdin)) { - char * found = strstr(buf, needle); - if (found) { - *found = '\0'; - found += strlen(needle); - fprintf(stdout, "%s\033[1;31m%s\033[0m%s", buf, needle, found); - ret = 0; - } - } - - return ret; -} - -/* - * vim:tabstop=4 - * vim:noexpandtab - * vim:shiftwidth=4 - */ diff --git a/userspace/core/hello.c b/userspace/core/hello.c deleted file mode 100644 index de3a1d0a..00000000 --- a/userspace/core/hello.c +++ /dev/null @@ -1,14 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* vim:tabstop=4 shiftwidth=4 noexpandtab - * - * prints "Hello World!" to standard out. - */ -#include - -int main(int argc, char ** argv) { - printf("Hello World!\n"); - return 0; -} diff --git a/userspace/core/init.c b/userspace/core/init.c deleted file mode 100644 index fd902176..00000000 --- a/userspace/core/init.c +++ /dev/null @@ -1,88 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * init - * - * Provides the standard boot routines and - * calls the user session (compositor / terminal) - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_HOSTNAME "toaru-test" - -void set_console() { - int _stdin = open("/dev/null", O_RDONLY); - int _stdout = open("/dev/ttyS0", O_WRONLY); - int _stderr = open("/dev/ttyS0", O_WRONLY); - - if (_stdout < 0) { - _stdout = open("/dev/null", O_WRONLY); - _stderr = open("/dev/null", O_WRONLY); - } -} - -/* Set the hostname to whatever is in /etc/hostname */ -void set_hostname() { - FILE * _host_file = fopen("/etc/hostname", "r"); - if (!_host_file) { - /* No /etc/hostname, use the default */ - syscall_sethostname(DEFAULT_HOSTNAME); - } else { - char buf[256]; - fgets(buf, 255, _host_file); - if (buf[strlen(buf)-1] == '\n') { - buf[strlen(buf)-1] = '\0'; - } - syscall_sethostname(buf); - setenv("HOST", buf, 1); - fclose(_host_file); - } -} - -int start_options(char * args[]) { - int pid = fork(); - if (!pid) { - int i = execvp(args[0], args); - exit(0); - } else { - int pid = 0; - do { - pid = wait(NULL); - } while ((pid > 0) || (pid == -1 && errno == EINTR)); - } -} - -int main(int argc, char * argv[]) { - /* stdin/out/err */ - set_console(); - /* Hostname */ - set_hostname(); - if (argc > 1) { - char * args = NULL; - if (argc > 2) { - args = argv[2]; - } - if (!strcmp(argv[1],"--single")) { - return start_options((char *[]){"/bin/compositor","--","/bin/terminal","-Fl",args,NULL}); - } else if (!strcmp(argv[1], "--vga")) { - return start_options((char *[]){"/bin/terminal-vga","-l",NULL}); - } else if (!strcmp(argv[1], "--migrate")) { - return start_options((char *[]){"/usr/bin/python","/bin/migrate.py",NULL}); - } else { - /* Pass it to the compositor... */ - return start_options((char *[]){"/bin/compositor","--",argv[1],NULL}); - } - } - return start_options((char *[]){"/bin/compositor",NULL}); -} diff --git a/userspace/core/mkdir.c b/userspace/core/mkdir.c deleted file mode 100644 index b7adade7..00000000 --- a/userspace/core/mkdir.c +++ /dev/null @@ -1,26 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* vim:tabstop=4 shiftwidth=4 noexpandtab - * - * mkdir - * - * Create a directory. - */ -#include -#include - -#include -#include - -int main(int argc, char ** argv) { - if (argc < 2) { - fprintf(stderr, "%s: expected argument\n", argv[0]); - return 1; - } - - mkdir(argv[1], 0x00); - - return 0; -} diff --git a/userspace/core/ps.c b/userspace/core/ps.c deleted file mode 100644 index 367b31e5..00000000 --- a/userspace/core/ps.c +++ /dev/null @@ -1,160 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - * - * ps - * - * print a list of running processes - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lib/list.h" - -#define LINE_LEN 4096 - -static int show_all = 0; - -void print_username(int uid) { - struct passwd * p = getpwuid(uid); - - if (p) { - printf("%-8s", p->pw_name); - } else { - printf("%-8d", uid); - } - - endpwent(); -} - -void print_entry(struct dirent * dent) { - char tmp[256], buf[4096]; - FILE * f; - int read = 1; - char line[LINE_LEN]; - - int pid, uid, tgid; - char name[100]; - - snprintf(tmp, 256, "/proc/%s/status", dent->d_name); - f = fopen(tmp, "r"); - - while (fgets(line, LINE_LEN, f) != NULL) { - if (strstr(line, "Pid:") == line) { - sscanf(line, "%s %d", &buf, &pid); - } else if (strstr(line, "Uid:") == line) { - sscanf(line, "%s %d", &buf, &uid); - } else if (strstr(line, "Tgid:") == line) { - sscanf(line, "%s %d", &buf, &tgid); - } else if (strstr(line, "Name:") == line) { - sscanf(line, "%s %s", &buf, &name); - } - } - - fclose(f); - - if ((tgid != pid) && !show_all) { - /* Skip threads */ - return; - } - - print_username(uid); - if (show_all) { - printf("%5d.%-5d", tgid, pid); - } else { - printf(" %5d", pid); - } - - printf(" "); - - snprintf(tmp, 256, "/proc/%s/cmdline", dent->d_name); - f = fopen(tmp, "r"); - memset(buf, 0x00, 4096); - read = fread(buf, 1, 4096, f); - fclose(f); - - buf[read] = '\0'; - for (int i = 0; i < read; ++i) { - if (buf[i] == '\036') { - buf[i] = ' '; - } - } - - if (tgid != pid) { - printf("{%s}\n", buf); - } else { - printf("%s\n", buf); - } -} - -void show_usage(int argc, char * argv[]) { - printf( - "ps - list running processes\n" - "\n" - "usage: %s [-A] [format]\n" - "\n" - " -A \033[3mignored\033[0m\n" - " -? \033[3mshow this help text\033[0m\n" - "\n", argv[0]); -} - -int main (int argc, char * argv[]) { - - /* Parse arguments */ - - if (argc > 1) { - int index, c; - while ((c = getopt(argc, argv, "A?")) != -1) { - switch (c) { - case 'A': - show_all = 1; - break; - case '?': - show_usage(argc, argv); - return 0; - } - } - } - - /* Open the directory */ - DIR * dirp = opendir("/proc"); - - /* Read the entries in the directory */ - list_t * ents_list = list_create(); - - struct dirent * ent = readdir(dirp); - while (ent != NULL) { - if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') { - struct dirent * entcpy = malloc(sizeof(struct dirent)); - memcpy(entcpy, ent, sizeof(struct dirent)); - list_insert(ents_list, (void *)entcpy); - } - - ent = readdir(dirp); - } - closedir(dirp); - - foreach(entry, ents_list) { - print_entry(entry->value); - } - - - return 0; -} - -/* - * vim: tabstop=4 - * vim: shiftwidth=4 - * vim: noexpandtab - */ diff --git a/userspace/core/rm.c b/userspace/core/rm.c deleted file mode 100644 index cb214812..00000000 --- a/userspace/core/rm.c +++ /dev/null @@ -1,24 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * rm - * - * unlink a file - * (in theory) - */ -#include -#include -#include - -int main(int argc, char * argv[]) { - if (argc < 2) { - fprintf(stderr, "%s: argument expected\n", argv[0]); - return 1; - } - - unlink(argv[1]); - - return 0; -} diff --git a/userspace/core/sh.c b/userspace/core/sh.c deleted file mode 100644 index 61d87255..00000000 --- a/userspace/core/sh.c +++ /dev/null @@ -1,993 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - * - * E-Shell - * - * This is the "experimental shell". It provides - * a somewhat unix-like shell environment, but does - * not include a parser any advanced functionality. - * It simply cuts its input into arguments and executes - * programs. - */ - -#define _XOPEN_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lib/list.h" -#include "lib/kbd.h" -#include "lib/rline.h" - -#define PIPE_TOKEN "\xFF\xFFPIPE\xFF\xFF" -#define STAR_TOKEN "\xFF\xFFSTAR\xFF\xFF" - -/* A shell command is like a C program */ -typedef uint32_t(*shell_command_t) (int argc, char ** argv); - -/* We have a static array that fits a certain number of them. */ -#define SHELL_COMMANDS 512 -char * shell_commands[SHELL_COMMANDS]; /* Command names */ -shell_command_t shell_pointers[SHELL_COMMANDS]; /* Command functions */ -char * shell_descript[SHELL_COMMANDS]; /* Command descriptions */ - -/* This is the number of actual commands installed */ -uint32_t shell_commands_len = 0; - -int shell_interactive = 1; - -int pid; /* Process ID of the shell */ - -void shell_install_command(char * name, shell_command_t func, char * desc) { - if (shell_commands_len == SHELL_COMMANDS) { - fprintf(stderr, "Ran out of space for static shell commands. The maximum number of commands is %d\n", SHELL_COMMANDS); - return; - } - shell_commands[shell_commands_len] = name; - shell_pointers[shell_commands_len] = func; - shell_descript[shell_commands_len] = desc; - shell_commands_len++; -} - -shell_command_t shell_find(char * str) { - for (uint32_t i = 0; i < shell_commands_len; ++i) { - if (!strcmp(str, shell_commands[i])) { - return shell_pointers[i]; - } - } - return NULL; -} - -void install_commands(); - -/* Maximum command length */ -#define LINE_LEN 4096 - -/* Current working directory */ -char cwd[1024] = {'/',0}; - -/* Username */ -char username[1024]; - -/* Hostname for prompt */ -char _hostname[256]; - -/* function to update the cached username */ -void getuser() { - char * tmp = getenv("USER"); - if (tmp) { - strcpy(username, tmp); - } else { - sprintf(username, "%d", getuid()); - } -} - -/* function to update the cached hostname */ -void gethost() { - struct utsname buf; - - uname(&buf); - - int len = strlen(buf.nodename); - memcpy(_hostname, buf.nodename, len+1); -} - -/* Draw the user prompt */ -void draw_prompt(int ret) { - /* Get the time */ - struct tm * timeinfo; - struct timeval now; - gettimeofday(&now, NULL); //time(NULL); - timeinfo = localtime((time_t *)&now.tv_sec); - - /* Format the date and time for prompt display */ - char date_buffer[80]; - strftime(date_buffer, 80, "%m/%d", timeinfo); - char time_buffer[80]; - strftime(time_buffer, 80, "%H:%M:%S", timeinfo); - - /* Print the working directory in there, too */ - getcwd(cwd, 512); - char _cwd[512]; - strncpy(_cwd, cwd, 512); - - char * home = getenv("HOME"); - if (home && strstr(cwd, home) == cwd) { - char * c = cwd + strlen(home); - if (*c == '/' || *c == 0) { - sprintf(_cwd, "~%s", c); - } - } - - /* Print the prompt. */ - printf("\033]1;%s@%s:%s\007", username, _hostname, _cwd); - printf("\033[s\033[400C\033[16D\033[1m\033[38;5;59m[\033[38;5;173m%s \033[38;5;167m%s\033[38;5;59m]\033[u\033[38;5;221m%s\033[38;5;59m@\033[38;5;81m%s ", - date_buffer, time_buffer, - username, _hostname); - if (ret != 0) { - printf("\033[38;5;167m%d ", ret); - } - - printf("\033[0m%s%s\033[0m ", _cwd, getuid() == 0 ? "\033[1;38;5;196m#" : "\033[1;38;5;47m$"); - fflush(stdout); -} - -uint32_t child = 0; - -void sig_pass(int sig) { - /* Interrupt handler */ - if (child) { - kill(child, sig); - } -} - -void redraw_prompt_func(rline_context_t * context) { - draw_prompt(0); -} - -void draw_prompt_c() { - printf("> "); - fflush(stdout); -} -void redraw_prompt_func_c(rline_context_t * context) { - draw_prompt_c(); -} - -void tab_complete_func(rline_context_t * c) { - char * dup = malloc(LINE_LEN); - - memcpy(dup, c->buffer, LINE_LEN); - - char *pch, *cmd, *save; - char *argv[1024]; - int argc = 0; - int cursor = 0; - - pch = strtok_r(dup, " ", &save); - - if (!pch) { - argv[0] = ""; - argc = 0; - } - - while (pch != NULL) { - if (pch - dup <= c->offset) cursor = argc; - argv[argc] = pch; - ++argc; - pch = strtok_r(NULL, " ", &save); - } - argv[argc] = NULL; - - if (c->offset && c->buffer[c->offset-1] == ' ' && argc) { - cursor++; - } - - char * word = argv[cursor]; - int word_offset = word ? (c->offset - (argv[cursor] - dup)) : 0; - - char * prefix = malloc(word_offset + 1); - if (word) memcpy(prefix, word, word_offset); - prefix[word_offset] = '\0'; - - /* Complete file path */ - list_t * matches = list_create(); - char * match = NULL; - int free_matches = 0; - int no_space_if_only = 0; - if (cursor == 0 && !strchr(prefix,'/')) { - /* Complete binary name */ - for (int i = 0; i < shell_commands_len; ++i) { - if (strstr(shell_commands[i], prefix) == shell_commands[i]) { - list_insert(matches, shell_commands[i]); - match = shell_commands[i]; - } - } - } else { - free_matches = 1; - char * tmp = strdup(prefix); - char * last_slash = strrchr(tmp, '/'); - DIR * dirp; - char * compare = prefix; - if (last_slash) { - *last_slash = '\0'; - word = word + (last_slash - tmp) + 1; - word_offset = word_offset - (last_slash - tmp + 1); - compare = word; - if (last_slash == tmp) { - dirp = opendir("/"); - } else { - dirp = opendir(tmp); - } - } else { - dirp = opendir("."); - } - - if (!dirp) { - free(tmp); - goto finish_tab; - } - - struct dirent * ent = readdir(dirp); - while (ent != NULL) { - if (ent->d_name[0] != '.') { - if (!word || strstr(ent->d_name, compare) == ent->d_name) { - struct stat statbuf; - /* stat it */ - if (last_slash) { - char * x = malloc(strlen(tmp) + 1 + strlen(ent->d_name) + 1); - sprintf(x,"%s/%s",tmp,ent->d_name); - int t = lstat(x, &statbuf); - } else { - int t = lstat(ent->d_name, &statbuf); - } - char * s; - if (S_ISDIR(statbuf.st_mode)) { - s = malloc(strlen(ent->d_name) + 2); - sprintf(s,"%s/", ent->d_name); - no_space_if_only = 1; - } else { - s = strdup(ent->d_name); - } - list_insert(matches, s); - match = s; - } - } - ent = readdir(dirp); - } - closedir(dirp); - - free(tmp); - } - if (matches->length == 1) { - /* Insert */ - rline_insert(c, &match[word_offset]); - if (word && word_offset == strlen(word) && !no_space_if_only) { - rline_insert(c, " "); - } - rline_redraw(c); - } else if (matches->length > 1) { - if (!c->tabbed) { - /* see if there is a minimum subset we can fill in */ - size_t j = word_offset; - do { - char d = match[j]; - int diff = 0; - foreach(node, matches) { - char * match = (char *)node->value; - if (match[j] != d || match[j] == '\0') diff = 1; - } - if (diff) break; - j++; - } while (j < c->requested); - if (j > word_offset) { - char * tmp = strdup(match); - tmp[j] = '\0'; - rline_insert(c, &tmp[word_offset]); - rline_redraw(c); - free(tmp); - } else { - c->tabbed = 1; - } - } else { - /* Print matches */ - fprintf(stderr,"\n"); - size_t j = 0; - foreach(node, matches) { - char * match = (char *)node->value; - fprintf(stderr, "%s", match); - ++j; - if (j < matches->length) { - fprintf(stderr, ", "); - } - } - fprintf(stderr,"\n"); - c->callbacks->redraw_prompt(c); - fprintf(stderr, "\033[s"); - rline_redraw(c); - } - } - -finish_tab: - if (free_matches) list_destroy(matches); - list_free(matches); - free(prefix); - free(dup); - -} - -void add_argument(list_t * argv, char * buf) { - char * c = malloc(strlen(buf) + 1); - memcpy(c, buf, strlen(buf) + 1); - - list_insert(argv, c); -} - -int read_entry(char * buffer) { - rline_callbacks_t callbacks = { - tab_complete_func, redraw_prompt_func, NULL, - NULL, NULL, NULL, NULL, NULL - }; - int buffer_size = rline((char *)buffer, LINE_LEN, &callbacks); - return buffer_size; -} - -int read_entry_continued(char * buffer) { - rline_callbacks_t callbacks = { - tab_complete_func, redraw_prompt_func_c, NULL, - NULL, NULL, NULL, NULL, NULL - }; - int buffer_size = rline((char *)buffer, LINE_LEN, &callbacks); - return buffer_size; -} - -int variable_char(uint8_t c) { - if (c >= 65 && c <= 90) return 1; - if (c >= 97 && c <= 122) return 1; - if (c >= 48 && c <= 57) return 1; - if (c == 95) return 1; - return 0; -} - -void run_cmd(char ** args) { - int i = execvp(*args, args); - shell_command_t func = shell_find(*args); - if (func) { - int argc = 0; - while (args[argc]) { - argc++; - } - i = func(argc, args); - } else { - if (i != 0) { - fprintf(stderr, "%s: Command not found\n", *args); - i = 127; - } - } - exit(i); -} - -int shell_exec(char * buffer, int buffer_size) { - - /* Read previous history entries */ - if (buffer[0] == '!') { - int x = atoi((char *)((uintptr_t)buffer + 1)); - if (x > 0 && x <= rline_history_count) { - buffer = rline_history_get(x - 1); - buffer_size = strlen(buffer); - } else { - fprintf(stderr, "esh: !%d: event not found\n", x); - return 0; - } - } - - char * history = malloc(strlen(buffer) + 1); - memcpy(history, buffer, strlen(buffer) + 1); - - if (buffer[0] != ' ' && buffer[0] != '\n') { - rline_history_insert(history); - } else { - free(history); - } - - char * argv[1024]; - int tokenid = 0; - - char quoted = 0; - char backtick = 0; - char buffer_[512] = {0}; - int collected = 0; - - list_t * args = list_create(); - int have_star = 0; - - while (1) { - - char * p = buffer; - - while (*p) { - switch (*p) { - case '$': - if (quoted == '\'') { - goto _just_add; - } else { - if (backtick) { - goto _just_add; - } - p++; - char var[100]; - int coll = 0; - if (*p == '{') { - p++; - while (*p != '}' && *p != '\0' && (coll < 100)) { - var[coll] = *p; - coll++; - var[coll] = '\0'; - p++; - } - if (*p == '}') { - p++; - } - } else { - while (*p != '\0' && variable_char(*p) && (coll < 100)) { - var[coll] = *p; - coll++; - var[coll] = '\0'; - p++; - } - } - char *c = getenv(var); - if (c) { - backtick = 0; - for (int i = 0; i < strlen(c); ++i) { - buffer_[collected] = c[i]; - collected++; - } - buffer_[collected] = '\0'; - } - continue; - } - case '\"': - if (quoted == '\"') { - if (backtick) { - goto _just_add; - } - quoted = 0; - goto _next; - } else if (!quoted) { - quoted = *p; - goto _next; - } - goto _just_add; - case '\'': - if (quoted == '\'') { - if (backtick) { - goto _just_add; - } - quoted = 0; - goto _next; - } else if (!quoted) { - quoted = *p; - goto _next; - } - goto _just_add; - case '*': - if (quoted) { - goto _just_add; - } - if (backtick) { - goto _just_add; - } - if (have_star) { - goto _just_add; /* TODO multiple globs */ - } - have_star = 1; - collected += sprintf(&buffer_[collected], STAR_TOKEN); - goto _next; - case '\\': - if (quoted == '\'') { - goto _just_add; - } - if (backtick) { - goto _just_add; - } - backtick = 1; - goto _next; - case ' ': - if (backtick) { - goto _just_add; - } - if (!quoted) { - goto _new_arg; - } - goto _just_add; - case '\n': - if (!quoted) { - goto _done; - } - goto _just_add; - case '|': - if (!quoted && !backtick && !collected) { - collected = sprintf(buffer_, "%s", PIPE_TOKEN); - goto _new_arg; - } - default: - if (backtick) { - buffer_[collected] = '\\'; - collected++; - buffer_[collected] = '\0'; - } -_just_add: - backtick = 0; - buffer_[collected] = *p; - collected++; - buffer_[collected] = '\0'; - goto _next; - } - -_new_arg: - backtick = 0; - if (collected) { - add_argument(args, buffer_); - buffer_[0] = '\0'; - have_star = 0; - collected = 0; - } - -_next: - p++; - } - -_done: - - if (quoted) { - if (shell_interactive) { - draw_prompt_c(); - buffer_size = read_entry_continued(buffer); - rline_history_append_line(buffer); - continue; - } else { - fprintf(stderr, "Syntax error: Unterminated quoted string.\n"); - return 127; - } - } - - if (collected) { - add_argument(args, buffer_); - break; - } - - break; - } - - int cmdi = 0; - char ** arg_starts[100] = { &argv[0], NULL }; - int argcs[100] = {0}; - - int i = 0; - foreach(node, args) { - char * c = node->value; - - if (!strcmp(c, PIPE_TOKEN)) { - argv[i] = 0; - i++; - cmdi++; - arg_starts[cmdi] = &argv[i]; - continue; - } - - char * glob = strstr(c, STAR_TOKEN); - if (glob) { - /* Globbing */ - glob[0] = '\0'; - glob[1] = '\0'; - - char * before = c; - char * after = &glob[8]; - - int has_before = !!strlen(before); - int has_after = !!strlen(after); - - if (!has_before || !strchr(before,'/')) { - /* read current directory, add all */ - DIR * dirp = opendir("."); - - int before_i = i; - struct dirent * ent = readdir(dirp); - while (ent != NULL) { - if (ent->d_name[0] != '.') { - char * s = malloc(sizeof(char) * (strlen(ent->d_name) + 1)); - memcpy(s, ent->d_name, strlen(ent->d_name) + 1); - - char * t = s; - - if (has_before) { - if (strstr(s,before) != s) { - goto _nope; - } - t = &s[strlen(before)]; - } - if (has_after) { - if (strlen(t) >= strlen(after)) { - if (!strcmp(after,&t[strlen(t)-strlen(after)])) { - argv[i] = s; - i++; - argcs[cmdi]++; - } - } - } else { - argv[i] = s; - i++; - argcs[cmdi]++; - } - } -_nope: - ent = readdir(dirp); - } - closedir(dirp); - - if (before_i == i) { - /* no matches */ - glob[0] = '*'; - memmove(&glob[1], after, strlen(after)+1); - argv[i] = c; - i++; - argcs[cmdi]++; - } else { - free(c); - } - } else { - /* directory globs not supported */ - glob[0] = '*'; - argv[i] = c; - i++; - argcs[cmdi]++; - } - } else { - argv[i] = c; - i++; - argcs[cmdi]++; - } - } - argv[i] = NULL; - - if (i == 0) { - return 0; - } - - list_free(args); - - char * cmd = *arg_starts[0]; - tokenid = i; - - unsigned int child_pid; - - int nowait = (!strcmp(argv[tokenid-1],"&")); - if (nowait) { - argv[tokenid-1] = NULL; - } - - if (cmdi > 0) { - int last_output[2]; - pipe(last_output); - child_pid = fork(); - if (!child_pid) { - dup2(last_output[1], STDOUT_FILENO); - close(last_output[0]); - run_cmd(arg_starts[0]); - } - - for (int j = 1; j < cmdi; ++j) { - int tmp_out[2]; - pipe(tmp_out); - if (!fork()) { - dup2(tmp_out[1], STDOUT_FILENO); - dup2(last_output[0], STDIN_FILENO); - close(tmp_out[0]); - close(last_output[1]); - run_cmd(arg_starts[j]); - } - close(last_output[0]); - close(last_output[1]); - last_output[0] = tmp_out[0]; - last_output[1] = tmp_out[1]; - } - - if (!fork()) { - dup2(last_output[0], STDIN_FILENO); - close(last_output[1]); - run_cmd(arg_starts[cmdi]); - } - close(last_output[0]); - close(last_output[1]); - - /* Now execute the last piece and wait on all of them */ - } else { - shell_command_t func = shell_find(*arg_starts[0]); - if (func) { - return func(argcs[0], arg_starts[0]); - } else { - child_pid = fork(); - if (!child_pid) { - run_cmd(arg_starts[0]); - } - } - } - - tcsetpgrp(STDIN_FILENO, child_pid); - int ret_code = 0; - if (!nowait) { - child = child_pid; - int pid; - do { - pid = waitpid(-1, &ret_code, 0); - } while (pid != -1 || (pid == -1 && errno != ECHILD)); - child = 0; - } - tcsetpgrp(STDIN_FILENO, getpid()); - free(cmd); - return ret_code; -} - -void add_path_contents(char * path) { - DIR * dirp = opendir(path); - - if (!dirp) return; /* Failed to load directly */ - - struct dirent * ent = readdir(dirp); - while (ent != NULL) { - if (ent->d_name[0] != '.') { - char * s = malloc(sizeof(char) * (strlen(ent->d_name) + 1)); - memcpy(s, ent->d_name, strlen(ent->d_name) + 1); - shell_install_command(s, NULL, NULL); - } - - ent = readdir(dirp); - } - closedir(dirp); - -} - -struct command { - char * string; - void * func; - char * desc; -}; - -static int comp_shell_commands(const void *p1, const void *p2) { - return strcmp(((struct command *)p1)->string, ((struct command *)p2)->string); -} - -void sort_commands() { - struct command commands[SHELL_COMMANDS]; - for (int i = 0; i < shell_commands_len; ++i) { - commands[i].string = shell_commands[i]; - commands[i].func = shell_pointers[i]; - commands[i].desc = shell_descript[i]; - } - qsort(&commands, shell_commands_len, sizeof(struct command), comp_shell_commands); - for (int i = 0; i < shell_commands_len; ++i) { - shell_commands[i] = commands[i].string; - shell_pointers[i] = commands[i].func; - shell_descript[i] = commands[i].desc; - } -} - -void show_version(void) { - printf("esh 0.11.0 - experimental shell\n"); -} - -void show_usage(int argc, char * argv[]) { - printf( - "Esh: The Experimental Shell\n" - "\n" - "usage: %s [-lha] [path]\n" - "\n" - " -c \033[4mcmd\033[0m \033[3mparse and execute cmd\033[0m\n" - //-c cmd \033[... - " -v \033[3mshow version information\033[0m\n" - " -? \033[3mshow this help text\033[0m\n" - "\n", argv[0]); -} - - -int main(int argc, char ** argv) { - - int nowait = 0; - int free_cmd = 0; - int last_ret = 0; - - pid = getpid(); - - signal(SIGINT, sig_pass); - signal(SIGWINCH, sig_pass); - - getuser(); - gethost(); - - install_commands(); - add_path_contents("/bin"); - add_path_contents("/usr/bin"); - sort_commands(); - - if (argc > 1) { - int index, c; - while ((c = getopt(argc, argv, "c:v?")) != -1) { - switch (c) { - case 'c': - shell_interactive = 0; - return shell_exec(optarg, strlen(optarg)); - case 'v': - show_version(); - return 0; - case '?': - show_usage(argc, argv); - return 0; - } - } - } - - shell_interactive = 1; - - while (1) { - draw_prompt(last_ret); - char buffer[LINE_LEN] = {0}; - int buffer_size; - - buffer_size = read_entry(buffer); - last_ret = shell_exec(buffer, buffer_size); - rline_scroll = 0; - - } - -exit: - - return 0; -} - -/* - * cd [path] - */ -uint32_t shell_cmd_cd(int argc, char * argv[]) { - if (argc > 1) { - if (chdir(argv[1])) { - goto cd_error; - } /* else success */ - } else /* argc < 2 */ { - char * home = getenv("HOME"); - if (home) { - if (chdir(home)) { - goto cd_error; - } - } else { - char home_path[512]; - sprintf(home_path, "/home/%s", username); - if (chdir(home_path)) { - goto cd_error; - } - } - } - return 0; -cd_error: - fprintf(stderr, "%s: could not cd '%s': no such file or directory\n", argv[0], argv[1]); - return 1; -} - -/* - * history - */ -uint32_t shell_cmd_history(int argc, char * argv[]) { - for (int i = 0; i < rline_history_count; ++i) { - printf("%d\t%s\n", i + 1, rline_history_get(i)); - } - return 0; -} - -uint32_t shell_cmd_export(int argc, char * argv[]) { - if (argc > 1) { - putenv(argv[1]); - } - return 0; -} - -uint32_t shell_cmd_exit(int argc, char * argv[]) { - if (argc > 1) { - exit(atoi(argv[1])); - } else { - exit(0); - } - return -1; -} - -uint32_t shell_cmd_set(int argc, char * argv[]) { - char * term = getenv("TERM"); - if (!term || strstr(term, "toaru") != term) { - fprintf(stderr, "Unrecognized terminal. These commands are for the とある terminal only.\n"); - return 1; - } - if (argc < 2) { - fprintf(stderr, "%s: expected argument\n", argv[0]); - return 1; - } - - if (!strcmp(argv[1], "alpha")) { - if (argc < 3) { - fprintf(stderr, "%s %s [0 or 1]\n", argv[0], argv[1]); - return 1; - } - int i = atoi(argv[2]); - if (i) { - printf("\033[2001z"); - } else { - printf("\033[2000z"); - } - fflush(stdout); - return 0; - } else if (!strcmp(argv[1], "scale")) { - if (argc < 3) { - fprintf(stderr, "%s %s [floating point size, 1.0 = normal]\n", argv[0], argv[1]); - return 1; - } - printf("\033[1555;%sz", argv[2]); - fflush(stdout); - return 0; - } else if (!strcmp(argv[1], "size")) { - if (argc < 4) { - fprintf(stderr, "%s %s [width] [height]\n", argv[0], argv[1]); - return 1; - } - printf("\033[3000;%s;%sz", argv[2], argv[3]); - fflush(stdout); - return 0; - } else if (!strcmp(argv[1], "--help")) { - fprintf(stderr, "Available arguments:\n" - " alpha - alpha transparency enabled / disabled\n" - " scale - font scaling\n" - " size - terminal width/height in characters\n" - " force-raw - sets terminal to raw mode before commands\n" - " no-force-raw - disables forced raw mode\n" - ); - return 0; - } - - fprintf(stderr, "%s: unrecognized argument\n", argv[0]); - return 1; -} - -uint32_t shell_cmd_help(int argc, char * argv[]) { - show_version(); - - printf("\nThis shell is not POSIX-compliant, please be careful.\n\n"); - - printf("Built-in commands:\n"); - for (uint32_t i = 0; i < shell_commands_len; ++i) { - if (!shell_descript[i]) continue; - printf(" %-20s - %s\n", shell_commands[i], shell_descript[i]); - } - - return 0; -} - -void install_commands() { - shell_install_command("cd", shell_cmd_cd, "change directory"); - shell_install_command("exit", shell_cmd_exit, "exit the shell"); - shell_install_command("export", shell_cmd_export, "set environment variables"); - shell_install_command("help", shell_cmd_help, "display this help text"); - shell_install_command("history", shell_cmd_history, "list command history"); - shell_install_command("set", shell_cmd_set, "enable special terminal options"); -} diff --git a/userspace/core/shutdown.c b/userspace/core/shutdown.c deleted file mode 100644 index 0dfc928b..00000000 --- a/userspace/core/shutdown.c +++ /dev/null @@ -1,13 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include -#include - -int main(int argc, char * argv[]) { - printf("Shutting down...\n"); - /* Nothing to actually do for shutdown, sadly */ - __asm__ __volatile__ ("outw %1, %0" : : "dN" ((uint16_t)0xB004), "a" ((uint16_t)0x2000)); - return 0; -} diff --git a/userspace/core/stat.c b/userspace/core/stat.c deleted file mode 100644 index f2e4451b..00000000 --- a/userspace/core/stat.c +++ /dev/null @@ -1,72 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * stat - * - * Displays information on a file's inode. - */ -#include -#include -#include -#include - -#include - -int main(int argc, char ** argv) { - int dereference = 0; - if (argc < 2) { - fprintf(stderr,"%s: expected argument\n", argv[0]); - return 1; - } - - char * file = argv[1]; - - if (argc > 2) { - if (!strcmp(argv[1],"-L")) { - dereference = 1; - } - file = argv[2]; - } - - struct stat _stat; - if (dereference) { - if (stat(file, &_stat) < 0) return 1; - } else { - if (lstat(file, &_stat) < 0) return 1; - } - - printf("0x%x bytes\n", _stat.st_size); - - if (S_ISDIR(_stat.st_mode)) { - printf("Is a directory.\n"); - } else if (S_ISFIFO(_stat.st_mode)) { - printf("Is a pipe.\n"); - } else if (S_ISLNK(_stat.st_mode)) { - printf("Is a symlink.\n"); - } else if (_stat.st_mode & 0111) { - printf("Is executable.\n"); - } - - struct stat * f = &_stat; - - printf("st_dev 0x%x %d\n", (uint32_t)f->st_dev , sizeof(f->st_dev )); - printf("st_ino 0x%x %d\n", (uint32_t)f->st_ino , sizeof(f->st_ino )); - printf("st_mode 0x%x %d\n", (uint32_t)f->st_mode , sizeof(f->st_mode )); - printf("st_nlink 0x%x %d\n", (uint32_t)f->st_nlink , sizeof(f->st_nlink )); - printf("st_uid 0x%x %d\n", (uint32_t)f->st_uid , sizeof(f->st_uid )); - printf("st_gid 0x%x %d\n", (uint32_t)f->st_gid , sizeof(f->st_gid )); - printf("st_rdev 0x%x %d\n", (uint32_t)f->st_rdev , sizeof(f->st_rdev )); - printf("st_size 0x%x %d\n", (uint32_t)f->st_size , sizeof(f->st_size )); - - printf("0x%x\n", ((uint32_t *)f)[0]); - - return 0; -} - -/* - * vim:tabstop=4 - * vim:noexpandtab - * vim:shiftwidth=4 - */ diff --git a/userspace/core/touch.c b/userspace/core/touch.c deleted file mode 100644 index 658dba64..00000000 --- a/userspace/core/touch.c +++ /dev/null @@ -1,28 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * touch - * - * Creates a file or updates its last-modified date. - * (in theory) - */ -#include -#include - -int main(int argc, char * argv[]) { - if (argc < 2) { - fprintf(stderr, "%s: argument expected\n", argv[0]); - return 1; - } - - FILE * f = fopen(argv[1], "a"); - if (!f) { - perror(argv[0]); - return 1; - } - fclose(f); - - return 0; -} diff --git a/userspace/extra/2048/2048.c b/userspace/extra/2048/2048.c deleted file mode 100644 index 60cec7be..00000000 --- a/userspace/extra/2048/2048.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Console implementation of the game "2048" - * - * Copyright (c) 2014 Maurits van der Schee - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SIZE 4 -uint32_t score=0; - -void getColor(uint16_t value, char *color, size_t length) { - uint8_t original[] = {8,255,1,255,2,255,3,255,4,255,5,255,6,255,7,255,9,0,10,0,11,0,12,0,13,0,14,0,255,0,255,0}; - uint8_t blackwhite[] = {232,255,234,255,236,255,238,255,240,255,242,255,244,255,246,0,248,0,249,0,250,0,251,0,252,0,253,0,254,0,255,0}; - uint8_t bluered[] = {235,255,63,255,57,255,93,255,129,255,165,255,201,255,200,255,199,255,198,255,197,255,196,255,196,255,196,255,196,255,196,255}; - uint8_t *scheme = original; - uint8_t *background = scheme+0; - uint8_t *foreground = scheme+1; - if (value > 0) while (value >>= 1) { - if (background+2=0;t--) { - if (array[t]!=0) { - if (array[t]!=array[x]) { - // merge is not possible, take next position - return t+1; - } - return t; - } else { - // we should not slide further, return this one - if (t==stop) { - return t; - } - } - } - // we did not find a - return x; -} - -bool slideArray(uint16_t array[SIZE]) { - bool success = false; - int8_t x,t,stop=0; - - for (x=0;x0) return false; - if (findPairDown(board)) return false; - rotateBoard(board); - if (findPairDown(board)) ended = false; - rotateBoard(board); - rotateBoard(board); - rotateBoard(board); - return ended; -} - -void addRandom(uint16_t board[SIZE][SIZE]) { - static bool initialized = false; - int8_t x,y; - int16_t r,len=0; - uint16_t n,list[SIZE*SIZE][2]; - - if (!initialized) { - srand(time(NULL)); - initialized = true; - } - - for (x=0;x0) { - r = rand()%len; - x = list[r][0]; - y = list[r][1]; - n = ((rand()%10)/9+1)*2; - board[x][y]=n; - } -} - -void setBufferedInput(bool enable) { - static bool enabled = true; - static struct termios old; - struct termios new; - - if (enable && !enabled) { - // restore the former settings - tcsetattr(STDIN_FILENO,TCSANOW,&old); - // set the new state - enabled = true; - } else if (!enable && enabled) { - // get the terminal settings for standard input - tcgetattr(STDIN_FILENO,&new); - // we want to keep the old setting to restore them at the end - old = new; - // disable canonical mode (buffered i/o) and local echo - new.c_lflag &=(~ICANON & ~ECHO); - // set the new settings immediately - tcsetattr(STDIN_FILENO,TCSANOW,&new); - // set the new state - enabled = false; - } -} - -int test() { - uint16_t array[SIZE]; - uint16_t data[] = { - 0,0,0,2, 2,0,0,0, - 0,0,2,2, 4,0,0,0, - 0,2,0,2, 4,0,0,0, - 2,0,0,2, 4,0,0,0, - 2,0,2,0, 4,0,0,0, - 2,2,2,0, 4,2,0,0, - 2,0,2,2, 4,2,0,0, - 2,2,0,2, 4,2,0,0, - 2,2,2,2, 4,4,0,0, - 4,4,2,2, 8,4,0,0, - 2,2,4,4, 4,8,0,0, - 8,0,2,2, 8,4,0,0, - 4,0,2,2, 4,4,0,0 - }; - uint16_t *in,*out; - uint16_t t,tests; - uint8_t i; - bool success = true; - - tests = (sizeof(data)/sizeof(data[0]))/(2*SIZE); - for (t=0;t "); - for (i=0;i "); - for (i=0;i -#include -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include -#define BACKSPACE_KEY 0x7F -#else -#include -#define BACKSPACE_KEY 0x08 -#endif - -#include - -#include "lib/utf8decode.h" - -#define BLOCK_SIZE 256 -#define ENTER_KEY '\n' - -typedef struct { - uint8_t display_width; - uint16_t codepoint; -} __attribute__((packed)) char_t; - -typedef struct { - uint32_t available; - uint32_t actual; - char_t text[0]; -} line_t; - -int term_width, term_height; -int csr_x_actual, csr_y_actual; - -typedef struct _env { - int bottom_size; - short lineno_width; - char * file_name; - int offset; - int coffset; - int line_no; - int line_count; - int line_avail; - int col_no; - short modified; - line_t ** lines; -} buffer_t; - -buffer_t * env; - -uint32_t buffers_len; -uint32_t buffers_avail; -buffer_t ** buffers; - -buffer_t * buffer_new() { - if (buffers_len == buffers_avail) { - buffers_avail *= 2; - buffers = realloc(buffers, sizeof(buffer_t *) * buffers_avail); - } - buffers[buffers_len] = malloc(sizeof(buffer_t)); - memset(buffers[buffers_len], 0x00, sizeof(buffer_t)); - buffers_len++; - - return buffers[buffers_len-1]; -} - -buffer_t * buffer_close(buffer_t * buf) { - uint32_t i; - for (i = 0; i < buffers_len; i++) { - if (buf == buffers[i]) - break; - } - if (i == buffers_len) { - return env; /* wtf */ - } - - if (i != buffers_len - 1) { - memmove(&buffers[i], &buffers[i+1], buffers_len - i); - } - - buffers_len--; - if (!buffers_len) { - return NULL; - } - if (i == buffers_len) { - return buffers[buffers_len-1]; - } - return buffers[buffers_len]; -} - -line_t * line_insert(line_t * line, char_t c, uint32_t offset) { - if (line->actual == line->available) { - line->available *= 2; - line = realloc(line, sizeof(line_t) + sizeof(char_t) * line->available); - } - if (offset < line->actual) { - memmove(&line->text[offset+1], &line->text[offset], sizeof(char_t) * (line->actual - offset)); - } - line->text[offset] = c; - line->actual += 1; - return line; -} - -void line_delete(line_t * line, uint32_t offset) { - if (offset == 0) return; - if (offset < line->actual) { - memmove(&line->text[offset-1], &line->text[offset], sizeof(char_t) * (line->actual - offset - 1)); - } - line->actual -= 1; -} - -line_t ** add_line(line_t ** lines, uint32_t offset) { - if (env->line_count == env->line_avail) { - env->line_avail *= 2; - lines = realloc(lines, sizeof(line_t *) * env->line_avail); - } - if (offset < env->line_count) { - memmove(&lines[offset+1], &lines[offset], sizeof(line_t *) * (env->line_count - offset)); - } - lines[offset] = malloc(sizeof(line_t) + sizeof(char_t) * 32); - lines[offset]->available = 32; - lines[offset]->actual = 0; - env->line_count += 1; - return lines; -} - -line_t ** split_line(line_t ** lines, uint32_t line, uint32_t split) { - if (split == 0) { - return add_line(lines, line - 1); - } - if (env->line_count == env->line_avail) { - env->line_avail *= 2; - lines = realloc(lines, sizeof(line_t *) * env->line_avail); - } - if (line < env->line_count) { - memmove(&lines[line+1], &lines[line], sizeof(line_t *) * (env->line_count - line)); - } - uint32_t remaining = lines[line-1]->actual - split; - - uint32_t v = remaining; - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - - lines[line] = malloc(sizeof(line_t) + sizeof(char_t) * v); - lines[line]->available = v; - lines[line]->actual = remaining; - - memmove(lines[line]->text, &lines[line-1]->text[split], sizeof(char_t) * remaining); - lines[line-1]->actual = split; - - env->line_count += 1; - - return lines; -} - -void setup_buffer(buffer_t * env) { - if (env->lines) { - for (int i = 0; i < env->line_count; ++i) { - free(env->lines[i]); - } - free(env->lines); - } - env->line_no = 1; - env->col_no = 1; - env->line_count = 1; /* XXX */ - env->modified = 0; - env->bottom_size = 2; - env->offset = 0; - env->line_avail = 8; - - env->lines = malloc(sizeof(line_t *) * env->line_avail); - env->lines[0] = malloc(sizeof(line_t) + sizeof(char_t) * 32); - env->lines[0]->available = 32; - env->lines[0]->actual = 0; - -} - -#define COLOR_FG 230 -#define COLOR_BG 235 -#define COLOR_CURSOR 15 -#define COLOR_ALT_FG 244 -#define COLOR_ALT_BG 236 -#define COLOR_NUMBER_BG 232 -#define COLOR_NUMBER_FG 101 -#define COLOR_STATUS_BG 238 -#define COLOR_TABBAR_BG 230 -#define COLOR_TAB_BG 248 -#define COLOR_ERROR_FG 15 -#define COLOR_ERROR_BG 196 - -uint32_t codepoint; -uint32_t codepoint_r; -uint32_t state = 0; -uint32_t istate = 0; - -struct termios old; - -void set_unbuffered() { - tcgetattr(fileno(stdin), &old); - struct termios new = old; - new.c_lflag &= (~ICANON & ~ECHO); - tcsetattr(fileno(stdin), TCSAFLUSH, &new); -} - -void set_buffered() { - tcsetattr(fileno(stdin), TCSAFLUSH, &old); -} - -int to_eight(uint32_t codepoint, uint8_t * out) { - memset(out, 0x00, 7); - - if (codepoint < 0x0080) { - out[0] = (uint8_t)codepoint; - } else if (codepoint < 0x0800) { - out[0] = 0xC0 | (codepoint >> 6); - out[1] = 0x80 | (codepoint & 0x3F); - } else if (codepoint < 0x10000) { - out[0] = 0xE0 | (codepoint >> 12); - out[1] = 0x80 | ((codepoint >> 6) & 0x3F); - out[2] = 0x80 | (codepoint & 0x3F); - } else if (codepoint < 0x200000) { - out[0] = 0xF0 | (codepoint >> 18); - out[1] = 0x80 | ((codepoint >> 12) & 0x3F); - out[2] = 0x80 | ((codepoint >> 6) & 0x3F); - out[3] = 0x80 | ((codepoint) & 0x3F); - } else if (codepoint < 0x4000000) { - out[0] = 0xF8 | (codepoint >> 24); - out[1] = 0x80 | (codepoint >> 18); - out[2] = 0x80 | ((codepoint >> 12) & 0x3F); - out[3] = 0x80 | ((codepoint >> 6) & 0x3F); - out[4] = 0x80 | ((codepoint) & 0x3F); - } else { - out[0] = 0xF8 | (codepoint >> 30); - out[1] = 0x80 | ((codepoint >> 24) & 0x3F); - out[2] = 0x80 | ((codepoint >> 18) & 0x3F); - out[3] = 0x80 | ((codepoint >> 12) & 0x3F); - out[4] = 0x80 | ((codepoint >> 6) & 0x3F); - out[5] = 0x80 | ((codepoint) & 0x3F); - } - - return strlen(out); -} - -int codepoint_width(uint16_t codepoint) { - if (codepoint < 32) { - return 4; - } - if (codepoint > 256) { - return wcwidth(codepoint); - } - return 1; -} - - -void place_cursor(int x, int y) { - printf("\033[%d;%dH", y, x); - fflush(stdout); -} - -void place_cursor_h(int h) { - printf("\033[%dG", h); - fflush(stdout); -} - -void set_colors(int fg, int bg) { - printf("\033[48;5;%dm", bg); - printf("\033[38;5;%dm", fg); - fflush(stdout); -} - -void clear_to_end() { - printf("\033[K"); - fflush(stdout); -} - -void set_bold() { - printf("\033[1m"); - fflush(stdout); -} - -void set_underline() { - printf("\033[4m"); - fflush(stdout); -} - -void reset() { - printf("\033[0m"); - fflush(stdout); -} - -void clear_screen() { - printf("\033[H\033[2J"); - fflush(stdout); -} - -void redraw_tabbar() { - place_cursor(1,1); - for (uint32_t i = 0; i < buffers_len; i++) { - buffer_t * _env = buffers[i]; - if (_env == env) { - reset(); - set_colors(COLOR_FG, COLOR_BG); - set_bold(); - } else { - reset(); - set_colors(COLOR_FG, COLOR_TAB_BG); - set_underline(); - } - if (_env->modified) { - printf(" +"); - } - if (_env->file_name) { - printf(" %s ", _env->file_name); - } else { - printf(" [No Name] "); - } - } - reset(); - set_colors(COLOR_FG, COLOR_TABBAR_BG); - clear_to_end(); -} - -int log_base_10(unsigned int v) { - int r = (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 : - (v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 : - (v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0; - return r; -} - -void render_line(line_t * line, int width, int offset) { - uint32_t i = 0; - uint32_t j = 0; - set_colors(COLOR_FG, COLOR_BG); - while (i < line->actual) { - char_t c = line->text[i]; - if (j >= offset) { - if (j - offset + c.display_width >= width) { - set_colors(COLOR_ALT_FG, COLOR_ALT_BG); - while (j - offset < width - 1) { - printf("-"); - j++; - } - printf(">"); - break; - } - if (c.codepoint == '\t') { - set_colors(COLOR_ALT_FG, COLOR_ALT_BG); - printf("»···"); - set_colors(COLOR_FG, COLOR_BG); - } else if (c.codepoint < 32) { - set_colors(COLOR_ALT_FG, COLOR_ALT_BG); - printf("<%02x>", c.codepoint); - set_colors(COLOR_FG, COLOR_BG); - } else { - char tmp[8]; - to_eight(c.codepoint, tmp); - printf("%s", tmp); - } - } else if (j + c.display_width == offset + 1) { - set_colors(COLOR_ALT_FG, COLOR_ALT_BG); - printf("<"); - set_colors(COLOR_FG, COLOR_BG); - } - j += c.display_width; - i += 1; - } -} - -void realign_cursor() { - line_t * line = env->lines[env->line_no-1]; - int x = -env->coffset; - int i = 0; - for (; i < env->col_no - 1; ++i) { - if (x + 12 > term_width) { - env->col_no = i + 1; - return; - } - char_t * c = &env->lines[env->line_no-1]->text[i]; - x += c->display_width; - } - while (x < 0) { - env->col_no += 1; - i++; - char_t * c = &env->lines[env->line_no-1]->text[i]; - x += c->display_width; - } -} - -void redraw_text() { - int l = term_height - env->bottom_size - 1; - int j = 0; - - int num_size = log_base_10(env->line_count) + 2; - for (int x = env->offset; j < l && x < env->line_count; x++) { - place_cursor(1,2 + j); - /* draw line number */ - set_colors(COLOR_NUMBER_FG, COLOR_ALT_FG); - printf(" "); - set_colors(COLOR_NUMBER_FG, COLOR_NUMBER_BG); - for (int y = 0; y < num_size - log_base_10(x + 1); ++y) { - printf(" "); - } - printf("%d ", x + 1); - set_colors(COLOR_FG, COLOR_BG); - clear_to_end(); - render_line(env->lines[x], term_width - 3 - num_size, env->coffset); - j++; - } - for (; j < l; ++j) { - place_cursor(1,2 + j); - set_colors(COLOR_ALT_FG, COLOR_ALT_BG); - printf("~"); - clear_to_end(); - } -} - -void redraw_statusbar() { - place_cursor(1, term_height - 1); - set_colors(COLOR_FG, COLOR_STATUS_BG); - if (env->file_name) { - printf("%s", env->file_name); - } else { - printf("[No Name]"); - } - if (env->modified) { - printf(" [+]"); - } - clear_to_end(); - char right_hand[1024]; - sprintf(right_hand, "Line %d/%d Col: %d ", env->line_no, env->line_count, env->col_no); - place_cursor_h(term_width - strlen(right_hand)); - printf("%s",right_hand); - fflush(stdout); -} - -void redraw_commandline() { - place_cursor(1, term_height); - set_colors(COLOR_FG, COLOR_BG); - clear_to_end(); -} - -void redraw_all() { - redraw_tabbar(); - redraw_text(); - redraw_statusbar(); - redraw_commandline(); -} - -void update_title() { - char cwd[1024] = {'/',0}; - getcwd(cwd, 1024); - printf("\033]1;%s%s (%s) - BIM\007", env->file_name, env->modified ? " +" : "", cwd); -} - -void set_modified() { - if (env->modified) return; - - update_title(); - env->modified = 1; - redraw_tabbar(); - redraw_statusbar(); -} - -void render_error(char * message) { - redraw_commandline(); - set_colors(COLOR_ERROR_FG, COLOR_ERROR_BG); - printf("%s", message); - fflush(stdout); -} - -void render_cursor() { - printf("\033[1z"); - fflush(stdout); -} - -void place_cursor_actual() { - int num_size = log_base_10(env->line_count) + 5; - int x = num_size + 1 - env->coffset; - for (int i = 0; i < env->col_no - 1; ++i) { - char_t * c = &env->lines[env->line_no-1]->text[i]; - x += c->display_width; - } - int y = env->line_no - env->offset + 1; - - place_cursor(x,y); - csr_x_actual = x; - csr_y_actual = y; - -#ifndef __linux__ - render_cursor(); -#endif -} - -void initialize() { - buffers_avail = 4; - buffers = malloc(sizeof(buffer_t *) * buffers_avail); - - struct winsize w; - ioctl(0, TIOCGWINSZ, &w); - term_width = w.ws_col; - term_height = w.ws_row; - set_unbuffered(); - -} - -void goto_line(int line) { - if (line < 1) line = 1; - if (line > env->line_count) line = env->line_count; - env->offset = line - 1; - env->line_no = line; - env->col_no = 1; - redraw_all(); -} - -void add_buffer(uint8_t * buf, int size) { - for (int i = 0; i < size; ++i) { - if (!decode(&state, &codepoint_r, buf[i])) { - uint32_t c = codepoint_r; - if (c == '\n') { - env->lines = add_line(env->lines, env->line_no); - env->col_no = 1; - env->line_no += 1; - } else { - char_t _c; - _c.codepoint = (uint16_t)c; - _c.display_width = codepoint_width((uint16_t)c); - line_t * line = env->lines[env->line_no - 1]; - line_t * nline = line_insert(line, _c, env->col_no - 1); - if (line != nline) { - env->lines[env->line_no - 1] = nline; - } - env->col_no += 1; - } - } else if (state == UTF8_REJECT) { - state = 0; - } - } -} - - -void open_file(char * file) { - env = buffer_new(); - - env->file_name = malloc(strlen(file) + 1); - memcpy(env->file_name, file, strlen(file) + 1); - - setup_buffer(env); - - FILE * f = fopen(file, "r"); - - if (!f) { - char buf[1024]; - snprintf(buf, 1024, "Could not open %s", file); - render_error(buf); - return; - } - - size_t length; - - fseek(f, 0, SEEK_END); - length = ftell(f); - fseek(f, 0, SEEK_SET); - - uint8_t buf[BLOCK_SIZE]; - - while (length > BLOCK_SIZE) { - fread(buf, BLOCK_SIZE, 1, f); - add_buffer(buf, BLOCK_SIZE); - length -= BLOCK_SIZE; - } - if (length > 0) { - fread(buf, 1, length, f); - add_buffer((uint8_t *)buf, length); - } - - update_title(); - goto_line(0); - - fclose(f); -} - -void quit() { - set_buffered(); - reset(); - clear_screen(); - printf("Thanks for flying bim!\n"); - exit(0); -} - -void try_quit() { - for (uint32_t i = 0; i < buffers_len; i++ ) { - buffer_t * _env = buffers[i]; - if (_env->modified) { - char msg[100]; - snprintf(msg, 100, "Modifications made to file `%s` in tab %d. Aborting.", _env->file_name, i+1); - render_error(msg); - return; - } - } - quit(); -} - -void previous_tab() { - buffer_t * last = NULL; - for (uint32_t i = 0; i < buffers_len; i++) { - buffer_t * _env = buffers[i]; - if (_env == env) { - if (last) { - env = last; - redraw_all(); - return; - } else { - env = buffers[buffers_len-1]; - redraw_all(); - return; - } - } - last = _env; - } -} - -void next_tab() { - for (uint32_t i = 0; i < buffers_len; i++) { - buffer_t * _env = buffers[i]; - if (_env == env) { - if (i != buffers_len - 1) { - env = buffers[i+1]; - redraw_all(); - return; - } else { - env = buffers[0]; - redraw_all(); - return; - } - } - } -} - -int isnumeric(char * str) { - char *p = str; - while (*p) { - if (*p < '0' || *p > '9') return 0; - ++p; - } - return 1; -} - -void write_file(char * file) { - if (!file) { - render_error("Need a file to write to."); - return; - } - - FILE * f = fopen(file, "w"); - - if (!f) { - render_error("Failed to open file for writing."); - } - - uint32_t i, j; - for (i = 0; i < env->line_count; ++i) { - line_t * line = env->lines[i]; - for (j = 0; j < line->actual; j++) { - char_t c = line->text[j]; - if (c.codepoint == 0) { - char buf[1] = {0}; - fwrite(buf, 1, 1, f); - } else { - char tmp[4]; - int i = to_eight(c.codepoint, tmp); - fwrite(tmp, i, 1, f); - } - } - if (i + 1 < env->line_count) { - fputc('\n', f); - } - } - fclose(f); - - env->modified = 0; - if (!env->file_name) { - env->file_name = malloc(strlen(file) + 1); - memcpy(env->file_name, file, strlen(file) + 1); - } - - redraw_all(); -} - -void process_command(char * cmd) { - char *p, *argv[512], *last; - int argc = 0; - for ((p = strtok_r(cmd, " ", &last)); p; - (p = strtok_r(NULL, " ", &last)), argc++) { - if (argc < 511) argv[argc] = p; - } - argv[argc] = NULL; - - if (argc < 1) { - /* no op */ - return; - } - if (!strcmp(argv[0], "e")) { - if (argc > 1) { - open_file(argv[1]); - } else { - render_error("Expected a file to open..."); - } - } else if (!strcmp(argv[0], "w")) { - if (argc > 1) { - write_file(argv[1]); - } else { - write_file(env->file_name); - } - } else if (!strcmp(argv[0], "q")) { - if (env->modified) { - render_error("No write since last change. Use :q! to force exit."); - } else { - buffer_t * previous_env = env; - buffer_t * new_env = buffer_close(env); - if (new_env == previous_env) { - render_error("lolwat"); - } - if (!new_env) { - quit(); - } - free(previous_env); - env = new_env; - redraw_all(); - } - } else if (!strcmp(argv[0], "qall")) { - try_quit(); - } else if (!strcmp(argv[0], "q!")) { - quit(); - } else if (!strcmp(argv[0], "tabp")) { - previous_tab(); - } else if (!strcmp(argv[0], "tabn")) { - next_tab(); - } else if (isnumeric(argv[0])) { - goto_line(atoi(argv[0])); - } else { - char buf[512]; - snprintf(buf, 512, "Not an editor command: %s", argv[0]); - render_error(buf); - } -} - -void command_mode() { - char c; - char buffer[1024] = {0}; - int buffer_len = 0; - - redraw_commandline(); - printf(":"); - fflush(stdout); - - while (c = fgetc(stdin)) { - if (c == '\033') { - break; - } else if (c == ENTER_KEY) { - process_command(buffer); - break; - } else if (c == BACKSPACE_KEY) { - if (buffer_len > 0) { - buffer_len -= 1; - buffer[buffer_len] = '\0'; - redraw_commandline(); - printf(":%s", buffer); - fflush(stdout); - } else { - redraw_commandline(); - break; - } - } else { - buffer[buffer_len] = c; - buffer_len++; - printf("%c", c); - fflush(stdout); - } - } -} - -void insert_mode() { - uint8_t cin; - uint32_t c; - redraw_commandline(); - set_bold(); - printf("-- INSERT --"); - reset(); - place_cursor_actual(); - set_colors(COLOR_FG, COLOR_BG); - while (cin = fgetc(stdin)) { - if (!decode(&istate, &c, cin)) { - switch (c) { - case '\033': - if (env->col_no > env->lines[env->line_no-1]->actual) { - env->col_no = env->lines[env->line_no-1]->actual; - } - if (env->col_no == 0) env->col_no = 1; - redraw_commandline(); - return; - case BACKSPACE_KEY: - if (env->col_no > 1) { - line_delete(env->lines[env->line_no - 1], env->col_no - 1); - env->col_no -= 1; - redraw_text(); - set_modified(); - redraw_statusbar(); - place_cursor_actual(); - } - break; - case ENTER_KEY: - if (env->col_no == env->lines[env->line_no - 1]->actual + 1) { - env->lines = add_line(env->lines, env->line_no); - } else { - /* oh oh god we're all gonna die */ - env->lines = split_line(env->lines, env->line_no, env->col_no - 1); - } - env->col_no = 1; - env->line_no += 1; - if (env->line_no > env->offset + term_height - env->bottom_size - 1) { - env->offset += 1; - } - redraw_text(); - set_modified(); - redraw_statusbar(); - place_cursor_actual(); - break; - default: - { - char_t _c; - _c.codepoint = c; - _c.display_width = codepoint_width(c); - line_t * line = env->lines[env->line_no - 1]; - line_t * nline = line_insert(line, _c, env->col_no - 1); - if (line != nline) { - env->lines[env->line_no - 1] = nline; - } - redraw_text(); /* XXX */ - env->col_no += 1; - set_modified(); - redraw_statusbar(); - place_cursor_actual(); - } - break; - } - } else if (istate == UTF8_REJECT) { - istate = 0; - } - } -} - -int main(int argc, char * argv[]) { - initialize(); - - if (argc > 1) { - open_file(argv[1]); - } else { - env = buffer_new(); - update_title(); - setup_buffer(env); - } - - while (1) { - redraw_all(); - place_cursor_actual(); - char buf[1]; - char c; - while (c = fgetc(stdin)) { - switch (c) { - case '\033': - redraw_all(); - break; - case ':': - /* Switch to command mode */ - command_mode(); - break; - case 'j': - if (env->line_no < env->line_count) { - env->line_no += 1; - if (env->col_no > env->lines[env->line_no-1]->actual) { - env->col_no = env->lines[env->line_no-1]->actual; - } - if (env->col_no == 0) env->col_no = 1; - if (env->line_no > env->offset + term_height - env->bottom_size - 1) { - env->offset += 1; - redraw_text(); - } - redraw_statusbar(); - place_cursor_actual(); - } - break; - case 'k': - if (env->line_no > 1) { - env->line_no -= 1; - if (env->col_no > env->lines[env->line_no-1]->actual) { - env->col_no = env->lines[env->line_no-1]->actual; - } - if (env->col_no == 0) env->col_no = 1; - if (env->line_no <= env->offset) { - env->offset -= 1; - redraw_text(); - } - redraw_statusbar(); - place_cursor_actual(); - } - break; - case 'h': - if (env->col_no > 1) { - env->col_no -= 1; - redraw_statusbar(); - place_cursor_actual(); - } - break; - case 'l': - if (env->col_no < env->lines[env->line_no-1]->actual) { - env->col_no += 1; - redraw_statusbar(); - place_cursor_actual(); - } - break; - case ' ': - goto_line(env->line_no + term_height - 6); - break; - case 'O': - { - env->lines = add_line(env->lines, env->line_no-1); - env->col_no = 1; - redraw_text(); - set_modified(); - place_cursor_actual(); - goto _insert; - } - case 'o': - { - env->lines = add_line(env->lines, env->line_no); - env->col_no = 1; - env->line_no += 1; - if (env->line_no > env->offset + term_height - env->bottom_size - 1) { - env->offset += 1; - } - redraw_text(); - set_modified(); - place_cursor_actual(); - goto _insert; - } - case ',': - if (env->coffset > 5) { - env->coffset -= 5; - } else { - env->coffset = 0; - } - realign_cursor(); - redraw_all(); - break; - case '.': - env->coffset += 5; - realign_cursor(); - redraw_all(); - break; - case 'a': - if (env->col_no < env->lines[env->line_no-1]->actual + 1) { - env->col_no += 1; - } - goto _insert; - case '$': - env->col_no = env->lines[env->line_no-1]->actual+1; - break; - case '0': - env->col_no = 1; - break; - case 'i': -_insert: - insert_mode(); - break; - default: - break; - } - place_cursor_actual(); - } -_continue: - printf("%c", c); - } - -#if 0 - if (argc < 2) { - fprintf(stderr, "%s: argument expected\n", argv[0]); - return 1; - } - - fprintf(stderr, "Writing out file again:\n\n"); - - for (int i = 0; i < file_len_unicode; ++i) { - uint8_t buf[4]; - int len = to_eight(file_buffer[i], buf); - fwrite(buf, len, 1, stdout); - } - fflush(stdout); -#endif - - - return 0; -} diff --git a/userspace/extra/compare.c b/userspace/extra/compare.c deleted file mode 100644 index 1f59dff5..00000000 --- a/userspace/extra/compare.c +++ /dev/null @@ -1,68 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * compare - * - * Compares two files and prints out some - * statistics on how they differ. - * - * This is *NOT* diff. - */ -#include -#include - -#define CHUNK_SIZE 1024 - -int main(int argc, char * argv[]) { - if (argc < 3) { - fprintf(stderr, "Need two files to compare.\n"); - return 1; - } - - FILE * a = fopen(argv[1], "r"); - FILE * b = fopen(argv[2], "r"); - size_t lengtha, lengthb; - - fseek(a, 0, SEEK_END); - lengtha = ftell(a); - fseek(a, 0, SEEK_SET); - - fseek(b, 0, SEEK_END); - lengthb = ftell(b); - fseek(b, 0, SEEK_SET); - - fprintf(stderr,"[%d bytes and %d bytes]\n", lengtha, lengthb); - - char bufa[CHUNK_SIZE]; - char bufb[CHUNK_SIZE]; - - int chunk = 0; - size_t read = 0; - - while (read < lengtha) { - memset(bufa, 0x0, CHUNK_SIZE); - memset(bufb, 0x0, CHUNK_SIZE); - fread(bufa, 1, CHUNK_SIZE, a); - fread(bufb, 1, CHUNK_SIZE, b); - size_t different = 0; - for (int i = 0; i < CHUNK_SIZE; ++i) { - if (bufa[i] != bufb[i]) - different++; - } - - if (different > 0) { - printf("Chunk %d has %d differing bytes.\n", chunk, different); - } - - read += CHUNK_SIZE; - chunk++; - } - - fclose(a); - fclose(b); - - - return 0; -} diff --git a/userspace/extra/csnow.c b/userspace/extra/csnow.c deleted file mode 100644 index 48d8e6b8..00000000 --- a/userspace/extra/csnow.c +++ /dev/null @@ -1,160 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include -#include -#include -#include -#include - -#define MAX_SPEED 2 -#define INITIAL_SNOW 40 -#define INCREMENTAL_SNOW 10 -#define BUFFER_SIZE 10 -#define BLANK_SPACE " " - -#define NUM_FLAKE_TEXTURES 4 -char * flake_textures[] = { - "❄", - "❅", - "❆", - "*", -}; - -typedef struct { - int width; - int height; - char ** backingstore; -} screen_t; - -typedef struct { - char * display; - signed short x; - signed short y; - signed char speed; - char gravity; -} flake_t; - -screen_t * init_screen() { - char * term = getenv("TERM"); - - screen_t * screen = malloc(sizeof(screen_t)); - - struct winsize w; - ioctl(0, TIOCGWINSZ, &w); - screen->width = w.ws_col; - screen->height = w.ws_row; - - screen->backingstore = malloc(sizeof(char *) * screen->width * screen->height); - - return screen; -} - -flake_t * make_some_flakes(screen_t * screen, int how_many) { - flake_t * out = malloc(sizeof(flake_t) * (how_many + 1)); - - for (int i = 0; i < how_many; ++i) { - out[i].display = flake_textures[rand() % NUM_FLAKE_TEXTURES]; - out[i].x = rand() % screen->width; - out[i].y = -(rand() % BUFFER_SIZE); - out[i].speed = rand() % MAX_SPEED - (MAX_SPEED / 2); - out[i].gravity = 1; - } - - out[how_many].display = NULL; - return out; -} - -flake_t * add_flakes(screen_t * screen, flake_t * flakes, int how_many) { - flake_t * more = make_some_flakes(screen, how_many); - - int len = 0; for (; flakes[len].display; ++len); - flakes = realloc(flakes, sizeof(flake_t) * (how_many + len + 1)); - - memcpy(&flakes[len], more, sizeof(flake_t) * (how_many + 1)); - - free(more); - - return flakes; -} - -int detect_collisions(screen_t * screen, flake_t * flakes, int i) { - int x = flakes[i].x; - int y = flakes[i].y; - - if (flakes[i].y >= screen->height - 1) { - flakes[i].gravity = 0; - return 1; - } - - for (int j = 0; flakes[j].display; ++j) { - if (flakes[j].gravity) continue; - if (flakes[j].x == x && flakes[j].y == (y + 1)) { - flakes[i].gravity = 0; - return 1; - } - } - - return 0; -} - -void update_flakes(screen_t * screen, flake_t * flakes) { - for (int i = 0; flakes[i].display; ++i) { - if (flakes[i].gravity) { - flakes[i].x += flakes[i].speed; - if (flakes[i].x < 0) { - flakes[i].x = screen->width - 1; - } else if (flakes[i].x >= screen->width) { - flakes[i].x = 0; - } - if (!detect_collisions(screen, flakes, i)) { - flakes[i].y += flakes[i].gravity; - } - } - } -} - -void write_screen(screen_t * screen, flake_t * flakes) { - for (int y = 0; y < screen->height; ++y) { - for (int x = 0; x < screen->width; ++x) { - screen->backingstore[x + y * screen->width] = BLANK_SPACE; - } - } - for (int i = 0; flakes[i].display; ++i) { - if (flakes[i].y >= 0 && flakes[i].y < screen->height && flakes[i].x >= 0 && flakes[i].x < screen->width) { - screen->backingstore[flakes[i].x + flakes[i].y * screen->width] = flakes[i].display; - } - } -} - -void flip_screen(screen_t * screen) { - printf("\033[H"); - for (int y = 0; y < screen->height; ++y) { - for (int x = 0; x < screen->width; ++x) { - if ((y == screen->height - 1) && (x == screen->width - 1)) { - fflush(stdout); - return; - } - printf("%s", screen->backingstore[x + y * screen->width]); - } - printf("\n"); - } -} - -int main(int argc, char * argv) { - - screen_t * main_screen = init_screen(); - flake_t * flakes = make_some_flakes(main_screen, INITIAL_SNOW); - - for (;;) { - write_screen(main_screen, flakes); - flip_screen(main_screen); - update_flakes(main_screen, flakes); - flakes = add_flakes(main_screen, flakes, INCREMENTAL_SNOW); - usleep(90000); - } - - - return 0; -} diff --git a/userspace/extra/curses/README.md b/userspace/extra/curses/README.md deleted file mode 100644 index c078d4b5..00000000 --- a/userspace/extra/curses/README.md +++ /dev/null @@ -1,28 +0,0 @@ -These samples are sourced from http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/ - -They were written by Pradeep Padala and are released under the MIT license as follows: - - Copyright © 2001 by Pradeep Padala. - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, distribute with modifications, - sublicense, and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name(s) of the above copyright holders - shall not be used in advertising or otherwise to promote the sale, use or other - dealings in this Software without prior written authorization. - - diff --git a/userspace/extra/curses/curses-hello.c b/userspace/extra/curses/curses-hello.c deleted file mode 100644 index f33f26fc..00000000 --- a/userspace/extra/curses/curses-hello.c +++ /dev/null @@ -1,15 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include - -int main() { - initscr(); - printw("Hello World !!!"); - refresh(); - getch(); - endwin(); - - return 0; -} diff --git a/userspace/extra/curses/panel-test.c b/userspace/extra/curses/panel-test.c deleted file mode 100644 index 378fba8d..00000000 --- a/userspace/extra/curses/panel-test.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - Copyright © 2001 by Pradeep Padala. -*/ -#include -#include - -typedef struct _PANEL_DATA { - int hide; /* TRUE if panel is hidden */ -}PANEL_DATA; - -#define NLINES 10 -#define NCOLS 40 - -void init_wins(WINDOW **wins, int n); -void win_show(WINDOW *win, char *label, int label_color); -void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); - -int main() -{ WINDOW *my_wins[3]; - PANEL *my_panels[3]; - PANEL_DATA panel_datas[3]; - PANEL_DATA *temp; - int ch; - - /* Initialize curses */ - initscr(); - start_color(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - - /* Initialize all the colors */ - init_pair(1, COLOR_RED, COLOR_BLACK); - init_pair(2, COLOR_GREEN, COLOR_BLACK); - init_pair(3, COLOR_BLUE, COLOR_BLACK); - init_pair(4, COLOR_CYAN, COLOR_BLACK); - - init_wins(my_wins, 3); - - /* Attach a panel to each window */ /* Order is bottom up */ - my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ - my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ - my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ - - /* Initialize panel datas saying that nothing is hidden */ - panel_datas[0].hide = FALSE; - panel_datas[1].hide = FALSE; - panel_datas[2].hide = FALSE; - - set_panel_userptr(my_panels[0], &panel_datas[0]); - set_panel_userptr(my_panels[1], &panel_datas[1]); - set_panel_userptr(my_panels[2], &panel_datas[2]); - - /* Update the stacking order. 2nd panel will be on top */ - update_panels(); - - /* Show it on the screen */ - attron(COLOR_PAIR(4)); - mvprintw(LINES - 3, 0, "Show or Hide a window with 'a'(first window) 'b'(Second Window) 'c'(Third Window)"); - mvprintw(LINES - 2, 0, "q to Exit"); - - attroff(COLOR_PAIR(4)); - doupdate(); - - while((ch = getch()) != 'q') - { switch(ch) - { case 'a': - temp = (PANEL_DATA *)panel_userptr(my_panels[0]); - if(temp->hide == FALSE) - { hide_panel(my_panels[0]); - temp->hide = TRUE; - } - else - { show_panel(my_panels[0]); - temp->hide = FALSE; - } - break; - case 'b': - temp = (PANEL_DATA *)panel_userptr(my_panels[1]); - if(temp->hide == FALSE) - { hide_panel(my_panels[1]); - temp->hide = TRUE; - } - else - { show_panel(my_panels[1]); - temp->hide = FALSE; - } - break; - case 'c': - temp = (PANEL_DATA *)panel_userptr(my_panels[2]); - if(temp->hide == FALSE) - { hide_panel(my_panels[2]); - temp->hide = TRUE; - } - else - { show_panel(my_panels[2]); - temp->hide = FALSE; - } - break; - } - update_panels(); - doupdate(); - } - endwin(); - return 0; -} - -/* Put all the windows */ -void init_wins(WINDOW **wins, int n) -{ int x, y, i; - char label[80]; - - y = 2; - x = 10; - for(i = 0; i < n; ++i) - { wins[i] = newwin(NLINES, NCOLS, y, x); - sprintf(label, "Window Number %d", i + 1); - win_show(wins[i], label, i + 1); - y += 3; - x += 7; - } -} - -/* Show the window with a border and a label */ -void win_show(WINDOW *win, char *label, int label_color) -{ int startx, starty, height, width; - - getbegyx(win, starty, startx); - getmaxyx(win, height, width); - - box(win, 0, 0); - mvwaddch(win, 2, 0, ACS_LTEE); - mvwhline(win, 2, 1, ACS_HLINE, width - 2); - mvwaddch(win, 2, width - 1, ACS_RTEE); - - print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color)); -} - -void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) -{ int length, x, y; - float temp; - - if(win == NULL) - win = stdscr; - getyx(win, y, x); - if(startx != 0) - x = startx; - if(starty != 0) - y = starty; - if(width == 0) - width = 80; - - length = strlen(string); - temp = (width - length)/ 2; - x = startx + (int)temp; - wattron(win, color); - mvwprintw(win, y, x, "%s", string); - wattroff(win, color); - refresh(); -} diff --git a/userspace/extra/cursor-off.c b/userspace/extra/cursor-off.c deleted file mode 100644 index 0316ca8e..00000000 --- a/userspace/extra/cursor-off.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(int argc, char * argv[]) { - int x[] = {0xFF,0xFF}; - return syscall_system_function(13, (char **)x); -} diff --git a/userspace/extra/kdebug.c b/userspace/extra/kdebug.c deleted file mode 100644 index 56fb7885..00000000 --- a/userspace/extra/kdebug.c +++ /dev/null @@ -1,13 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include - -int main(int argc, char * argv[]) { - int pid = syscall_system_function(7, NULL); - int status; - wait(&status); - return status; -} diff --git a/userspace/extra/live-welcome.c b/userspace/extra/live-welcome.c deleted file mode 100644 index 0a9de174..00000000 --- a/userspace/extra/live-welcome.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include -#include - -#include "lib/toaru_auth.h" - -#include "lib/trace.h" -#define TRACE_APP_NAME "live-welcome" - -int main(int argc, char * argv[]) { - - int _session_pid = fork(); - if (!_session_pid) { - setuid(1000); - toaru_auth_set_vars(); - - char * args[] = {"/bin/gsession", NULL}; - execvp(args[0], args); - TRACE("gsession start failed?"); - } - - int _wizard_pid = fork(); - if (!_wizard_pid) { - setuid(1000); - toaru_auth_set_vars(); - - char * args[] = {"/bin/wizard.py", NULL}; - execvp(args[0], args); - TRACE("wizard start failed?"); - } - - int pid = 0; - do { - pid = wait(NULL); - } while ((pid > 0 && pid != _session_pid) || (pid == -1 && errno == EINTR)); - - char * args[] = {"/bin/glogin",NULL}; - execvp(args[0],args); - - TRACE("failed to start glogin after log out, trying to reboot instead."); - system("reboot"); - - return 1; -} diff --git a/userspace/extra/lock.c b/userspace/extra/lock.c deleted file mode 100644 index 83ee70ca..00000000 --- a/userspace/extra/lock.c +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* - * lock - * - * CLI screen locker. Useful for a single-user - * terminal-only session. - */ -#include -#include -#include -#include -#include -#include -#include - -void sig_int(int sig) { - /* Ignore */ -} - -void main(int argc, char * argv[]) { - signal(SIGINT, sig_int); - - char * password_a = malloc(sizeof(char) * 1024); - char * password_b = malloc(sizeof(char) * 1024); - - printf("\033[H\033[2J"); - - fprintf(stdout, "Enter a lock password: \033[1001z"); - fflush(stdout); - fgets(password_a, 1024, stdin); - password_a[strlen(password_a)-1] = '\0'; - fprintf(stdout, "\033[1002z\n"); - - uint32_t failures = 0; - - do { - printf("\033[H\033[2J"); - if (failures > 0) { - printf("\n\033[1;41;33mIncorrect password. (%d failure%s)\033[0m\n", failures, (failures > 1 ? "s" : "")); - } - printf("\n\033[1;31mSystem is locked.\033[0m\n\n"); - fprintf(stdout, "Enter password to unlock: \033[1001z"); - fflush(stdout); - fgets(password_b, 1024, stdin); - password_b[strlen(password_b)-1] = '\0'; - fprintf(stdout, "\033[1002z\n"); - failures++; - } while (strcmp(password_a, password_b) != 0); -} diff --git a/userspace/extra/pipe-out.c b/userspace/extra/pipe-out.c deleted file mode 100644 index da0fcb54..00000000 --- a/userspace/extra/pipe-out.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -int main(int argc, char * argv[]) { - if (argc < 2) { - return 1; - } - - FILE * out = fopen(argv[1], "w"); - - while (!feof(stdin)) { - char buf[1024]; - size_t r = fread(buf, 1, 1024, stdin); - fwrite(buf, 1, r, out); - } - fflush(out); - fclose(out); - return 0; -} diff --git a/userspace/extra/prepend.c b/userspace/extra/prepend.c deleted file mode 100644 index 11262c03..00000000 --- a/userspace/extra/prepend.c +++ /dev/null @@ -1,35 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -/* - * Prepend text in front of output lines - */ -#include -#include -#include -#include - -#define LINE_SIZE 4096 - -int main(int argc, char ** argv) { - if (argc < 2) { - fprintf(stderr, "usage: %s text-to-prepend\n", argv[0]); - return 1; - } - - char * needle = argv[1]; - char buf[LINE_SIZE]; - - while (fgets(buf, LINE_SIZE, stdin)) { - fprintf(stdout, "%s: %s", argv[1], buf); - } - - return 0; -} - -/* - * vim:tabstop=4 - * vim:noexpandtab - * vim:shiftwidth=4 - */ diff --git a/userspace/extra/quick-launch.c b/userspace/extra/quick-launch.c deleted file mode 100644 index 8dba960e..00000000 --- a/userspace/extra/quick-launch.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -#include -#include -#include - -#include "lib/toaru_auth.h" - -#include "lib/trace.h" -#define TRACE_APP_NAME "quick-launch" - -int main(int argc, char * argv[]) { - TRACE("Starting session manager..."); - - int _session_pid = fork(); - if (!_session_pid) { - setuid(1000); - toaru_auth_set_vars(); - - char * args[] = {"/bin/gsession", NULL}; - execvp(args[0], args); - TRACE("gsession start failed?"); - } - - int pid = 0; - do { - pid = wait(NULL); - } while ((pid > 0 && pid != _session_pid) || (pid == -1 && errno == EINTR)); - - system("reboot"); - -} diff --git a/userspace/extra/sha512sum.c b/userspace/extra/sha512sum.c deleted file mode 100644 index e5ed8507..00000000 --- a/userspace/extra/sha512sum.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "lib/sha2.h" - -int main(int argc, char * argv[]) { - if (argc < 2) return 1; - struct stat buf; - stat(argv[1], &buf); - FILE * f = fopen(argv[1], "r"); - - char * x = malloc(buf.st_size); - fread(x, buf.st_size, 1, f); - - /* Generate SHA512 */ - char hash[SHA512_DIGEST_STRING_LENGTH]; - SHA512_Data(x, buf.st_size, hash); - fprintf(stderr, "%s %s\n", hash, argv[1]); - return 0; -} diff --git a/userspace/extra/solver.c b/userspace/extra/solver.c deleted file mode 100644 index cbb060f6..00000000 --- a/userspace/extra/solver.c +++ /dev/null @@ -1,251 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * Brute-Force SAT Solver - * - * Copyright (c) 2012 Kevin Lange. All rights reserved. - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal with the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimers. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimers in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of Kevin Lange, nor the names of its contributors - * may be used to endorse or promote products derived from this Software - * without specific prior written permission. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * WITH THE SOFTWARE. - * - */ - -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include -#include -#include "lib/list.h" - -/* Width of a line to read for a clause. Clauses should not be too terrible long. */ -#define LINE_WIDTH 4096 - -/* This brute-force solution uses bitsets, one bit per variable */ -#define BITS_IN_SET 8 -uint8_t * bit_sets = NULL; -uint64_t bit_sets_n = 0; -uint64_t variables = 0; -uint64_t clause_n = 0; -uint64_t collected = 0; - -#define DEBUG 0 - -/* Clauses are stored as dynamic linked-lists of variable states */ -list_t ** clauses; - -/* Check a bit (variable) for the current state */ -inline uint8_t checkbit(uint64_t bit) { - uint64_t set_id = bit / BITS_IN_SET; - uint8_t offset = bit - set_id * BITS_IN_SET; - uint8_t tmp = ((bit_sets[set_id] & (1 << offset)) > 0); - -#if DEBUG - fprintf(stderr,"bit %ld [%ld:%d] = %d [%x, %d]\n", bit, set_id, offset, tmp, bit_sets[set_id], 1 << offset); -#endif - - return tmp; -} - -/* Initialize the bitsets */ -inline void setup_bitsets() { - bit_sets_n = variables / BITS_IN_SET + 1; - bit_sets = (uint8_t *)malloc(sizeof(uint8_t) * bit_sets_n); - memset(bit_sets, 0x00, sizeof(uint8_t) * bit_sets_n); -} - -/* - * Increment the state. - * The bit sets are like a very large integer, and we are - * incrementing by one. - */ -inline void next_bitset(uint64_t i) { - if (__builtin_expect(bit_sets[i] == 0xFF, 0)) { - bit_sets[i] = 0; - if (__builtin_expect(i + 1 == bit_sets_n, 0)) { - /* If we have run out of state, there is no solution. */ - printf("UNSATISFIABLE\n"); - exit(0); - } - next_bitset(i + 1); - } else { - bit_sets[i]++; - if (i + 1 == bit_sets_n) { - if (__builtin_expect(bit_sets[i] == (1 << variables), 0)) { - /* If we have run out of state, there is no solution. */ - printf("UNSATISFIABLE\n"); - exit(0); - } - } - } -} - -/* - * We can determine if a clause is true by - * running through each of the values in it and checking - * if any of them are true (as a clause is a set of ORs) - */ -inline uint8_t is_clause_true(uint64_t i) { - list_t * clause = clauses[i]; - - foreach(node, clause) { - intptr_t var = (intptr_t)node->value; - if (var < 0) { - if (!checkbit(-var - 1)) return 1; - } else { - if (checkbit(var - 1)) return 1; - } - } - - return 0; -} - -inline uint8_t solved_with_bitset() { - for (uint64_t i = 0; i < clause_n; ++i) { - if (!is_clause_true(i)) { - /* If any clause is not true, the entire statement - * is false for this state */ - return 0; - } - } - /* If all of the clauses are true, we are done. */ - return 1; -} - -/* Read a line of input and process it */ -int read_line() { - char c = fgetc(stdin); - switch (c) { - case 'c': - /* Comment */ - while (fgetc(stdin) != '\n'); - break; - case 'p': - /* Problem definition */ - { - fgetc(stdin); - while (fgetc(stdin) != ' '); - char num[30]; - int offset = 0; - char input; - while ((input = fgetc(stdin)) != ' ') { - num[offset] = input; - offset++; - } - num[offset] = '\0'; - variables = atoi(num); - offset = 0; - while ((input = fgetc(stdin)) != '\n') { - num[offset] = input; - offset++; - } - num[offset] = '\0'; - clause_n = atoi(num); - clauses = malloc(sizeof(list_t *) * clause_n); - setup_bitsets(); -#if DEBUG - fprintf(stderr, "%ld variables, %ld clauses\n", variables, clause_n); -#endif - } - break; - default: - /* Clause */ - { - assert(variables > 0); - assert(clauses > 0); - - ungetc(c, stdin); - - clauses[collected] = list_create(); - char * line = malloc(LINE_WIDTH); - fgets(line, LINE_WIDTH - 1, stdin); - if (line[strlen(line) - 1] == '\n') { - line[strlen(line) - 1] = '\0'; - } - -#if DEBUG - fprintf(stderr, "Preparing to add clause %ld: %s\n", collected, line); -#endif - - char *p, *last; - for ((p = strtok_r(line, " ", &last)); ; - (p = strtok_r(NULL, " ", &last))) { - int var = atoi(p); - if (var == 0) break; - uintptr_t x = var; - list_insert(clauses[collected], (void *)x); - } - free(line); - -#if DEBUG - fprintf(stderr, "Added clause.\n"); -#endif - - collected++; - if (collected == clause_n) return 0; - } - break; - } - return 1; -} - -int main(int argc, char * argv[]) { - /* Read the CNF file from standard in and process it into clauses */ - while (read_line()); - -#if DEBUG - /* Debug: Print out the clauses */ - for (uint32_t i = 0; i < clause_n; ++i) { - list_t * clause = clauses[i]; - fprintf(stderr, "[clause #%d] ", (i + 1)); - foreach(node, clause) { - fprintf(stderr, "%ld ", (uintptr_t)node->value); - } - fprintf(stderr, "\n"); - } - - /* Print out variable information */ - fprintf(stderr, "%ld variables to check, which means %d combinations to bruteforce.\n", variables, 1 << variables); -#endif - - /* Brute force! */ - while (!solved_with_bitset()) { - next_bitset(0); - } - - /* If we get to this point, we have a solution. */ - for (uint64_t i = 0; i < variables; ++i) { - /* Print the state of each variable. */ - if (checkbit(i)) { - printf("%ld", i + 1); - } else { - printf("-%ld", i + 1); - } - if (i != variables - 1) { - printf(" "); - } else { - printf("\n"); - } - } - -} diff --git a/userspace/extra/stty.c b/userspace/extra/stty.c deleted file mode 100644 index 46a6f95d..00000000 --- a/userspace/extra/stty.c +++ /dev/null @@ -1,1294 +0,0 @@ -/* - * This is the Minix implementation of stty. - * - * Author: Andy Tanenbaum - * Adapted to POSIX 1003.2 by: Philip Homburg - * - * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The - * Netherlands All rights reserved. Redistribution and use of the MINIX 3 - * operating system in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. Redistributions in binary - * form must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. Neither the name of the Vrije Universiteit - * nor the names of the software authors or contributors may be used to - * endorse or promote products derived from this software without specific - * prior written permission. Any deviations from these conditions require - * written permission from the copyright holder in advance - */ - -#ifdef __minix_vmd -#define _MINIX_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#ifdef __minix -#include -#include -#endif -#ifdef __NBSD_LIBC -#include -#endif - -/* Default settings, the Minix ones are defined in */ - -#ifndef TCTRL_DEF -#define TCTRL_DEF (PARENB | CREAD | CS7) -#endif - -#ifndef TSPEED_DEF -#define TSPEED_DEF B1200 -#endif - -#ifndef TINPUT_DEF -#define TINPUT_DEF (BRKINT | IGNPAR | ISTRIP | ICRNL) -#endif - -#ifndef TOUTPUT_DEF -#define TOUTPUT_DEF OPOST -#endif - -#ifndef TLOCAL_DEF -#define TLOCAL_DEF (ISIG | IEXTEN | ICANON | ECHO | ECHOE) -#endif - -#ifndef TEOF_DEF -#define TEOF_DEF '\4' /* ^D */ -#endif -#ifndef TEOL_DEF -#ifdef _POSIX_VDISABLE -#define TEOL_DEF _POSIX_VDISABLE -#else -#define TEOL_DEF '\n' -#endif -#endif -#ifndef TERASE_DEF -#define TERASE_DEF '\10' /* ^H */ -#endif -#ifndef TINTR_DEF -#define TINTR_DEF '\177' /* ^? */ -#endif -#ifndef TKILL_DEF -#define TKILL_DEF '\25' /* ^U */ -#endif -#ifndef TQUIT_DEF -#define TQUIT_DEF '\34' /* ^\ */ -#endif -#ifndef TSUSP_DEF -#define TSUSP_DEF '\32' /* ^Z */ -#endif -#ifndef TSTART_DEF -#define TSTART_DEF '\21' /* ^Q */ -#endif -#ifndef TSTOP_DEF -#define TSTOP_DEF '\23' /* ^S */ -#endif -#ifndef TMIN_DEF -#define TMIN_DEF 1 -#endif -#ifndef TTIME_DEF -#define TTIME_DEF 0 -#endif - - - -char *prog_name; -struct termios termios; -int column= 0, max_column=80; /* Assume 80 character terminals. */ -#ifdef __minix -struct winsize winsize; -#endif - -#define PROTO(a) a - -int main PROTO(( int argc, char **argv )); -void report PROTO(( int flags )); -int option PROTO(( char *opt, char *next )); -int match PROTO(( char *s1, char *s2 )); -void prctl PROTO(( int c )); -speed_t long2speed PROTO(( long num )); -long speed2long PROTO(( unsigned long speed )); -void print_flags PROTO(( unsigned long flags, unsigned long flag, - unsigned long def, char *string, int all )); -void output PROTO(( char *s )); -void do_print_char PROTO(( unsigned chr, unsigned def, char *name, int all )); -void do_print_num PROTO(( unsigned num, unsigned def, char *name, int all )); -void set_saved_settings PROTO(( char *opt )); -void set_control PROTO(( int option, char *value )); -void set_min_tim PROTO(( int option, char *value )); - -#define print_char(c,d,n,a) (do_print_char((unsigned)(c),(unsigned)(d),(n),(a))) -#define print_num(m,d,n,a) (do_print_num((unsigned)(m),(unsigned)(d),(n),(a))) - -int main(argc, argv) -int argc; -char *argv[]; -{ - int flags, k; - - prog_name= argv[0]; - flags= 0; - - /* Stty with no arguments just reports on current status. */ - if (tcgetattr(0, &termios) == -1) - { - fprintf(stderr, "%s: can't read ioctl parameters from stdin: %s\n", - prog_name, strerror(errno)); - exit(1); - } -#ifdef __minix - if (ioctl(0, TIOCGWINSZ, &winsize) == -1) - { - fprintf(stderr, "%s: can't get screen size from stdin: %s\n", - prog_name, strerror(errno)); - exit(1); - } - if (winsize.ws_col != 0) - max_column= winsize.ws_col; -#endif - - if (argc == 2) - { - if (!strcmp(argv[1], "-a")) - flags |= 1; - else if (!strcmp(argv[1], "-g")) - flags |= 2; - } - if (argc == 1 || flags) { - report(flags); - exit(0); - } - - /* Process the options specified. */ - for (k= 1; k < argc; k++) - k += option(argv[k], k+1 < argc ? argv[k+1] : ""); - -#ifdef __minix - if (ioctl(0, TIOCSWINSZ, &winsize) == -1) - { - fprintf(stderr, "%s: can't set screen size to stdin: %s\n", - prog_name, strerror(errno)); - exit(1); - } -#endif - if (tcsetattr(0, TCSANOW, &termios) == -1) - { - fprintf(stderr, "%s: can't set terminal parameters to stdin: %s\n", - prog_name, strerror(errno)); - exit(1); - } - exit(0); -} - - - -void report(flags) -int flags; -{ - int i, all; - tcflag_t c_cflag, c_iflag, c_oflag, c_lflag; - char line[80]; - speed_t ispeed, ospeed; - - if (flags & 2) - { /* We have to write the termios structure in a encoded form - * to stdout. - */ - printf(":%x:%x:%x:%x:%x:%x", termios.c_iflag, termios.c_oflag, - termios.c_cflag, termios.c_lflag, cfgetispeed(&termios), - cfgetospeed(&termios)); - for (i= 0; ins == num) return sp->ts; - } - return -1; -} - -long speed2long(speed) -unsigned long speed; -{ - struct s2s *sp; - - for (sp = s2s; sp < s2s + (sizeof(s2s) / sizeof(s2s[0])); sp++) { - if (sp->ts == speed) return sp->ns; - } - return -1; -} - -void print_flags(flags, flag, def, string, all) -unsigned long flags; -unsigned long flag; -unsigned long def; -char *string; -int all; -{ - if (!(flags & flag)) - { - if (all || (def & flag)) - output(string); - return; - } - string++; - if (all || !(def & flag)) - output(string); -} - -void output(s) -char *s; -{ - int len; - - len= strlen(s); - if (column + len + 3 >= max_column) - { - printf("\n"); - column= 0; - } - if (column) - { - putchar(' '); - column++; - } - fputs(s, stdout); - column += len; -} - -void do_print_char(chr, def, name, all) -unsigned chr; -unsigned def; -char *name; -int all; -{ - char line[20]; - - if (!all && chr == def) - return; - -#ifdef _POSIX_VDISABLE - if (chr == _POSIX_VDISABLE) - sprintf(line, "%s = ", name); - else -#endif - if (chr < ' ') - sprintf(line, "%s = ^%c", name, chr + '@'); - else if (chr == 127) - sprintf(line, "%s = ^?", name); - else - sprintf(line, "%s = %c", name, chr); - output(line); -} - -void do_print_num(num, def, name, all) -unsigned num; -unsigned def; -char *name; -int all; -{ - char line[20]; - - if (!all && num == def) - return; - sprintf(line, "%s = %u", name, num); - output(line); -} - -void set_saved_settings(opt) -char *opt; -{ - long num; - char *check; - tcflag_t c_oflag, c_cflag, c_lflag, c_iflag; - cc_t c_cc[NCCS]; - speed_t ispeed, ospeed; - int i; - - check= opt; - num= strtol(check+1, &check, 16); - if (check[0] != ':') - { - fprintf(stderr, "error in saved settings '%s'\n", opt); - return; - } - c_iflag= num; - - num= strtol(check+1, &check, 16); - if (check[0] != ':') - { - fprintf(stderr, "error in saved settings '%s'\n", opt); - return; - } - c_oflag= num; - - num= strtol(check+1, &check, 16); - if (check[0] != ':') - { - fprintf(stderr, "error in saved settings '%s'\n", opt); - return; - } - c_cflag= num; - - num= strtol(check+1, &check, 16); - if (check[0] != ':') - { - fprintf(stderr, "error in saved settings '%s'\n", opt); - return; - } - c_lflag= num; - - num= strtol(check+1, &check, 16); - if (check[0] != ':') - { - fprintf(stderr, "error in saved settings '%s'\n", opt); - return; - } - ispeed= num; - - num= strtol(check+1, &check, 16); - if (check[0] != ':') - { - fprintf(stderr, "error in saved settings '%s'\n", opt); - return; - } - ospeed= num; - - for(i=0; i= 32) { - fprintf(stderr, "stty: illegal option value: '%s'\n", - value); - return; - } - } else if (strlen(value) == 1) - chr= value[0]; - else { - fprintf(stderr, "stty: illegal option value: '%s'\n", value); - return; - } - - assert(option >= 0 && option < NCCS); - termios.c_cc[option]= chr; -} - -void set_min_tim(option, value) -int option; -char *value; -{ - long num; - char *check; - - num= strtol(value, &check, 0); - if (check[0] != '\0') { - fprintf(stderr, "stty: illegal option value: '%s'\n", value); - return; - } - - if ((cc_t)num != num) { - fprintf(stderr, "stty: illegal option value: '%s'\n", value); - return; - } - assert(option >= 0 && option < NCCS); - termios.c_cc[option]= num; -} - -/* - * $PchId: stty.c,v 1.7 2001/05/02 15:04:42 philip Exp $ - */ diff --git a/userspace/extra/toast.c b/userspace/extra/toast.c deleted file mode 100644 index 3a637bcb..00000000 --- a/userspace/extra/toast.c +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include - -#include "lib/pex.h" -#include "lib/toastd.h" - -int main(int argc, char * argv[]) { - if (argc < 3) { - fprintf(stderr, "%s: \"title\" \"message\"\n", argv[0]); - return 1; - } - - char * server = getenv("TOASTD"); - - if (!server) { - server = "toastd"; /* Appropriate fallback */ - } - - FILE * c = pex_connect(server); - - if (!c) { - fprintf(stderr, "%s: Could not connect to toast daemon.\n", argv[0]); - return 1; - } - - int size = strlen(argv[1]) + strlen(argv[2]) + 2 + sizeof(notification_t); - - notification_t * note = malloc(size); - - note->ttl = 5; /* seconds */ - - memcpy(note->strings, argv[1], strlen(argv[1])+1); - memcpy(note->strings + strlen(argv[1])+1, argv[2], strlen(argv[2])+1); - - pex_reply(c, size, (void*)note); - - return 0; -} diff --git a/userspace/extra/ungz.c b/userspace/extra/ungz.c deleted file mode 100644 index 1f1e6b63..00000000 --- a/userspace/extra/ungz.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Really dumb wrapper around gzopen/gzread - */ -#include -#include -#include -#include - -int main(int argc, char **argv) -{ - int ret; - - if (argc < 2) { - fprintf(stderr, "Usage: %s file.gz\n", argv[0]); - return 1; - } - - if (strstr(argv[1],".gz") != (argv[1] + strlen(argv[1]) - 3)) { - fprintf(stderr, "%s: Not sure if this file is gzipped. Try renaming it to include `.gz' at the end.\n", argv[0]); - return 1; - } - - gzFile src = gzopen(argv[1], "r"); - - if (!src) return 1; - - char * dest_name = strdup(argv[1]); - char * t = strstr(dest_name,".gz"); - *t = '\0'; - - FILE * dest = fopen(dest_name, "w"); - - if (!dest) return 1; - - while (!gzeof(src)) { - char buf[1024]; - int r = gzread(src, buf, 1024); - fwrite(buf, r, 1, dest); - } - - fclose(dest); - - unlink(argv[1]); - - return 0; -} diff --git a/userspace/extra/verify-write.c b/userspace/extra/verify-write.c deleted file mode 100644 index 0ca5e686..00000000 --- a/userspace/extra/verify-write.c +++ /dev/null @@ -1,48 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * verify-write - * - * A dangerous tool to write to a file and verified it worked. - */ -#include -#include - -#define CHUNK_SIZE 1024 - -int main(int argc, char * argv[]) { - if (argc < 3) { - printf("Expected two arguments, the file to read, and the filename to write out to.\nTry again, maybe?\n"); - return -1; - } - FILE * input = fopen(argv[1], "r"); - FILE * output = fopen(argv[2], "w"); - size_t length; - - fseek(input, 0, SEEK_END); - length = ftell(input); - fseek(input, 0, SEEK_SET); - - char buf[CHUNK_SIZE]; - while (length > CHUNK_SIZE) { - fread( buf, 1, CHUNK_SIZE, input); - fwrite(buf, 1, CHUNK_SIZE, output); - fflush(output); - length -= CHUNK_SIZE; - } - if (length > 0) { - fread( buf, 1, length, input); - fwrite(buf, 1, length, output); - fflush(output); - } - - fclose(output); - fclose(input); - - char * args[] = {"/bin/compare", argv[1], argv[2], NULL }; - execvp(args[0], args); - - return 0; -} diff --git a/userspace/gui/basic/drawlines.c b/userspace/gui/basic/drawlines.c deleted file mode 100644 index a12da8cb..00000000 --- a/userspace/gui/basic/drawlines.c +++ /dev/null @@ -1,95 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* - * drawlines - * - * Test application to draw lines to a window. - */ -#include -#include -#include -#include - -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/pthread.h" - -static int left, top, width, height; - -static yutani_t * yctx; -static yutani_window_t * wina; -static gfx_context_t * ctx; -static int should_exit = 0; - -static int32_t min(int32_t a, int32_t b) { - return (a < b) ? a : b; -} - -static int32_t max(int32_t a, int32_t b) { - return (a > b) ? a : b; -} - -void * draw_thread(void * garbage) { - (void)garbage; - while (!should_exit) { - draw_line(ctx, rand() % width, rand() % width, rand() % height, rand() % height, rgb(rand() % 255,rand() % 255,rand() % 255)); - yutani_flip(yctx, wina); - usleep(16666); - } - pthread_exit(0); -} - -int main (int argc, char ** argv) { - left = 100; - top = 100; - width = 500; - height = 500; - - yctx = yutani_init(); - wina = yutani_window_create(yctx, width, height); - yutani_window_move(yctx, wina, left, top); - yutani_window_advertise_icon(yctx, wina, "drawlines", "drawlines"); - - ctx = init_graphics_yutani(wina); - draw_fill(ctx, rgb(0,0,0)); - - pthread_t thread; - pthread_create(&thread, NULL, draw_thread, NULL); - - while (!should_exit) { - yutani_msg_t * m = yutani_poll(yctx); - if (m) { - switch (m->type) { - case YUTANI_MSG_KEY_EVENT: - { - struct yutani_msg_key_event * ke = (void*)m->data; - if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { - should_exit = 1; - syscall_yield(); - } - } - break; - case YUTANI_MSG_WINDOW_MOUSE_EVENT: - { - struct yutani_msg_window_mouse_event * me = (void*)m->data; - if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { - yutani_window_drag_start(yctx, wina); - } - } - break; - case YUTANI_MSG_SESSION_END: - should_exit = 1; - break; - default: - break; - } - } - free(m); - } - - yutani_close(yctx, wina); - - return 0; -} diff --git a/userspace/gui/basic/yutani-query.c b/userspace/gui/basic/yutani-query.c deleted file mode 100644 index dbd0cbb2..00000000 --- a/userspace/gui/basic/yutani-query.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include - -#include "lib/yutani.h" -#include "lib/shmemfonts.h" - -yutani_t * yctx; - -void show_usage(int argc, char * argv[]) { - printf( - "yutani-query - show misc. information about the display system\n" - "\n" - "usage: %s [-rfm?]\n" - "\n" - " -r \033[3mprint display resoluton\033[0m\n" - " -f \033[3mprint the name of the default font\033[0m\n" - " -m \033[3mprint the name of the monospace font\033[0m\n" - " -? \033[3mshow this help text\033[0m\n" - "\n", argv[0]); -} - -int show_resolution(void) { - printf("%dx%d\n", yctx->display_width, yctx->display_height); - return 0; -} - -int show_fontname(int font) { - init_shmemfonts(); - printf("%s\n", shmem_font_name(font)); - return 0; -} - -int main(int argc, char * argv[]) { - yctx = yutani_init(); - if (!yctx) { - printf("(not connected)\n"); - return 1; - } - if (argc > 1) { - int index, c; - while ((c = getopt(argc, argv, "rfm?")) != -1) { - switch (c) { - case 'r': - return show_resolution(); - case 'f': - return show_fontname(FONT_SANS_SERIF); - case 'm': - return show_fontname(FONT_MONOSPACE); - case '?': - show_usage(argc, argv); - return 0; - } - } - } - - return 0; -} diff --git a/userspace/gui/compositor/yutani_int.h b/userspace/gui/compositor/yutani_int.h deleted file mode 100644 index 9373ba0f..00000000 --- a/userspace/gui/compositor/yutani_int.h +++ /dev/null @@ -1,190 +0,0 @@ -#pragma once - -#include -#include "lib/yutani.h" -#include "lib/list.h" -#include "lib/hashmap.h" -#include "lib/graphics.h" -#include "lib/kbd.h" - -#define MOUSE_SCALE 3 -#define MOUSE_OFFSET_X 26 -#define MOUSE_OFFSET_Y 26 - -#define YUTANI_BYTE_DEPTH 4 - -#define YUTANI_SCREENSHOT_FULL 1 -#define YUTANI_SCREENSHOT_WINDOW 2 - -typedef enum { - YUTANI_EFFECT_NONE, - YUTANI_EFFECT_FADE_IN, - YUTANI_EFFECT_FADE_OUT, - YUTANI_EFFECT_MINIMIZE, - YUTANI_EFFECT_UNMINIMIZE, -} yutani_effect; - -static int yutani_animation_lengths[] = { - 0, - 200, - 200, - 0, - 0, -}; - -typedef struct { - yutani_wid_t wid; - - signed long x; - signed long y; - unsigned short z; - - int32_t width; - int32_t height; - - uint8_t * buffer; - uint32_t bufid; - - uint32_t owner; - - int16_t rotation; - - uint32_t newbufid; - uint8_t * newbuffer; - - uint32_t client_flags; - uint16_t client_offsets[5]; - uint32_t client_length; - char * client_strings; - - int anim_mode; - uint32_t anim_start; - - int alpha_threshold; - int show_mouse; - - int tiled; - int32_t untiled_width; - int32_t untiled_height; - - int default_mouse; - uint32_t server_flags; - - int opacity; -} yutani_server_window_t; - -typedef struct { - /* XXX multiple displays */ - unsigned int width; - unsigned int height; - - cairo_surface_t * framebuffer_surface; - cairo_surface_t * real_surface; - cairo_t * framebuffer_ctx; - cairo_t * real_ctx; - - void * backend_framebuffer; - gfx_context_t * backend_ctx; - - signed int mouse_x; - signed int mouse_y; - - signed int last_mouse_x; - signed int last_mouse_y; - - list_t * windows; - hashmap_t * wids_to_windows; - - yutani_server_window_t * bottom_z; - list_t * mid_zs; - yutani_server_window_t * top_z; - - list_t * update_list; - volatile int update_list_lock; - - sprite_t mouse_sprite; - - char * server_ident; - - yutani_server_window_t * focused_window; - FILE * server; - - int mouse_state; - yutani_server_window_t * mouse_window; - - int mouse_win_x; - int mouse_win_y; - int mouse_init_x; - int mouse_init_y; - int mouse_init_r; - - int mouse_drag_button; - int mouse_moved; - - int32_t mouse_click_x; - int32_t mouse_click_y; - - key_event_state_t kbd_state; - - yutani_server_window_t * resizing_window; - int32_t resizing_w; - int32_t resizing_h; - - list_t * window_subscribers; - - uint32_t start_time; - - volatile int redraw_lock; - - yutani_server_window_t * old_hover_window; - - hashmap_t * key_binds; - - list_t * windows_to_remove; - - yutani_t * host_context; - yutani_window_t * host_window; - - hashmap_t * clients_to_windows; - - int debug_bounds; - int debug_shapes; - - int screenshot_frame; - - uint32_t start_subtime; - - yutani_scale_direction_t resizing_direction; - int32_t resizing_offset_x; - int32_t resizing_offset_y; - int resizing_button; - - sprite_t mouse_sprite_drag; - sprite_t mouse_sprite_resize_v; - sprite_t mouse_sprite_resize_h; - sprite_t mouse_sprite_resize_da; - sprite_t mouse_sprite_resize_db; - - int current_cursor; - int resize_on_next; - - uint32_t timer_precison; - list_t * timer_subscribers; - - uint32_t last_mouse_buttons; - - uint32_t stride; - - int32_t mouse_click_x_orig; - int32_t mouse_click_y_orig; -} yutani_globals_t; - -struct key_bind { - unsigned int owner; - int response; -}; - -static void mark_window(yutani_globals_t * yg, yutani_server_window_t * window); -static void window_actually_close(yutani_globals_t * yg, yutani_server_window_t * w); -static void notify_subscribers(yutani_globals_t * yg); - diff --git a/userspace/gui/demo/cairo-demo.c b/userspace/gui/demo/cairo-demo.c deleted file mode 100644 index 772c8d16..00000000 --- a/userspace/gui/demo/cairo-demo.c +++ /dev/null @@ -1,99 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -#include -#include -#include - -#include "lib/yutani.h" -#include "lib/graphics.h" - -static yutani_t * yctx; -static yutani_window_t * window; -static gfx_context_t * ctx; - -void render() { - draw_fill(ctx, rgba(0,0,0,127)); - - int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, window->width); - cairo_surface_t * surface = cairo_image_surface_create_for_data(ctx->buffer, CAIRO_FORMAT_ARGB32, window->width, window->height, stride); - cairo_t * cr = cairo_create(surface); - - cairo_set_line_width (cr, 6); - - cairo_rectangle (cr, 12, 12, 232, 70); - cairo_new_sub_path (cr); cairo_arc (cr, 64, 64, 40, 0, 2*M_PI); - cairo_new_sub_path (cr); cairo_arc_negative (cr, 192, 64, 40, 0, -2*M_PI); - - cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); - cairo_set_source_rgb (cr, 0, 0.7, 0); cairo_fill_preserve (cr); - cairo_set_source_rgb (cr, 0, 0, 0); cairo_stroke (cr); - - cairo_translate (cr, 0, 128); - cairo_rectangle (cr, 12, 12, 232, 70); - cairo_new_sub_path (cr); cairo_arc (cr, 64, 64, 40, 0, 2*M_PI); - cairo_new_sub_path (cr); cairo_arc_negative (cr, 192, 64, 40, 0, -2*M_PI); - - cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); - cairo_set_source_rgb (cr, 0, 0, 0.9); cairo_fill_preserve (cr); - cairo_set_source_rgb (cr, 0, 0, 0); cairo_stroke (cr); - - cairo_surface_flush(surface); - cairo_destroy(cr); - cairo_surface_flush(surface); - cairo_surface_destroy(surface); - - yutani_flip(yctx, window); -} - -int main(int argc, char * argv[]) { - - int width = 500; - int height = 500; - - yctx = yutani_init(); - window = yutani_window_create(yctx,500,500); - yutani_window_move(yctx, window, 100, 100); - ctx = init_graphics_yutani(window); - draw_fill(ctx, rgba(0,0,0,127)); - - yutani_window_advertise_icon(yctx, window, "Cairo Demo", "cairo-demo"); - - render(); - - while (1) { - yutani_msg_t * m = yutani_poll(yctx); - if (m) { - switch (m->type) { - case YUTANI_MSG_KEY_EVENT: - { - struct yutani_msg_key_event * ke = (void*)m->data; - if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { - free(m); - goto done; - } - } - break; - case YUTANI_MSG_WINDOW_MOUSE_EVENT: - { - struct yutani_msg_window_mouse_event * me = (void*)m->data; - if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { - yutani_window_drag_start(yctx, window); - } - } - break; - case YUTANI_MSG_SESSION_END: - goto done; - default: - break; - } - } - free(m); - } - -done: - yutani_close(yctx, window); - - return 0; -} diff --git a/userspace/gui/demo/make-it-snow.c b/userspace/gui/demo/make-it-snow.c deleted file mode 100644 index 5d9a9a1b..00000000 --- a/userspace/gui/demo/make-it-snow.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * This is a port of some code from a Wayland drag-drop demo. - * - * Copyright (C) 2010 Kristian Høgsberg - * Copyright (C) 2013-2014 Kevin Lange - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - - -#include -#include -#include -#include - -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/pthread.h" -#include "lib/list.h" - -static yutani_t * yctx; -static yutani_window_t * window; -static gfx_context_t * ctx; -static int should_exit = 0; - -static list_t * snowflakes; - -static int width, height; - -struct snowflake { - int x; - int y; - cairo_surface_t * surface; -}; - -#define random rand -#define item_width 64 -#define item_height 64 - -static int windspeed = 2; -static int gravity = 5; - -static struct snowflake * create_snowflake() { - - struct snowflake * item = malloc(sizeof(struct snowflake)); - - item->x = random() % width; - item->y = random() % height; - - const int petal_count = 3 + random() % 5; - const double r1 = 20 + random() % 10; - const double r2 = 5 + random() % 12; - const double u = (10 + random() % 90) / 100.0; - const double v = (random() % 90) / 100.0; - - cairo_t *cr; - int i; - double t, dt = 2 * M_PI / (petal_count * 2); - double x1, y1, x2, y2, x3, y3; - - item->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, item_width, item_height); - - cr = cairo_create(item->surface); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba(cr, 0, 0, 0, 0); - cairo_paint(cr); - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_translate(cr, item_width / 2, item_height / 2); - t = random(); - cairo_move_to(cr, cos(t) * r1, sin(t) * r1); - for (i = 0; i < petal_count; i++, t += dt * 2) { - x1 = cos(t) * r1; - y1 = sin(t) * r1; - x2 = cos(t + dt) * r2; - y2 = sin(t + dt) * r2; - x3 = cos(t + 2 * dt) * r1; - y3 = sin(t + 2 * dt) * r1; - - cairo_curve_to(cr, - x1 - y1 * u, y1 + x1 * u, - x2 + y2 * v, y2 - x2 * v, - x2, y2); - - cairo_curve_to(cr, - x2 - y2 * v, y2 + x2 * v, - x3 + y3 * u, y3 - x3 * u, - x3, y3); - } - - cairo_close_path(cr); - - cairo_set_source_rgba(cr, - 0.5 + (random() % 50) / 49.0, - 0.5 + (random() % 50) / 49.0, - 0.5 + (random() % 50) / 49.0, - 0.5 + (random() % 100) / 99.0); - - cairo_fill_preserve(cr); - - cairo_set_line_width(cr, 1); - cairo_set_source_rgba(cr, - 0.5 + (random() % 50) / 49.0, - 0.5 + (random() % 50) / 49.0, - 0.5 + (random() % 50) / 49.0, - 0.5 + (random() % 100) / 99.0); - cairo_stroke(cr); - - cairo_destroy(cr);; - - return item; -} - -static void render() { - /* Clear window */ - draw_fill(ctx, rgba(0,0,0,0)); - - /* Set up cairo context */ - int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, window->width); - cairo_surface_t * surface = cairo_image_surface_create_for_data(ctx->backbuffer, CAIRO_FORMAT_ARGB32, window->width, window->height, stride); - cairo_t * cr = cairo_create(surface); - - /* Draw some snowflakes */ - foreach(node, snowflakes) { - struct snowflake * item = node->value; - cairo_save(cr); - - cairo_set_source_surface(cr, item->surface, item->x, item->y); - cairo_paint(cr); - - item->x += windspeed; - item->y += gravity; - - if (item->y > height + item_height) { - item->y = -item_height; - } - if (item->x > width + item_width) { - item->x = -item_width; - } - - cairo_restore(cr); - } - - cairo_surface_flush(surface); - cairo_destroy(cr); - cairo_surface_flush(surface); - cairo_surface_destroy(surface); - - flip(ctx); -} - -void * draw_thread(void * garbage) { - (void)garbage; - while (!should_exit) { - render(); - yutani_flip(yctx, window); - syscall_yield(); - } - pthread_exit(0); -} - -int main(int argc, char * argv[]) { - - yctx = yutani_init(); - - width = yctx->display_width; - height = yctx->display_height; - - window = yutani_window_create(yctx,width,height); - ctx = init_graphics_yutani_double_buffer(window); - draw_fill(ctx, rgba(0,0,0,0)); - flip(ctx); - yutani_flip(yctx, window); - yutani_window_advertise_icon(yctx, window, "Cairo Snow Demo", "snow"); - - snowflakes = list_create(); - for (int i = 0; i < 100; ++i) { - list_insert(snowflakes, create_snowflake()); - } - - pthread_t thread; - pthread_create(&thread, NULL, draw_thread, NULL); - - while (!should_exit) { - yutani_msg_t * m = yutani_poll(yctx); - if (m) { - switch (m->type) { - case YUTANI_MSG_KEY_EVENT: - { - struct yutani_msg_key_event * ke = (void*)m->data; - if (ke->event.action == KEY_ACTION_DOWN) { - switch (ke->event.keycode) { - case 'q': - should_exit = 1; - free(m); - goto finish; - } - } - } - break; - case YUTANI_MSG_SESSION_END: - should_exit = 1; - goto finish; - default: - break; - } - free(m); - } - } - - -finish: - yutani_close(yctx, window); - - return 0; -} diff --git a/userspace/gui/demo/pixman-demo.c b/userspace/gui/demo/pixman-demo.c deleted file mode 100644 index 04978fc5..00000000 --- a/userspace/gui/demo/pixman-demo.c +++ /dev/null @@ -1,124 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -#include -#include - -#include "lib/yutani.h" -#include "lib/graphics.h" - -static yutani_t * yctx; -static yutani_window_t * window; -static gfx_context_t * ctx; - -int main(int argc, char * argv[]) { - -#define WIDTH 400 -#define HEIGHT 400 -#define TILE_SIZE 25 - - yctx = yutani_init(); - window = yutani_window_create(yctx,WIDTH,HEIGHT); - yutani_window_move(yctx, window, 100, 100); - ctx = init_graphics_yutani(window); - draw_fill(ctx, rgba(0,0,0,255)); - - yutani_window_advertise_icon(yctx, window, "pixman Demo", "pixman-demo"); - - pixman_image_t *checkerboard; - pixman_image_t *destination; -#define D2F(d) (pixman_double_to_fixed(d)) - pixman_transform_t trans = { { - { D2F (-1.96830), D2F (-1.82250), D2F (512.12250)}, - { D2F (0.00000), D2F (-7.29000), D2F (1458.00000)}, - { D2F (0.00000), D2F (-0.00911), D2F (0.59231)}, - }}; - int i, j; - - checkerboard = pixman_image_create_bits (PIXMAN_a8r8g8b8, - WIDTH, HEIGHT, - NULL, 0); - - destination = pixman_image_create_bits (PIXMAN_a8r8g8b8, - WIDTH, HEIGHT, - NULL, 0); - - for (i = 0; i < HEIGHT / TILE_SIZE; ++i) - { - for (j = 0; j < WIDTH / TILE_SIZE; ++j) - { - double u = (double)(j + 1) / (WIDTH / TILE_SIZE); - double v = (double)(i + 1) / (HEIGHT / TILE_SIZE); - pixman_color_t black = { 0, 0, 0, 0xffff }; - pixman_color_t white = { - v * 0xffff, - u * 0xffff, - (1 - (double)u) * 0xffff, - 0xffff }; - pixman_color_t *c; - pixman_image_t *fill; - - if ((j & 1) != (i & 1)) - c = &black; - else - c = &white; - - fill = pixman_image_create_solid_fill (c); - - pixman_image_composite (PIXMAN_OP_SRC, fill, NULL, checkerboard, - 0, 0, 0, 0, j * TILE_SIZE, i * TILE_SIZE, - TILE_SIZE, TILE_SIZE); - } - } - - pixman_image_set_transform (checkerboard, &trans); - pixman_image_set_filter (checkerboard, PIXMAN_FILTER_BEST, NULL, 0); - pixman_image_set_repeat (checkerboard, PIXMAN_REPEAT_NONE); - - pixman_image_composite (PIXMAN_OP_SRC, - checkerboard, NULL, destination, - 0, 0, 0, 0, 0, 0, - WIDTH, HEIGHT); - - printf("Going for native draw.\n"); - - uint32_t * buf = pixman_image_get_data(destination); - memcpy(ctx->buffer,buf,WIDTH*HEIGHT*4); - - yutani_flip(yctx, window); - - while (1) { - yutani_msg_t * m = yutani_poll(yctx); - if (m) { - switch (m->type) { - case YUTANI_MSG_KEY_EVENT: - { - struct yutani_msg_key_event * ke = (void*)m->data; - if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { - free(m); - goto done; - } - } - break; - case YUTANI_MSG_WINDOW_MOUSE_EVENT: - { - struct yutani_msg_window_mouse_event * me = (void*)m->data; - if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { - yutani_window_drag_start(yctx, window); - } - } - break; - case YUTANI_MSG_SESSION_END: - goto done; - default: - break; - } - } - free(m); - } - -done: - yutani_close(yctx, window); - return 0; -} diff --git a/userspace/gui/lib/decor-fancy.c b/userspace/gui/lib/decor-fancy.c deleted file mode 100644 index 1318d820..00000000 --- a/userspace/gui/lib/decor-fancy.c +++ /dev/null @@ -1,144 +0,0 @@ -#include - -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/shmemfonts.h" -#include "lib/decorations.h" - -#define INACTIVE 9 - -#define TTK_FANCY_PATH "/usr/share/ttk/" - -static int u_height = 33; -static int ul_width = 10; -static int ur_width = 10; -static int ml_width = 6; -static int mr_width = 6; -static int l_height = 9; -static int ll_width = 9; -static int lr_width = 9; -static int llx_offset = 3; -static int lly_offset = 3; -static int lrx_offset = 3; -static int lry_offset = 3; - -static sprite_t * sprites[20]; - -#define TEXT_OFFSET 24 - -static void init_sprite_png(int id, char * path) { - sprites[id] = malloc(sizeof(sprite_t)); - load_sprite_png(sprites[id], path); -} - -static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * ctx, char * title, int decors_active) { - int width = window->width; - int height = window->height; - - for (int j = 0; j < decor_top_height; ++j) { - for (int i = 0; i < width; ++i) { - GFX(ctx,i,j) = 0; - } - } - - for (int j = decor_top_height; j < height - decor_bottom_height; ++j) { - for (int i = 0; i < decor_left_width; ++i) { - GFX(ctx,i,j) = 0; - } - for (int i = width - decor_right_width; i < width; ++i) { - GFX(ctx,i,j) = 0; - } - } - - for (int j = height - decor_bottom_height; j < height; ++j) { - for (int i = 0; i < width; ++i) { - GFX(ctx,i,j) = 0; - } - } - - if (decors_active == DECOR_INACTIVE) decors_active = INACTIVE; - - draw_sprite(ctx, sprites[decors_active + 0], 0, 0); - for (int i = 0; i < width - (ul_width + ur_width); ++i) { - draw_sprite(ctx, sprites[decors_active + 1], i + ul_width, 0); - } - draw_sprite(ctx, sprites[decors_active + 2], width - ur_width, 0); - for (int i = 0; i < height - (u_height + l_height); ++i) { - draw_sprite(ctx, sprites[decors_active + 3], 0, i + u_height); - draw_sprite(ctx, sprites[decors_active + 4], width - mr_width, i + u_height); - } - draw_sprite(ctx, sprites[decors_active + 5], 0, height - l_height); - for (int i = 0; i < width - (ll_width + lr_width); ++i) { - draw_sprite(ctx, sprites[decors_active + 6], i + ll_width, height - l_height); - } - draw_sprite(ctx, sprites[decors_active + 7], width - lr_width, height - l_height); - - set_font_face(FONT_SANS_SERIF_BOLD); - set_font_size(12); - - char * tmp_title = strdup(title); - int t_l = strlen(tmp_title); - -#define EXTRA_SPACE 40 - - if (draw_string_width(tmp_title) + EXTRA_SPACE > width) { - while (t_l >= 0 && (draw_string_width(tmp_title) + EXTRA_SPACE > width)) { - tmp_title[t_l] = '\0'; - t_l--; - } - } - - if (strlen(tmp_title)) { - int title_offset = (width / 2) - (draw_string_width(tmp_title) / 2); - if (decors_active == 0) { - draw_string(ctx, title_offset, TEXT_OFFSET, rgb(226,226,226), tmp_title); - } else { - draw_string(ctx, title_offset, TEXT_OFFSET, rgb(147,147,147), tmp_title); - } - } - - free(tmp_title); - - /* Buttons */ - draw_sprite(ctx, sprites[decors_active + 8], width - 28, 16); -} - -static int check_button_press_fancy(yutani_window_t * window, int x, int y) { - if (x >= window->width - 28 && x <= window->width - 18 && - y >= 16 && y <= 26) { - return DECOR_CLOSE; - } - - return 0; -} - -void decor_init() { - init_sprite_png(0, TTK_FANCY_PATH "active/ul.png"); - init_sprite_png(1, TTK_FANCY_PATH "active/um.png"); - init_sprite_png(2, TTK_FANCY_PATH "active/ur.png"); - init_sprite_png(3, TTK_FANCY_PATH "active/ml.png"); - init_sprite_png(4, TTK_FANCY_PATH "active/mr.png"); - init_sprite_png(5, TTK_FANCY_PATH "active/ll.png"); - init_sprite_png(6, TTK_FANCY_PATH "active/lm.png"); - init_sprite_png(7, TTK_FANCY_PATH "active/lr.png"); - init_sprite_png(8, TTK_FANCY_PATH "active/button-close.png"); - - init_sprite_png(INACTIVE + 0, TTK_FANCY_PATH "inactive/ul.png"); - init_sprite_png(INACTIVE + 1, TTK_FANCY_PATH "inactive/um.png"); - init_sprite_png(INACTIVE + 2, TTK_FANCY_PATH "inactive/ur.png"); - init_sprite_png(INACTIVE + 3, TTK_FANCY_PATH "inactive/ml.png"); - init_sprite_png(INACTIVE + 4, TTK_FANCY_PATH "inactive/mr.png"); - init_sprite_png(INACTIVE + 5, TTK_FANCY_PATH "inactive/ll.png"); - init_sprite_png(INACTIVE + 6, TTK_FANCY_PATH "inactive/lm.png"); - init_sprite_png(INACTIVE + 7, TTK_FANCY_PATH "inactive/lr.png"); - init_sprite_png(INACTIVE + 8, TTK_FANCY_PATH "inactive/button-close.png"); - - decor_top_height = 33; - decor_bottom_height = 6; - decor_left_width = 6; - decor_right_width = 6; - - decor_render_decorations = render_decorations_fancy; - decor_check_button_press = check_button_press_fancy; -} - diff --git a/userspace/gui/lib/decor-piecewise.c b/userspace/gui/lib/decor-piecewise.c deleted file mode 100644 index cc1aaf43..00000000 --- a/userspace/gui/lib/decor-piecewise.c +++ /dev/null @@ -1,168 +0,0 @@ -#include - -#include "lib/yutani.h" -#include "lib/graphics.h" -#include "lib/shmemfonts.h" -#include "lib/decorations.h" -#include "lib/confreader.h" - -static int u_height = 3; -static int ul_width = 3; -static int ur_width = 3; - -static int m_height = 3; -static int ml_width = 3; -static int mr_width = 3; - -static int l_height = 3; -static int ll_width = 3; -static int lr_width = 3; - -static int close_top = 0; -static int close_right = 0; -static int close_left = -1; -static int close_bottom = -1; - -static sprite_t * sprites[4]; - -static void init_sprite_png(int id, char * path) { - sprites[id] = malloc(sizeof(sprite_t)); - load_sprite_png(sprites[id], path); -} - -extern uint32_t getBilinearFilteredPixelColor(sprite_t * tex, double u, double v); - -static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * ctx, char * title, int decors_active) { - int width = window->width; - int height = window->height; - - sprite_t * texture = sprites[decors_active == DECOR_ACTIVE ? 0 : 1]; - sprite_t * close_button = sprites[decors_active == DECOR_ACTIVE ? 2 : 3]; - - for (int j = 0; j < u_height; ++j) { - for (int i = 0; i < ul_width; ++i) { - GFX(ctx,i,j) = SPRITE(texture,i,j); - } - } - - for (int j = 0; j < u_height; ++j) { - for (int i = 0; i < ur_width; ++i) { - GFX(ctx,(width-ur_width+i),j) = SPRITE(texture,(texture->width - ur_width+i),j); - } - } - - for (int j = 0; j < l_height; ++j) { - for (int i = 0; i < ll_width; ++i) { - GFX(ctx,i,height-l_height+j) = SPRITE(texture,i,texture->width-l_height+j); - } - } - - for (int j = 0; j < u_height; ++j) { - for (int i = 0; i < ur_width; ++i) { - GFX(ctx,(width-lr_width+i),height-l_height+j) = SPRITE(texture,(texture->width - lr_width+i),texture->width-l_height+j); - } - } - - for (int j = u_height; j < height-l_height; ++j) { - double v = (double)(j - u_height)/(double)(height-l_height-u_height); - v = ((double)u_height + v * (texture->height - u_height - l_height))/(double)(texture->height); - for (int i = 0; i < ml_width; ++i) { - double u = (double)i/(double)texture->width; - GFX(ctx,i,j)=getBilinearFilteredPixelColor(texture,u,v); - } - } - - for (int j = u_height; j < height-l_height; ++j) { - double v = (double)(j - u_height)/(double)(height-l_height-u_height); - v = ((double)u_height + v * (texture->height - u_height - l_height))/(double)(texture->height); - for (int i = 0; i < mr_width; ++i) { - double u = (double)(texture->width - mr_width + i)/(double)texture->width; - GFX(ctx,width-mr_width+i,j)=getBilinearFilteredPixelColor(texture,u,v); - } - } - - for (int j = ul_width; j < width - ur_width; ++j) { - double u = (double)(j - ul_width)/(double)(width-ur_width-ul_width); - u = ((double)ul_width + u * (texture->width - ul_width - ur_width))/(double)(texture->width); - for (int i = 0; i < u_height; ++i) { - double v = (double)i/(double)texture->height; - GFX(ctx,j,i)=getBilinearFilteredPixelColor(texture,u,v); - } - } - - for (int j = ll_width; j < width - lr_width; ++j) { - double u = (double)(j - ll_width)/(double)(width-lr_width-ll_width); - u = ((double)ll_width + u * (texture->width - ll_width - lr_width))/(double)(texture->width); - for (int i = 0; i < u_height; ++i) { - double v = (double)(texture->height - l_height + i)/(double)texture->height; - GFX(ctx,j,height-l_height+i)=getBilinearFilteredPixelColor(texture,u,v); - } - } - - /* Draw the close button */ - int c_top = close_top == -1 ? height - close_bottom - sprites[2]->height : close_top; - int c_left = close_left == -1 ? width - close_right - sprites[2]->width : close_left; - - draw_sprite(ctx, close_button, c_left, c_top); - - - -} - -static int check_button_press_fancy(yutani_window_t * window, int x, int y) { - int c_top = close_top == -1 ? window->height - close_bottom - sprites[2]->height : close_top; - int c_left = close_left == -1 ? window->width - close_right - sprites[2]->width : close_left; - - if (x >= c_left && x < c_left + sprites[2]->width && y >= c_top && y < c_top + sprites[2]->height) { - return DECOR_CLOSE; - } - - return 0; -} - -void decor_init(char * theme_name) { - char tmp[256]; - - fprintf(stderr, "Theme name is %s\n", theme_name); - - sprintf(tmp, "/usr/share/decors/%s/%s", theme_name, "decor.conf"); - confreader_t * conf = confreader_load(tmp); - - u_height = confreader_intd(conf, "upper", "height", 1); - ul_width = confreader_intd(conf, "upper", "left", 1); - ur_width = confreader_intd(conf, "upper", "right", 1); - - m_height = confreader_intd(conf, "middle", "height", 1); - ml_width = confreader_intd(conf, "middle", "left", 1); - mr_width = confreader_intd(conf, "middle", "right", 1); - - l_height = confreader_intd(conf, "lower", "height", 1); - ll_width = confreader_intd(conf, "lower", "left", 1); - lr_width = confreader_intd(conf, "lower", "right", 1); - - close_left = confreader_intd(conf, "close", "left", -1); - close_right = confreader_intd(conf, "close", "right", -1); - close_top = confreader_intd(conf, "close", "top", -1); - close_bottom = confreader_intd(conf, "close", "bottom", -1); - - confreader_free(conf); - - /* Load sprites */ - sprintf(tmp, "/usr/share/decors/%s/%s", theme_name, "active.png"); - init_sprite_png(0, tmp); - sprintf(tmp, "/usr/share/decors/%s/%s", theme_name, "inactive.png"); - init_sprite_png(1, tmp); - sprintf(tmp, "/usr/share/decors/%s/%s", theme_name, "close-active.png"); - init_sprite_png(2, tmp); - sprintf(tmp, "/usr/share/decors/%s/%s", theme_name, "close-inactive.png"); - init_sprite_png(3, tmp); - - decor_top_height = u_height; - decor_bottom_height = l_height; - decor_left_width = ml_width; - decor_right_width = mr_width; - - decor_render_decorations = render_decorations_fancy; - decor_check_button_press = check_button_press_fancy; -} - diff --git a/userspace/gui/terminal/terminal-font.h b/userspace/gui/terminal/terminal-font.h deleted file mode 100644 index 55e1410b..00000000 --- a/userspace/gui/terminal/terminal-font.h +++ /dev/null @@ -1,1727 +0,0 @@ -/* - * terminal bitmap fallback font - */ - -/* Binary Literals */ -#define b(x) ((uint8_t)b_(0 ## x ## uL)) -#define b_(x) ((x & 1) | (x >> 2 & 2) | (x >> 4 & 4) | (x >> 6 & 8) | (x >> 8 & 16) | (x >> 10 & 32) | (x >> 12 & 64) | (x >> 14 & 128)) - -uint8_t number_font[][12] = { - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111110), - b(11000011), - b(10000001), /* 4 */ - b(10100101), - b(10000001), - b(10111101), - b(10011001), /* 8 */ - b(11000011), - b(01111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111110), - b(11111111), - b(11111111), /* 4 */ - b(11011011), - b(11111111), - b(11000011), - b(11100111), /* 8 */ - b(11111111), - b(01111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(01000100), - b(11101110), /* 4 */ - b(11111110), - b(11111110), - b(11111110), - b(01111100), /* 8 */ - b(00111000), - b(00010000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00010000), - b(00111000), - b(01111100), /* 4 */ - b(11111110), - b(11111110), - b(01111100), - b(00111000), /* 8 */ - b(00010000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011000), - b(00111100), - b(00111100), /* 4 */ - b(11111111), - b(11100111), - b(11100111), - b(00011000), /* 8 */ - b(00011000), - b(01111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011000), - b(00111100), - b(01111110), /* 4 */ - b(11111111), - b(11111111), - b(01111110), - b(00011000), /* 8 */ - b(00011000), - b(01111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(00111100), - b(01111110), - b(01111110), - b(00111100), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(11111111), - b(11111111), - b(11111111), - b(11111111), /* 4 */ - b(11000011), - b(10000001), - b(10000001), - b(11000011), /* 8 */ - b(11111111), - b(11111111), - b(11111111), - b(11111111) /* 01 */ - }, - { b(00000000), - b(00000000), - b(00111100), - b(01111110), /* 4 */ - b(01100110), - b(01000010), - b(01000010), - b(01100110), /* 8 */ - b(01111110), - b(00111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(11111111), - b(11111111), - b(11000011), - b(10000001), /* 4 */ - b(10011001), - b(10111101), - b(10111101), - b(10011001), /* 8 */ - b(10000001), - b(11000011), - b(11111111), - b(11111111) /* 01 */ - }, - { b(00000000), - b(00111110), - b(00001110), - b(00111010), /* 4 */ - b(01110010), - b(11111000), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111100), - b(01100110), - b(01100110), /* 4 */ - b(01100110), - b(00111100), - b(00011000), - b(01111110), /* 8 */ - b(00011000), - b(00011000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011111), - b(00011001), - b(00011001), /* 4 */ - b(00011111), - b(00011000), - b(00011000), - b(01111000), /* 8 */ - b(11111000), - b(01110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111111), - b(01100011), - b(01111111), /* 4 */ - b(01100011), - b(01100011), - b(01100011), - b(01100111), /* 8 */ - b(11100111), - b(11100110), - b(11000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00011000), - b(11011011), /* 4 */ - b(01111110), - b(11100111), - b(11100111), - b(01111110), /* 8 */ - b(11011011), - b(00011000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(10000000), - b(11000000), - b(11100000), /* 4 */ - b(11111000), - b(11111110), - b(11111000), - b(11100000), /* 8 */ - b(11000000), - b(10000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000010), - b(00000110), - b(00001110), /* 4 */ - b(00111110), - b(11111110), - b(00111110), - b(00001110), /* 8 */ - b(00000110), - b(00000010), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011000), - b(00111100), - b(01111110), /* 4 */ - b(00011000), - b(00011000), - b(00011000), - b(01111110), /* 8 */ - b(00111100), - b(00011000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01100110), - b(01100110), - b(01100110), /* 4 */ - b(01100110), - b(01100110), - b(00000000), - b(00000000), /* 8 */ - b(01100110), - b(01100110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111111), - b(11011011), - b(11011011), /* 4 */ - b(11011011), - b(01111011), - b(00011011), - b(00011011), /* 8 */ - b(00011011), - b(00011011), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111110), - b(01100011), - b(00110000), /* 4 */ - b(00111100), - b(01100110), - b(01100110), - b(00111100), /* 8 */ - b(00001100), - b(11000110), - b(01111110), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(11111110), /* 8 */ - b(11111110), - b(11111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011000), - b(00111100), - b(01111110), /* 4 */ - b(00011000), - b(00011000), - b(00011000), - b(01111110), /* 8 */ - b(00111100), - b(00011000), - b(01111110), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011000), - b(00111100), - b(01111110), /* 4 */ - b(00011000), - b(00011000), - b(00011000), - b(00011000), /* 8 */ - b(00011000), - b(00011000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011000), - b(00011000), - b(00011000), /* 4 */ - b(00011000), - b(00011000), - b(00011000), - b(01111110), /* 8 */ - b(00111100), - b(00011000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00011000), /* 4 */ - b(00001100), - b(11111110), - b(00001100), - b(00011000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00110000), /* 4 */ - b(01100000), - b(11111110), - b(01100000), - b(00110000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11000000), - b(11000000), - b(11111110), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00100100), /* 4 */ - b(01100110), - b(11111111), - b(01100110), - b(00100100), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00010000), - b(00010000), /* 4 */ - b(00111000), - b(00111000), - b(01111100), - b(01111100), /* 8 */ - b(11111110), - b(11111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(11111110), - b(11111110), /* 4 */ - b(01111100), - b(01111100), - b(00111000), - b(00111000), /* 8 */ - b(00010000), - b(00010000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00110000), - b(01111000), - b(01111000), /* 4 */ - b(00110000), - b(00110000), - b(00000000), - b(00110000), /* 8 */ - b(00110000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01100110), - b(01100110), - b(00100100), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01101100), - b(01101100), - b(11111110), /* 4 */ - b(01101100), - b(01101100), - b(01101100), - b(11111110), /* 8 */ - b(01101100), - b(01101100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00110000), - b(00110000), - b(01111100), - b(11000000), /* 4 */ - b(11000000), - b(01111000), - b(00001100), - b(00001100), /* 8 */ - b(11111000), - b(00110000), - b(00110000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(11000100), - b(11001100), /* 4 */ - b(00011000), - b(00110000), - b(01100000), - b(11001100), /* 8 */ - b(10001100), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01110000), - b(11011000), - b(11011000), /* 4 */ - b(01110000), - b(11111010), - b(11011110), - b(11001100), /* 8 */ - b(11011100), - b(01110110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00110000), - b(00110000), - b(00110000), /* 4 */ - b(01100000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00001100), - b(00011000), - b(00110000), /* 4 */ - b(01100000), - b(01100000), - b(01100000), - b(00110000), /* 8 */ - b(00011000), - b(00001100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01100000), - b(00110000), - b(00011000), /* 4 */ - b(00001100), - b(00001100), - b(00001100), - b(00011000), /* 8 */ - b(00110000), - b(01100000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(01100110), /* 4 */ - b(00111100), - b(11111111), - b(00111100), - b(01100110), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /** 4 */ - b(00011000), - b(00011000), - b(01111110), - b(00011000), /* 8 */ - b(00011000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00111000), - b(00111000), - b(01100000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(00000000), - b(00000000), - b(11111110), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00111000), - b(00111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000010), - b(00000110), /* 4 */ - b(00001100), - b(00011000), - b(00110000), - b(01100000), /* 8 */ - b(11000000), - b(10000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111100), - b(11000110), - b(11001110), /* 4 */ - b(11011110), - b(11010110), - b(11110110), - b(11100110), /* 8 */ - b(11000110), - b(01111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00010000), - b(00110000), - b(11110000), /* 4 */ - b(00110000), - b(00110000), - b(00110000), - b(00110000), /* 8 */ - b(00110000), - b(11111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111000), - b(11001100), - b(11001100), /* 4 */ - b(00001100), - b(00011000), - b(00110000), - b(01100000), /* 8 */ - b(11001100), - b(11111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111000), - b(11001100), - b(00001100), /* 4 */ - b(00001100), - b(00111000), - b(00001100), - b(00001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00001100), - b(00011100), - b(00111100), /* 4 */ - b(01101100), - b(11001100), - b(11111110), - b(00001100), /* 8 */ - b(00001100), - b(00011110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111100), - b(11000000), - b(11000000), /* 4 */ - b(11000000), - b(11111000), - b(00001100), - b(00001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111000), - b(01100000), - b(11000000), /* 4 */ - b(11000000), - b(11111000), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111110), - b(11000110), - b(11000110), /* 4 */ - b(00000110), - b(00001100), - b(00011000), - b(00110000), /* 8 */ - b(00110000), - b(00110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111000), - b(11001100), - b(11001100), /* 4 */ - b(11001100), - b(01111000), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111000), - b(11001100), - b(11001100), /* 4 */ - b(11001100), - b(01111100), - b(00011000), - b(00011000), /* 8 */ - b(00110000), - b(01110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00111000), /* 4 */ - b(00111000), - b(00000000), - b(00000000), - b(00111000), /* 8 */ - b(00111000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00111000), /* 4 */ - b(00111000), - b(00000000), - b(00000000), - b(00111000), /* 8 */ - b(00111000), - b(00011000), - b(00110000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00001100), - b(00011000), - b(00110000), /* 4 */ - b(01100000), - b(11000000), - b(01100000), - b(00110000), /* 8 */ - b(00011000), - b(00001100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01111110), - b(00000000), - b(01111110), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01100000), - b(00110000), - b(00011000), /* 4 */ - b(00001100), - b(00000110), - b(00001100), - b(00011000), /* 8 */ - b(00110000), - b(01100000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111000), - b(11001100), - b(00001100), /* 4 */ - b(00011000), - b(00110000), - b(00110000), - b(00000000), /* 8 */ - b(00110000), - b(00110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111100), - b(11000110), - b(11000110), /* 4 */ - b(11011110), - b(11010110), - b(11011110), - b(11000000), /* 8 */ - b(11000000), - b(01111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00110000), - b(01111000), - b(11001100), /* 4 */ - b(11001100), - b(11001100), - b(11111100), - b(11001100), /* 8 */ - b(11001100), - b(11001100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111100), - b(01100110), - b(01100110), /* 4 */ - b(01100110), - b(01111100), - b(01100110), - b(01100110), /* 8 */ - b(01100110), - b(11111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111100), - b(01100110), - b(11000110), /* 4 */ - b(11000000), - b(11000000), - b(11000000), - b(11000110), /* 8 */ - b(01100110), - b(00111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111000), - b(01101100), - b(01100110), /* 4 */ - b(01100110), - b(01100110), - b(01100110), - b(01100110), /* 8 */ - b(01101100), - b(11111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111110), - b(01100010), - b(01100000), /* 4 */ - b(01100100), - b(01111100), - b(01100100), - b(01100000), /* 8 */ - b(01100010), - b(11111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111110), - b(01100110), - b(01100010), /* 4 */ - b(01100100), - b(01111100), - b(01100100), - b(01100000), /* 8 */ - b(01100000), - b(11110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111100), - b(01100110), - b(11000110), /* 4 */ - b(11000000), - b(11000000), - b(11001110), - b(11000110), /* 8 */ - b(01100110), - b(00111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11001100), - b(11001100), - b(11001100), /* 4 */ - b(11001100), - b(11111100), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(11001100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111000), - b(00110000), - b(00110000), /* 4 */ - b(00110000), - b(00110000), - b(00110000), - b(00110000), /* 8 */ - b(00110000), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011110), - b(00001100), - b(00001100), /* 4 */ - b(00001100), - b(00001100), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11100110), - b(01100110), - b(01101100), /* 4 */ - b(01101100), - b(01111000), - b(01101100), - b(01101100), /* 8 */ - b(01100110), - b(11100110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11110000), - b(01100000), - b(01100000), /* 4 */ - b(01100000), - b(01100000), - b(01100010), - b(01100110), /* 8 */ - b(01100110), - b(11111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11000110), - b(11101110), - b(11111110), /* 4 */ - b(11111110), - b(11010110), - b(11000110), - b(11000110), /* 8 */ - b(11000110), - b(11000110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11000110), - b(11000110), - b(11100110), /* 4 */ - b(11110110), - b(11111110), - b(11011110), - b(11001110), /* 8 */ - b(11000110), - b(11000110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111000), - b(01101100), - b(11000110), /* 4 */ - b(11000110), - b(11000110), - b(11000110), - b(11000110), /* 8 */ - b(01101100), - b(00111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111100), - b(01100110), - b(01100110), /* 4 */ - b(01100110), - b(01111100), - b(01100000), - b(01100000), /* 8 */ - b(01100000), - b(11110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111000), - b(01101100), - b(11000110), /* 4 */ - b(11000110), - b(11000110), - b(11001110), - b(11011110), /* 8 */ - b(01111100), - b(00001100), - b(00011110), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111100), - b(01100110), - b(01100110), /* 4 */ - b(01100110), - b(01111100), - b(01101100), - b(01100110), /* 8 */ - b(01100110), - b(11100110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111000), - b(11001100), - b(11001100), /* 4 */ - b(11000000), - b(01110000), - b(00011000), - b(11001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111100), - b(10110100), - b(00110000), /* 4 */ - b(00110000), - b(00110000), - b(00110000), - b(00110000), /* 8 */ - b(00110000), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11001100), - b(11001100), - b(11001100), /* 4 */ - b(11001100), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11001100), - b(11001100), - b(11001100), /* 4 */ - b(11001100), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(01111000), - b(00110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11000110), - b(11000110), - b(11000110), /* 4 */ - b(11000110), - b(11010110), - b(11010110), - b(01101100), /* 8 */ - b(01101100), - b(01101100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11001100), - b(11001100), - b(11001100), /* 4 */ - b(01111000), - b(00110000), - b(01111000), - b(11001100), /* 8 */ - b(11001100), - b(11001100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11001100), - b(11001100), - b(11001100), /* 4 */ - b(11001100), - b(01111000), - b(00110000), - b(00110000), /* 8 */ - b(00110000), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111110), - b(11001110), - b(10011000), /* 4 */ - b(00011000), - b(00110000), - b(01100000), - b(01100010), /* 8 */ - b(11000110), - b(11111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111100), - b(00110000), - b(00110000), /* 4 */ - b(00110000), - b(00110000), - b(00110000), - b(00110000), /* 8 */ - b(00110000), - b(00111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(10000000), - b(11000000), - b(01100000), /* 4 */ - b(00110000), - b(00011000), - b(00001100), - b(00000110), /* 8 */ - b(00000010), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111100), - b(00001100), - b(00001100), /* 4 */ - b(00001100), - b(00001100), - b(00001100), - b(00001100), /* 8 */ - b(00001100), - b(00111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00010000), - b(00111000), - b(01101100), - b(11000110), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(11111111), - b(00000000) /* 12 */ - }, - { b(00110000), - b(00110000), - b(00011000), - b(00000000), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01111000), - b(00001100), - b(01111100), - b(11001100), /* 8 */ - b(11001100), - b(01110110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11100000), - b(01100000), - b(01100000), /* 4 */ - b(01111100), - b(01100110), - b(01100110), - b(01100110), /* 8 */ - b(01100110), - b(11011100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01111000), - b(11001100), - b(11000000), - b(11000000), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011100), - b(00001100), - b(00001100), /* 4 */ - b(01111100), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01110110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01111000), - b(11001100), - b(11111100), - b(11000000), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00111000), - b(01101100), - b(01100000), /* 4 */ - b(01100000), - b(11111000), - b(01100000), - b(01100000), /* 8 */ - b(01100000), - b(11110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01110110), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(01111100), - b(00001100), - b(11001100), - b(01111000) /* 12 */ - }, - { b(00000000), - b(11100000), - b(01100000), - b(01100000), /* 4 */ - b(01101100), - b(01110110), - b(01100110), - b(01100110), /* 8 */ - b(01100110), - b(11100110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011000), - b(00011000), - b(00000000), /* 4 */ - b(01111000), - b(00011000), - b(00011000), - b(00011000), /* 8 */ - b(00011000), - b(01111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00001100), - b(00001100), - b(00000000), /* 4 */ - b(00011100), - b(00001100), - b(00001100), - b(00001100), /* 8 */ - b(00001100), - b(11001100), - b(11001100), - b(01111000) /* 12 */ - }, - { b(00000000), - b(11100000), - b(01100000), - b(01100000), /* 4 */ - b(01100110), - b(01101100), - b(01111000), - b(01101100), /* 8 */ - b(01100110), - b(11100110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01111000), - b(00011000), - b(00011000), /* 4 */ - b(00011000), - b(00011000), - b(00011000), - b(00011000), /* 8 */ - b(00011000), - b(01111110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11111100), - b(11010110), - b(11010110), - b(11010110), /* 8 */ - b(11010110), - b(11000110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11111000), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(11001100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01111000), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11011100), - b(01100110), - b(01100110), - b(01100110), /* 8 */ - b(01100110), - b(01111100), - b(01100000), - b(11110000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01110110), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01111100), - b(00001100), - b(00011110) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11101100), - b(01101110), - b(01110110), - b(01100000), /* 8 */ - b(01100000), - b(11110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01111000), - b(11001100), - b(01100000), - b(00011000), /* 8 */ - b(11001100), - b(01111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00100000), - b(01100000), /* 4 */ - b(11111100), - b(01100000), - b(01100000), - b(01100000), /* 8 */ - b(01101100), - b(00111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11001100), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(11001100), - b(01110110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11001100), - b(11001100), - b(11001100), - b(11001100), /* 8 */ - b(01111000), - b(00110000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11000110), - b(11000110), - b(11010110), - b(11010110), /* 8 */ - b(01101100), - b(01101100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11000110), - b(01101100), - b(00111000), - b(00111000), /* 8 */ - b(01101100), - b(11000110), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(01100110), - b(01100110), - b(01100110), - b(01100110), /* 8 */ - b(00111100), - b(00001100), - b(00011000), - b(11110000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 4 */ - b(11111100), - b(10001100), - b(00011000), - b(01100000), /* 8 */ - b(11000100), - b(11111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011100), - b(00110000), - b(00110000), /* 4 */ - b(01100000), - b(11000000), - b(01100000), - b(00110000), /* 8 */ - b(00110000), - b(00011100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00011000), - b(00011000), - b(00011000), /* 4 */ - b(00011000), - b(00000000), - b(00011000), - b(00011000), /* 8 */ - b(00011000), - b(00011000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11100000), - b(00110000), - b(00110000), /* 4 */ - b(00011000), - b(00001100), - b(00011000), - b(00110000), /* 8 */ - b(00110000), - b(11100000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01110011), - b(11011010), - b(11001110), /* 4 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000), /* 8 */ - b(00000000), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00000000), - b(00000000), - b(00010000), /* 4 */ - b(00111000), - b(01101100), - b(11000110), - b(11000110), /* 8 */ - b(11111110), - b(00000000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01000100), - b(01101100), - b(00111000), /* 4 */ - b(00110000), - b(01100000), - b(11000000), - b(11000000), /* 8 */ - b(01100000), - b(00111000), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(00110000), - b(00110000), - b(11111110), /* 4 */ - b(00110000), - b(00110000), - b(01111010), - b(10110110), /* 8 */ - b(01111100), - b(00110010), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(11111110), - b(00001100), - b(00011000), /* 4 */ - b(00110000), - b(00011000), - b(00001100), - b(01110110), /* 8 */ - b(11000110), - b(01111100), - b(00000000), - b(00000000) /* 12 */ - }, - { b(00000000), - b(01100110), - b(01100110), - b(01100110), /* 4 */ - b(01100110), - b(00000000), - b(00000000), - b(00111100), /* 8 */ - b(01100110), - b(11000011), - b(00000000), - b(00000000) /* 12 */ - }, -}; - diff --git a/userspace/gui/terminal/terminal.c b/userspace/gui/terminal/terminal.c deleted file mode 100644 index 1719a5e6..00000000 --- a/userspace/gui/terminal/terminal.c +++ /dev/null @@ -1,1581 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - * - * Terminal Emulator - * - * Graphical terminal emulator. - * - * Provides a number of features: - * - Windowed and full screen modes - * - Antialiased fonts - * - Built-in fallback bitmap font - * - ANSI escape support - * - 256 colors - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include FT_FREETYPE_H -#include FT_CACHE_H - -#include - -#include "lib/utf8decode.h" - -#include "lib/graphics.h" -#include "lib/yutani.h" -#include "lib/decorations.h" -#include "lib/kbd.h" -#include "lib/spinlock.h" - -#include "terminal-palette.h" -#include "terminal-font.h" - -#include "gui/terminal/lib/termemu.h" - -#define USE_BELL 0 - -/* master and slave pty descriptors */ -static int fd_master, fd_slave; -static FILE * terminal; - -int scale_fonts = 0; /* Whether fonts should be scaled */ -float font_scaling = 1.0; /* How much they should be scaled by */ -uint16_t term_width = 0; /* Width of the terminal (in cells) */ -uint16_t term_height = 0; /* Height of the terminal (in cells) */ -uint16_t font_size = 13; /* Font size according to Freetype */ -uint16_t char_width = 8; /* Width of a cell in pixels */ -uint16_t char_height = 12; /* Height of a cell in pixels */ -uint16_t char_offset = 0; /* Offset of the font within the cell */ -int csr_x = 0; /* Cursor X */ -int csr_y = 0; /* Cursor Y */ -term_cell_t * term_buffer = NULL; /* The terminal cell buffer */ -uint32_t current_fg = 7; /* Current foreground color */ -uint32_t current_bg = 0; /* Current background color */ -uint8_t cursor_on = 1; /* Whether or not the cursor should be rendered */ -uint8_t _fullscreen = 0; /* Whether or not we are running in fullscreen mode (GUI only) */ -uint8_t _no_frame = 0; /* Whether to disable decorations or not */ -uint8_t _login_shell = 0; /* Whether we're going to display a login shell or not */ -uint8_t _use_freetype = 0; /* Whether we should use freetype or not XXX seriously, how about some flags */ -uint8_t _force_kernel = 0; -uint8_t _hold_out = 0; /* state indicator on last cell ignore \n */ -uint8_t _free_size = 1; /* Disable rounding when resized */ - -int last_mouse_x = -1; -int last_mouse_y = -1; -int button_state = 0; - -uint64_t mouse_ticks = 0; - -yutani_window_t * window = NULL; /* GUI window */ -yutani_t * yctx = NULL; - -term_state_t * ansi_state = NULL; - -int32_t l_x = INT32_MAX; -int32_t l_y = INT32_MAX; -int32_t r_x = -1; -int32_t r_y = -1; - -void reinit(); /* Defined way further down */ -void term_redraw_cursor(); - -/* Some GUI-only options */ -uint32_t window_width = 640; -uint32_t window_height = 408; -#define TERMINAL_TITLE_SIZE 512 -char terminal_title[TERMINAL_TITLE_SIZE]; -size_t terminal_title_length = 0; -gfx_context_t * ctx; -static void render_decors(); -void term_clear(); -void flush_unused_images(void); - -void dump_buffer(); - -/* Trigger to exit the terminal when the child process dies or - * we otherwise receive an exit signal */ -volatile int exit_application = 0; - -static uint64_t get_ticks(void) { - struct timeval now; - gettimeofday(&now, NULL); - - return (uint64_t)now.tv_sec * 1000000LL + (uint64_t)now.tv_usec; -} - -static void display_flip(void) { - if (l_x != INT32_MAX && l_y != INT32_MAX) { - yutani_flip_region(yctx, window, l_x, l_y, r_x - l_x, r_y - l_y); - l_x = INT32_MAX; - l_y = INT32_MAX; - r_x = -1; - r_y = -1; - } -} - -static void set_term_font_size(float s) { - scale_fonts = 1; - font_scaling = s; - reinit(1); -} - -/* Returns the lower of two shorts */ -int32_t min(int32_t a, int32_t b) { - return (a < b) ? a : b; -} - -/* Returns the higher of two shorts */ -int32_t max(int32_t a, int32_t b) { - return (a > b) ? a : b; -} - -void set_title(char * c) { - int len = min(TERMINAL_TITLE_SIZE, strlen(c)+1); - memcpy(terminal_title, c, len); - terminal_title[len-1] = '\0'; - terminal_title_length = len - 1; - render_decors(); -} - -/* Stuffs a string into the stdin of the terminal's child process - * Useful for things like the ANSI DSR command. */ -void input_buffer_stuff(char * str) { - size_t s = strlen(str) + 1; - write(fd_master, str, s); -} - -static void render_decors() { - /* XXX Make the decorations library support Yutani windows */ - if (_fullscreen) return; - if (!_no_frame) { - render_decorations(window, ctx, terminal_title_length ? terminal_title : "Terminal"); - } - yutani_window_advertise_icon(yctx, window, terminal_title_length ? terminal_title : "Terminal", "utilities-terminal"); - l_x = 0; l_y = 0; - r_x = window->width; - r_y = window->height; - display_flip(); -} - -static inline void term_set_point(uint16_t x, uint16_t y, uint32_t color ) { - if (_fullscreen) { - color = alpha_blend_rgba(premultiply(rgba(0,0,0,0xFF)), color); - } - if (!_no_frame) { - GFX(ctx, (x+decor_left_width),(y+decor_top_height)) = color; - } else { - GFX(ctx, x,y) = color; - } -} - -/* FreeType text rendering */ - -FT_Library library; -FT_Face face; -FT_Face face_bold; -FT_Face face_italic; -FT_Face face_bold_italic; -FT_Face face_extra; -FT_Face face_symbol; -FT_Face face_variable; - -FT_Face * fallbacks[] = {&face_variable, &face_symbol, &face_extra, &face_symbol, NULL}; - - -void drawChar(FT_Bitmap * bitmap, int x, int y, uint32_t fg, uint32_t bg) { - int i, j, p, q; - int x_max = x + bitmap->width; - int y_max = y + bitmap->rows; - for (j = y, q = 0; j < y_max; j++, q++) { - for ( i = x, p = 0; i < x_max; i++, p++) { - uint32_t a = _ALP(fg); - a = (a * bitmap->buffer[q * bitmap->width + p]) / 255; - uint32_t tmp = rgba(_RED(fg),_GRE(fg),_BLU(fg),a); - term_set_point(i,j, alpha_blend_rgba(premultiply(bg), premultiply(tmp))); - } - } -} - -void draw_semi_block(int c, int x, int y, uint32_t fg, uint32_t bg) { - int height; - bg = premultiply(bg); - fg = premultiply(fg); - if (c == 0x2580) { - uint32_t t = bg; - bg = fg; - fg = t; - c = 0x2584; - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = 0; j < char_width; ++j) { - term_set_point(x+j,y+i,bg); - } - } - } - c -= 0x2580; - height = char_height - ((c * char_height) / 8); - for (uint8_t i = height; i < char_height; ++i) { - for (uint8_t j = 0; j < char_width; ++j) { - term_set_point(x+j, y+i,fg); - } - } -} - -void focus_callback(yutani_window_t * yutani_window) { - render_decors(); - term_redraw_cursor(); -} - -void -term_write_char( - uint32_t val, - uint16_t x, - uint16_t y, - uint32_t fg, - uint32_t bg, - uint8_t flags - ) { - - uint32_t _fg, _bg; - - if (fg < PALETTE_COLORS) { - _fg = term_colors[fg]; - _fg |= 0xFF << 24; - } else { - _fg = fg; - } - if (bg < PALETTE_COLORS) { - _bg = term_colors[bg]; - if (flags & ANSI_SPECBG) { - _bg |= 0xFF << 24; - } else { - _bg |= TERM_DEFAULT_OPAC << 24; - } - } else { - _bg = bg; - } - if (_use_freetype) { - if (val == 0xFFFF) { return; } /* Unicode, do not redraw here */ - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = 0; j < char_width; ++j) { - term_set_point(x+j,y+i,premultiply(_bg)); - } - } - if (flags & ANSI_WIDE) { - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = char_width; j < 2 * char_width; ++j) { - term_set_point(x+j,y+i,premultiply(_bg)); - } - } - } - if (val < 32 || val == ' ') { - goto _extra_stuff; - } - if (val >= 0x2580 && val <= 0x2588) { - draw_semi_block(val, x, y, _fg, _bg); - goto _extra_stuff; - } - - int pen_x = x; - int pen_y = y + char_offset; - int error; - - FT_Face * _font = NULL; - FT_GlyphSlot slot; - FT_UInt glyph_index; - - if (flags & ANSI_ALTFONT) { - _font = &face_extra; - } else if (flags & ANSI_BOLD && flags & ANSI_ITALIC) { - _font = &face_bold_italic; - } else if (flags & ANSI_ITALIC) { - _font = &face_italic; - } else if (flags & ANSI_BOLD) { - _font = &face_bold; - } else { - _font = &face; - } - glyph_index = FT_Get_Char_Index(*_font, val); - - if (!glyph_index) { - int i = 0; - while (!glyph_index && fallbacks[i]) { - _font = fallbacks[i]; - glyph_index = FT_Get_Char_Index(*_font, val); - i++; - } - } - error = FT_Load_Glyph(*_font, glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(terminal, "Error loading glyph: %d\n", val); - fprintf(stderr, "Error loading glyph: %d\n", val); - }; - slot = (*_font)->glyph; - if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { - error = FT_Render_Glyph((*_font)->glyph, FT_RENDER_MODE_NORMAL); - if (error) { - fprintf(stderr, "Error rendering glyph: %d\n", val); - goto _extra_stuff; - } - } - drawChar(&slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top, _fg, _bg); - - } else { - if (val > 128) { - val = 4; - } - uint8_t * c = number_font[val]; - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = 0; j < char_width; ++j) { - if (c[i] & (1 << (8-j))) { - term_set_point(x+j,y+i,_fg); - } else { - term_set_point(x+j,y+i,_bg); - } - } - } - } -_extra_stuff: - if (flags & ANSI_UNDERLINE) { - for (uint8_t i = 0; i < char_width; ++i) { - term_set_point(x + i, y + char_offset + 2, _fg); - } - } - if (flags & ANSI_CROSS) { - for (uint8_t i = 0; i < char_width; ++i) { - term_set_point(x + i, y + char_offset - 5, _fg); - } - } - if (flags & ANSI_BORDER) { - for (uint8_t i = 0; i < char_height; ++i) { - term_set_point(x , y + i, _fg); - term_set_point(x + (char_width - 1), y + i, _fg); - } - for (uint8_t j = 0; j < char_width; ++j) { - term_set_point(x + j, y, _fg); - term_set_point(x + j, y + (char_height - 1), _fg); - } - } - - if (!_no_frame) { - l_x = min(l_x, decor_left_width + x); - l_y = min(l_y, decor_top_height + y); - - if (flags & ANSI_WIDE) { - r_x = max(r_x, decor_left_width + x + char_width * 2); - r_y = max(r_y, decor_top_height + y + char_height * 2); - } else { - r_x = max(r_x, decor_left_width + x + char_width); - r_y = max(r_y, decor_top_height + y + char_height); - } - } else { - l_x = min(l_x, x); - l_y = min(l_y, y); - - if (flags & ANSI_WIDE) { - r_x = max(r_x, x + char_width * 2); - r_y = max(r_y, y + char_height * 2); - } else { - r_x = max(r_x, x + char_width); - r_y = max(r_y, y + char_height); - } - } -} - -static void cell_set(uint16_t x, uint16_t y, uint32_t c, uint32_t fg, uint32_t bg, uint32_t flags) { - if (x >= term_width || y >= term_height) return; - term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); - cell->c = c; - cell->fg = fg; - cell->bg = bg; - cell->flags = flags; -} - -static void redraw_cell_image(uint16_t x, uint16_t y, term_cell_t * cell) { - if (x >= term_width || y >= term_height) return; - uint32_t * data = (uint32_t *)cell->fg; - for (uint32_t yy = 0; yy < char_height; ++yy) { - for (uint32_t xx = 0; xx < char_width; ++xx) { - term_set_point(x * char_width + xx, y * char_height + yy, *data); - data++; - } - } - if (!_no_frame) { - l_x = min(l_x, decor_left_width + x * char_width); - l_y = min(l_y, decor_top_height + y * char_height); - r_x = max(r_x, decor_left_width + x * char_width + char_width); - r_y = max(r_y, decor_top_height + y * char_height + char_height); - } else { - l_x = min(l_x, x * char_width); - l_y = min(l_y, y * char_height); - r_x = max(r_x, x * char_width + char_width); - r_y = max(r_y, y * char_height + char_height); - } -} - -static void cell_redraw(uint16_t x, uint16_t y) { - if (x >= term_width || y >= term_height) return; - term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); - if (cell->flags & ANSI_EXT_IMG) { redraw_cell_image(x,y,cell); return; } - if (((uint32_t *)cell)[0] == 0x00000000) { - term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); - } else { - term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags); - } -} - -static void cell_redraw_inverted(uint16_t x, uint16_t y) { - if (x >= term_width || y >= term_height) return; - term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); - if (cell->flags & ANSI_EXT_IMG) { redraw_cell_image(x,y,cell); return; } - if (((uint32_t *)cell)[0] == 0x00000000) { - term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_BG, TERM_DEFAULT_FG, TERM_DEFAULT_FLAGS | ANSI_SPECBG); - } else { - term_write_char(cell->c, x * char_width, y * char_height, cell->bg, cell->fg, cell->flags | ANSI_SPECBG); - } -} - -static void cell_redraw_box(uint16_t x, uint16_t y) { - if (x >= term_width || y >= term_height) return; - term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); - if (cell->flags & ANSI_EXT_IMG) { redraw_cell_image(x,y,cell); return; } - if (((uint32_t *)cell)[0] == 0x00000000) { - term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS | ANSI_BORDER); - } else { - term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags | ANSI_BORDER); - } -} - -void render_cursor() { - if (!window->focused) { - cell_redraw_box(csr_x, csr_y); - } else { - cell_redraw_inverted(csr_x, csr_y); - } -} - -void draw_cursor() { - if (!cursor_on) return; - mouse_ticks = get_ticks(); - render_cursor(); -} - -void term_redraw_all() { - for (int i = 0; i < term_height; i++) { - for (int x = 0; x < term_width; ++x) { - term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (i * term_width + x) * sizeof(term_cell_t)); - if (cell->flags & ANSI_EXT_IMG) { redraw_cell_image(x,i,cell); continue; } - if (((uint32_t *)cell)[0] == 0x00000000) { - term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); - } else { - term_write_char(cell->c, x * char_width, i * char_height, cell->fg, cell->bg, cell->flags); - } - } - } -} - -void term_scroll(int how_much) { - if (how_much >= term_height || -how_much >= term_height) { - term_clear(); - return; - } - if (how_much == 0) { - return; - } - - cell_redraw(csr_x, csr_y); - if (how_much > 0) { - /* Shift terminal cells one row up */ - memmove(term_buffer, (void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width), sizeof(term_cell_t) * term_width * (term_height - how_much)); - /* Reset the "new" row to clean cells */ - memset((void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width * (term_height - how_much)), 0x0, sizeof(term_cell_t) * term_width * how_much); - /* In graphical modes, we will shift the graphics buffer up as necessary */ - uintptr_t dst, src; - size_t siz = char_height * (term_height - how_much) * GFX_W(ctx) * GFX_B(ctx); - if (!_no_frame) { - /* Must include decorations */ - dst = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * decor_top_height) * GFX_B(ctx); - src = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * (decor_top_height + char_height * how_much)) * GFX_B(ctx); - } else { - /* Can skip decorations */ - dst = (uintptr_t)ctx->backbuffer; - src = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * char_height * how_much) * GFX_B(ctx); - } - /* Perform the shift */ - memmove((void *)dst, (void *)src, siz); - /* And redraw the new rows */ - for (int i = 0; i < how_much; ++i) { - for (uint16_t x = 0; x < term_width; ++x) { - cell_set(x,term_height - how_much,' ', current_fg, current_bg, ansi_state->flags); - cell_redraw(x, term_height - how_much); - } - } - } else { - how_much = -how_much; - /* Shift terminal cells one row up */ - memmove((void *)((uintptr_t)term_buffer + sizeof(term_cell_t) * term_width), term_buffer, sizeof(term_cell_t) * term_width * (term_height - how_much)); - /* Reset the "new" row to clean cells */ - memset(term_buffer, 0x0, sizeof(term_cell_t) * term_width * how_much); - uintptr_t dst, src; - size_t siz = char_height * (term_height - how_much) * GFX_W(ctx) * GFX_B(ctx); - if (!_no_frame) { - src = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * decor_top_height) * GFX_B(ctx); - dst = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * (decor_top_height + char_height * how_much)) * GFX_B(ctx); - } else { - src = (uintptr_t)ctx->backbuffer; - dst = (uintptr_t)ctx->backbuffer + (GFX_W(ctx) * char_height * how_much) * GFX_B(ctx); - } - /* Perform the shift */ - memmove((void *)dst, (void *)src, siz); - /* And redraw the new rows */ - for (int i = 0; i < how_much; ++i) { - for (uint16_t x = 0; x < term_width; ++x) { - cell_redraw(x, i); - } - } - } - flush_unused_images(); - yutani_flip(yctx, window); -} - -int is_wide(uint32_t codepoint) { - if (codepoint < 256) return 0; - return wcwidth(codepoint) == 2; -} - -struct scrollback_row { - unsigned short width; - term_cell_t cells[]; -}; - -#define MAX_SCROLLBACK 10240 - -list_t * scrollback_list = NULL; - -uint32_t scrollback_offset = 0; - -void save_scrollback() { - /* Save the current top row for scrollback */ - if (!scrollback_list) { - scrollback_list = list_create(); - } - if (scrollback_list->length == MAX_SCROLLBACK) { - free(list_dequeue(scrollback_list)); - } - - struct scrollback_row * row = malloc(sizeof(struct scrollback_row) + sizeof(term_cell_t) * term_width + 20); - row->width = term_width; - for (int i = 0; i < term_width; ++i) { - term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (i) * sizeof(term_cell_t)); - memcpy(&row->cells[i], cell, sizeof(term_cell_t)); - } - - list_insert(scrollback_list, row); -} - -void redraw_scrollback() { - if (!scrollback_offset) { - term_redraw_all(); - display_flip(); - return; - } - if (scrollback_offset < term_height) { - for (int i = scrollback_offset; i < term_height; i++) { - int y = i - scrollback_offset; - for (int x = 0; x < term_width; ++x) { - term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); - if (cell->flags & ANSI_EXT_IMG) { redraw_cell_image(x,i,cell); continue; } - if (((uint32_t *)cell)[0] == 0x00000000) { - term_write_char(' ', x * char_width, i * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); - } else { - term_write_char(cell->c, x * char_width, i * char_height, cell->fg, cell->bg, cell->flags); - } - } - } - - node_t * node = scrollback_list->tail; - for (int i = 0; i < scrollback_offset; ++i) { - struct scrollback_row * row = (struct scrollback_row *)node->value; - - int y = scrollback_offset - 1 - i; - int width = row->width; - if (width > term_width) { - width = term_width; - } else { - for (int x = row->width; x < term_width; ++x) { - term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); - } - } - for (int x = 0; x < width; ++x) { - term_cell_t * cell = &row->cells[x]; - if (((uint32_t *)cell)[0] == 0x00000000) { - term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); - } else { - term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags); - } - } - - node = node->prev; - } - } else { - node_t * node = scrollback_list->tail; - for (int i = 0; i < scrollback_offset - term_height; ++i) { - node = node->prev; - } - for (int i = scrollback_offset - term_height; i < scrollback_offset; ++i) { - struct scrollback_row * row = (struct scrollback_row *)node->value; - - int y = scrollback_offset - 1 - i; - int width = row->width; - if (width > term_width) { - width = term_width; - } else { - for (int x = row->width; x < term_width; ++x) { - term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); - } - } - for (int x = 0; x < width; ++x) { - term_cell_t * cell = &row->cells[x]; - if (((uint32_t *)cell)[0] == 0x00000000) { - term_write_char(' ', x * char_width, y * char_height, TERM_DEFAULT_FG, TERM_DEFAULT_BG, TERM_DEFAULT_FLAGS); - } else { - term_write_char(cell->c, x * char_width, y * char_height, cell->fg, cell->bg, cell->flags); - } - } - - node = node->prev; - } - } - display_flip(); -} - -void term_write(char c) { - static uint32_t unicode_state = 0; - static uint32_t codepoint = 0; - - cell_redraw(csr_x, csr_y); - - if (!decode(&unicode_state, &codepoint, (uint8_t)c)) { - uint32_t o = codepoint; - codepoint = 0; - if (c == '\r') { - csr_x = 0; - return; - } - if (csr_x < 0) csr_x = 0; - if (csr_y < 0) csr_y = 0; - if (csr_x == term_width) { - csr_x = 0; - ++csr_y; - } - if (csr_y == term_height) { - save_scrollback(); - term_scroll(1); - csr_y = term_height - 1; - } - if (c == '\n') { - if (csr_x == 0 && _hold_out) { - _hold_out = 0; - return; - } - ++csr_y; - if (csr_y == term_height) { - save_scrollback(); - term_scroll(1); - csr_y = term_height - 1; - } - draw_cursor(); - } else if (c == '\007') { - /* bell */ -#if USE_BELL - for (int i = 0; i < term_height; ++i) { - for (int j = 0; j < term_width; ++j) { - cell_redraw_inverted(j, i); - } - } - syscall_nanosleep(0,10); - term_redraw_all(); -#endif - } else if (c == '\b') { - if (csr_x > 0) { - --csr_x; - } - cell_redraw(csr_x, csr_y); - draw_cursor(); - } else if (c == '\t') { - csr_x += (8 - csr_x % 8); - draw_cursor(); - } else { - int wide = is_wide(o); - uint8_t flags = ansi_state->flags; - if (wide && csr_x == term_width - 1) { - csr_x = 0; - ++csr_y; - } - if (wide) { - flags = flags | ANSI_WIDE; - } - cell_set(csr_x,csr_y, o, current_fg, current_bg, flags); - cell_redraw(csr_x,csr_y); - csr_x++; - if (wide && csr_x != term_width) { - cell_set(csr_x, csr_y, 0xFFFF, current_fg, current_bg, ansi_state->flags); - cell_redraw(csr_x,csr_y); - cell_redraw(csr_x-1,csr_y); - csr_x++; - } - } - } else if (unicode_state == UTF8_REJECT) { - unicode_state = 0; - codepoint = 0; - } - draw_cursor(); -} - -void term_set_csr(int x, int y) { - cell_redraw(csr_x,csr_y); - csr_x = x; - csr_y = y; - draw_cursor(); -} - -int term_get_csr_x(void) { - return csr_x; -} - -int term_get_csr_y(void) { - return csr_y; -} - -static list_t * images_list = NULL; - -void term_set_cell_contents(int x, int y, char * data) { - if (!images_list) { - images_list = list_create(); - } - char * cell_data = malloc(char_width * char_height * sizeof(uint32_t)); - memcpy(cell_data, data, char_width * char_height * sizeof(uint32_t)); - list_insert(images_list, cell_data); - cell_set(x, y, ' ', (uint32_t)cell_data, 0, ANSI_EXT_IMG); - return; -} - -void flush_unused_images(void) { - if (!images_list) return; - - list_t * tmp = list_create(); - for (int y = 0; y < term_height; ++y) { - for (int x = 0; x < term_width; ++x) { - term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); - if (cell->flags & ANSI_EXT_IMG) { - list_insert(tmp, (void *)cell->fg); - } - } - } - foreach(node, images_list) { - if (!list_find(tmp, node->value)) { - free(node->value); - } - } - - list_free(images_list); - images_list = tmp; -} - -int term_get_cell_width(void) { - return char_width; -} - -int term_get_cell_height(void) { - return char_height; -} - -void term_set_csr_show(int on) { - cursor_on = on; -} - -void term_set_colors(uint32_t fg, uint32_t bg) { - current_fg = fg; - current_bg = bg; -} - -void term_redraw_cursor() { - if (term_buffer) { - draw_cursor(); - } -} - -void flip_cursor() { - static uint8_t cursor_flipped = 0; - if (scrollback_offset != 0) { - return; /* Don't flip cursor while drawing scrollback */ - } - if (window->focused && cursor_flipped) { - cell_redraw(csr_x, csr_y); - } else { - render_cursor(); - } - display_flip(); - cursor_flipped = 1 - cursor_flipped; -} - -void term_set_cell(int x, int y, uint32_t c) { - cell_set(x, y, c, current_fg, current_bg, ansi_state->flags); - cell_redraw(x, y); -} - -void term_redraw_cell(int x, int y) { - if (x < 0 || y < 0 || x >= term_width || y >= term_height) return; - cell_redraw(x,y); -} - -void term_clear(int i) { - if (i == 2) { - /* Oh dear */ - csr_x = 0; - csr_y = 0; - memset((void *)term_buffer, 0x00, term_width * term_height * sizeof(term_cell_t)); - if (!_no_frame) { - render_decors(); - } - term_redraw_all(); - } else if (i == 0) { - for (int x = csr_x; x < term_width; ++x) { - term_set_cell(x, csr_y, ' '); - } - for (int y = csr_y + 1; y < term_height; ++y) { - for (int x = 0; x < term_width; ++x) { - term_set_cell(x, y, ' '); - } - } - } else if (i == 1) { - for (int y = 0; y < csr_y; ++y) { - for (int x = 0; x < term_width; ++x) { - term_set_cell(x, y, ' '); - } - } - for (int x = 0; x < csr_x; ++x) { - term_set_cell(x, csr_y, ' '); - } - } - flush_unused_images(); -} - -char * loadMemFont(char * name, char * ident, size_t * size) { - size_t s = 0; - int error; - char tmp[100]; - snprintf(tmp, 100, "sys.%s.fonts.%s", yctx->server_ident, ident); - - char * font = (char *)syscall_shm_obtain(tmp, &s); - *size = s; - return font; -} - -#define INPUT_SIZE 1024 -char input_buffer[INPUT_SIZE]; -int input_collected = 0; - -void clear_input() { - memset(input_buffer, 0x0, INPUT_SIZE); - input_collected = 0; -} - -uint32_t child_pid = 0; - -void handle_input(char c) { - write(fd_master, &c, 1); - display_flip(); -} - -void handle_input_s(char * c) { - write(fd_master, c, strlen(c)); - display_flip(); -} - -void scroll_up(int amount) { - int i = 0; - while (i < amount && scrollback_list && scrollback_offset < scrollback_list->length) { - scrollback_offset ++; - i++; - } - redraw_scrollback(); -} - -void scroll_down(int amount) { - int i = 0; - while (i < amount && scrollback_list && scrollback_offset != 0) { - scrollback_offset -= 1; - i++; - } - redraw_scrollback(); -} - -void key_event(int ret, key_event_t * event) { - if (ret) { - if (event->modifiers & KEY_MOD_LEFT_ALT || event->modifiers & KEY_MOD_RIGHT_ALT) { - handle_input('\033'); - } - if ((event->modifiers & KEY_MOD_LEFT_SHIFT || event->modifiers & KEY_MOD_RIGHT_SHIFT) && - event->key == '\t') { - handle_input_s("\033[Z"); - return; - } - handle_input(event->key); - } else { - if (event->action == KEY_ACTION_UP) return; - switch (event->keycode) { - case KEY_F1: - handle_input_s("\033OP"); - break; - case KEY_F2: - handle_input_s("\033OQ"); - break; - case KEY_F3: - handle_input_s("\033OR"); - break; - case KEY_F4: - handle_input_s("\033OS"); - break; - case KEY_F5: - handle_input_s("\033[15~"); - break; - case KEY_F6: - handle_input_s("\033[17~"); - break; - case KEY_F7: - handle_input_s("\033[18~"); - break; - case KEY_F8: - handle_input_s("\033[19~"); - break; - case KEY_F9: - handle_input_s("\033[20~"); - break; - case KEY_F10: - handle_input_s("\033[21~"); - break; - case KEY_F11: - handle_input_s("\033[23~"); - break; - case KEY_F12: - /* Toggle decorations */ - if (!_fullscreen) { - _no_frame = !_no_frame; - window_width = window->width - decor_width() * (!_no_frame); - window_height = window->height - decor_height() * (!_no_frame); - reinit(1); - } - break; - case KEY_ARROW_UP: - if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { - handle_input_s("\033[6A"); - } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { - handle_input_s("\033[5A"); - } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { - handle_input_s("\033[4A"); - } else if (event->modifiers & KEY_MOD_LEFT_ALT) { - handle_input_s("\033[3A"); - } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { - handle_input_s("\033[2A"); - } else { - handle_input_s("\033[A"); - } - break; - case KEY_ARROW_DOWN: - if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { - handle_input_s("\033[6B"); - } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { - handle_input_s("\033[5B"); - } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { - handle_input_s("\033[4B"); - } else if (event->modifiers & KEY_MOD_LEFT_ALT) { - handle_input_s("\033[3B"); - } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { - handle_input_s("\033[2B"); - } else { - handle_input_s("\033[B"); - } - break; - case KEY_ARROW_RIGHT: - if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { - handle_input_s("\033[6C"); - } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { - handle_input_s("\033[5C"); - } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { - handle_input_s("\033[4C"); - } else if (event->modifiers & KEY_MOD_LEFT_ALT) { - handle_input_s("\033[3C"); - } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { - handle_input_s("\033[2C"); - } else { - handle_input_s("\033[C"); - } - break; - case KEY_ARROW_LEFT: - if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_CTRL) { - handle_input_s("\033[6D"); - } else if (event->modifiers & KEY_MOD_LEFT_CTRL) { - handle_input_s("\033[5D"); - } else if (event->modifiers & KEY_MOD_LEFT_SHIFT && event->modifiers & KEY_MOD_LEFT_ALT) { - handle_input_s("\033[4D"); - } else if (event->modifiers & KEY_MOD_LEFT_ALT) { - handle_input_s("\033[3D"); - } else if (event->modifiers & KEY_MOD_LEFT_SHIFT) { - handle_input_s("\033[2D"); - } else { - handle_input_s("\033[D"); - } - break; - case KEY_PAGE_UP: - if (event->modifiers & KEY_MOD_LEFT_SHIFT) { - scroll_up(term_height/2); - } else { - handle_input_s("\033[5~"); - } - break; - case KEY_PAGE_DOWN: - if (event->modifiers & KEY_MOD_LEFT_SHIFT) { - scroll_down(term_height/2); - } else { - handle_input_s("\033[6~"); - } - break; - case KEY_HOME: - if (event->modifiers & KEY_MOD_LEFT_SHIFT) { - scrollback_offset = scrollback_list->length; - redraw_scrollback(); - } else { - handle_input_s("\033OH"); - } - break; - case KEY_END: - if (event->modifiers & KEY_MOD_LEFT_SHIFT) { - scrollback_offset = 0; - redraw_scrollback(); - } else { - handle_input_s("\033OF"); - } - break; - case KEY_DEL: - handle_input_s("\033[3~"); - break; - case KEY_INSERT: - handle_input_s("\033[2~"); - break; - } - } -} - -void check_for_exit(void) { - if (exit_application) return; - - int pid = waitpid(-1, NULL, WNOHANG); - - if (pid != child_pid) return; - - /* Clean up */ - exit_application = 1; - /* Exit */ - char exit_message[] = "[Process terminated]\n"; - write(fd_slave, exit_message, sizeof(exit_message)); -} - -void usage(char * argv[]) { - printf( - "Terminal Emulator\n" - "\n" - "usage: %s [-b] [-F] [-h]\n" - "\n" - " -F --fullscreen \033[3mRun in fullscreen (background) mode.\033[0m\n" - " -b --bitmap \033[3mUse the integrated bitmap font.\033[0m\n" - " -h --help \033[3mShow this help message.\033[0m\n" - " -s --scale \033[3mScale the font in FreeType mode by a given amount.\033[0m\n" - " -x --grid \033[3mMake resizes round to nearest match for character cell size.\033[0m\n" - " -n --no-frame \033[3mDisable decorations.\033[0m\n" - "\n" - " This terminal emulator provides basic support for VT220 escapes and\n" - " XTerm extensions, including 256 color support and font effects.\n", - argv[0]); -} - -term_callbacks_t term_callbacks = { - &term_write, - term_set_colors, - term_set_csr, - term_get_csr_x, - term_get_csr_y, - term_set_cell, - term_clear, - term_scroll, - term_redraw_cursor, - input_buffer_stuff, - set_term_font_size, - set_title, - term_set_cell_contents, - term_get_cell_width, - term_get_cell_height, - term_set_csr_show, -}; - -void reinit(int send_sig) { - if (_use_freetype) { - /* Reset font sizes */ - - font_size = 13; - char_height = 17; - char_width = 8; - char_offset = 13; - - if (scale_fonts) { - /* Recalculate scaling */ - font_size *= font_scaling; - char_height *= font_scaling; - char_width *= font_scaling; - char_offset *= font_scaling; - } - - /* Initialize the freetype font pixel sizes */ - FT_Set_Pixel_Sizes(face, font_size, font_size); - FT_Set_Pixel_Sizes(face_bold, font_size, font_size); - FT_Set_Pixel_Sizes(face_italic, font_size, font_size); - FT_Set_Pixel_Sizes(face_bold_italic, font_size, font_size); - FT_Set_Pixel_Sizes(face_extra, font_size, font_size); - FT_Set_Pixel_Sizes(face_symbol, font_size, font_size); - FT_Set_Pixel_Sizes(face_variable, font_size, font_size); - } - int i = 0; - - int old_width = term_width; - int old_height = term_height; - - term_width = window_width / char_width; - term_height = window_height / char_height; - if (term_buffer) { - term_cell_t * new_term_buffer = malloc(sizeof(term_cell_t) * term_width * term_height); - - memset(new_term_buffer, 0x0, sizeof(term_cell_t) * term_width * term_height); - - int offset = 0; - if (term_height < old_height) { - offset = old_height - term_height; - } - for (int row = 0; row < min(old_height, term_height); ++row) { - for (int col = 0; col < min(old_width, term_width); ++col) { - term_cell_t * old_cell = (term_cell_t *)((uintptr_t)term_buffer + ((row + offset) * old_width + col) * sizeof(term_cell_t)); - term_cell_t * new_cell = (term_cell_t *)((uintptr_t)new_term_buffer + (row * term_width + col) * sizeof(term_cell_t)); - *new_cell = *old_cell; - } - } - csr_y -= offset; - free(term_buffer); - - term_buffer = new_term_buffer; - } else { - term_buffer = malloc(sizeof(term_cell_t) * term_width * term_height); - memset(term_buffer, 0x0, sizeof(term_cell_t) * term_width * term_height); - } - - int old_mouse_state = 0; - if (ansi_state) old_mouse_state = ansi_state->mouse_on; - ansi_state = ansi_init(ansi_state, term_width, term_height, &term_callbacks); - ansi_state->mouse_on = old_mouse_state; - - draw_fill(ctx, rgba(0,0,0, TERM_DEFAULT_OPAC)); - render_decors(); - term_redraw_all(); - - struct winsize w; - w.ws_row = term_height; - w.ws_col = term_width; - w.ws_xpixel = term_width * char_width; - w.ws_ypixel = term_height * char_height; - ioctl(fd_master, TIOCSWINSZ, &w); - - if (send_sig) { - kill(child_pid, SIGWINCH); - } -} - -static void resize_finish(int width, int height) { - static int resize_attempts = 0; - - int extra_x = 0; - int extra_y = 0; - - if (!_no_frame) { - extra_x = decor_width(); - extra_y = decor_height(); - } - - int t_window_width = width - extra_x; - int t_window_height = height - extra_y; - - if (t_window_width < char_width * 20 || t_window_height < char_height * 10) { - resize_attempts++; - int n_width = extra_x + max(char_width * 20, t_window_width); - int n_height = extra_y + max(char_height * 10, t_window_height); - yutani_window_resize_offer(yctx, window, n_width, n_height); - return; - } - - if (!_free_size && (t_window_width % char_width != 0 || t_window_height % char_height != 0 && resize_attempts < 3)) { - resize_attempts++; - int n_width = extra_x + t_window_width - (t_window_width % char_width); - int n_height = extra_y + t_window_height - (t_window_height % char_height); - yutani_window_resize_offer(yctx, window, n_width, n_height); - return; - } - - resize_attempts = 0; - - yutani_window_resize_accept(yctx, window, width, height); - window_width = window->width - extra_x; - window_height = window->height - extra_y; - - reinit_graphics_yutani(ctx, window); - reinit(1); - - yutani_window_resize_done(yctx, window); - yutani_flip(yctx, window); -} - -void mouse_event(int button, int x, int y) { - char buf[7]; - sprintf(buf, "\033[M%c%c%c", button + 32, x + 33, y + 33); - handle_input_s(buf); -} - -void * handle_incoming(void) { - - yutani_msg_t * m = yutani_poll(yctx); - if (m) { - switch (m->type) { - case YUTANI_MSG_KEY_EVENT: - { - struct yutani_msg_key_event * ke = (void*)m->data; - int ret = (ke->event.action == KEY_ACTION_DOWN) && (ke->event.key); - key_event(ret, &ke->event); - } - break; - case YUTANI_MSG_WINDOW_FOCUS_CHANGE: - { - struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); - if (win) { - win->focused = wf->focused; - render_decors(); - } - } - break; - case YUTANI_MSG_SESSION_END: - { - kill(child_pid, SIGKILL); - exit_application = 1; - } - break; - case YUTANI_MSG_RESIZE_OFFER: - { - struct yutani_msg_window_resize * wr = (void*)m->data; - resize_finish(wr->width, wr->height); - } - break; - case YUTANI_MSG_WINDOW_MOUSE_EVENT: - { - struct yutani_msg_window_mouse_event * me = (void*)m->data; - if (!_no_frame) { - if (decor_handle_event(yctx, m) == DECOR_CLOSE) { - kill(child_pid, SIGKILL); - exit_application = 1; - break; - } - } - if (me->new_x < 0 || me->new_x >= window_width || me->new_y < 0 || me->new_y >= window_height) { - break; - } - /* Map Cursor Action */ - if (ansi_state->mouse_on) { - int new_x = me->new_x; - int new_y = me->new_y; - if (!_no_frame) { - new_x -= decor_left_width; - new_y -= decor_top_height; - } - /* Convert from coordinate to cell positon */ - new_x /= char_width; - new_y /= char_height; - - if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { - mouse_event(32+32, new_x, new_y); - } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { - mouse_event(32+32+1, new_x, new_y); - } - - if (me->buttons != button_state) { - /* Figure out what changed */ - if (me->buttons & YUTANI_MOUSE_BUTTON_LEFT && !(button_state & YUTANI_MOUSE_BUTTON_LEFT)) mouse_event(0, new_x, new_y); - if (me->buttons & YUTANI_MOUSE_BUTTON_MIDDLE && !(button_state & YUTANI_MOUSE_BUTTON_MIDDLE)) mouse_event(1, new_x, new_y); - if (me->buttons & YUTANI_MOUSE_BUTTON_RIGHT && !(button_state & YUTANI_MOUSE_BUTTON_RIGHT)) mouse_event(2, new_x, new_y); - if (!(me->buttons & YUTANI_MOUSE_BUTTON_LEFT) && button_state & YUTANI_MOUSE_BUTTON_LEFT) mouse_event(3, new_x, new_y); - if (!(me->buttons & YUTANI_MOUSE_BUTTON_MIDDLE) && button_state & YUTANI_MOUSE_BUTTON_MIDDLE) mouse_event(3, new_x, new_y); - if (!(me->buttons & YUTANI_MOUSE_BUTTON_RIGHT) && button_state & YUTANI_MOUSE_BUTTON_RIGHT) mouse_event(3, new_x, new_y); - last_mouse_x = new_x; - last_mouse_y = new_y; - button_state = me->buttons; - } else if (ansi_state->mouse_on == 2) { - /* Report motion for pressed buttons */ - if (last_mouse_x == new_x && last_mouse_y == new_y) break; - if (button_state & YUTANI_MOUSE_BUTTON_LEFT) mouse_event(32, new_x, new_y); - if (button_state & YUTANI_MOUSE_BUTTON_MIDDLE) mouse_event(33, new_x, new_y); - if (button_state & YUTANI_MOUSE_BUTTON_RIGHT) mouse_event(34, new_x, new_y); - last_mouse_x = new_x; - last_mouse_y = new_y; - } - } else { - if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { - scroll_up(5); - } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { - scroll_down(5); - } - } - } - break; - default: - break; - } - free(m); - } -} - -void maybe_flip_cursor(void) { - uint64_t ticks = get_ticks(); - if (ticks > mouse_ticks + 600000LL) { - mouse_ticks = ticks; - flip_cursor(); - } -} - -int main(int argc, char ** argv) { - - _use_freetype = 1; - _login_shell = 0; - - static struct option long_opts[] = { - {"fullscreen", no_argument, 0, 'F'}, - {"bitmap", no_argument, 0, 'b'}, - {"login", no_argument, 0, 'l'}, - {"help", no_argument, 0, 'h'}, - {"kernel", no_argument, 0, 'k'}, - {"grid", no_argument, 0, 'x'}, - {"no-frame", no_argument, 0, 'n'}, - {"scale", required_argument, 0, 's'}, - {"geometry", required_argument, 0, 'g'}, - {0,0,0,0} - }; - - /* Read some arguments */ - int index, c; - while ((c = getopt_long(argc, argv, "bhxnFlks:g:", long_opts, &index)) != -1) { - if (!c) { - if (long_opts[index].flag == 0) { - c = long_opts[index].val; - } - } - switch (c) { - case 'k': - _force_kernel = 1; - break; - case 'x': - _free_size = 0; - break; - case 'l': - _login_shell = 1; - break; - case 'n': - _no_frame = 1; - break; - case 'F': - _fullscreen = 1; - _no_frame = 1; - break; - case 'b': - _use_freetype = 0; - break; - case 'h': - usage(argv); - return 0; - break; - case 's': - scale_fonts = 1; - font_scaling = atof(optarg); - break; - case 'g': - { - char * c = strstr(optarg, "x"); - if (c) { - *c = '\0'; - c++; - window_width = atoi(optarg); - window_height = atoi(c); - } - } - break; - case '?': - break; - default: - break; - } - } - - putenv("TERM=toaru"); - - /* Initialize the windowing library */ - yctx = yutani_init(); - - if (_fullscreen) { - window_width = yctx->display_width; - window_height = yctx->display_height; - } - - if (_no_frame) { - window = yutani_window_create(yctx, window_width, window_height); - } else { - init_decorations(); - window = yutani_window_create(yctx, window_width + decor_left_width + decor_right_width, window_height + decor_top_height + decor_bottom_height); - } - - if (_fullscreen) { - yutani_set_stack(yctx, window, YUTANI_ZORDER_BOTTOM); - window->focused = 1; - } else { - window->focused = 0; - } - - /* Initialize the graphics context */ - ctx = init_graphics_yutani(window); - - /* Clear to black */ - draw_fill(ctx, rgba(0,0,0,0)); - - yutani_window_move(yctx, window, yctx->display_width / 2 - window->width / 2, yctx->display_height / 2 - window->height / 2); - - if (_use_freetype) { - int error; - error = FT_Init_FreeType(&library); - if (error) return 1; - - char * font = NULL; - size_t s; - - /* XXX Use shmemfont library */ - - font = loadMemFont("/usr/share/fonts/DejaVuSansMono.ttf", "monospace", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face); if (error) return 1; - - font = loadMemFont("/usr/share/fonts/DejaVuSansMono-Bold.ttf", "monospace.bold", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face_bold); if (error) return 1; - - font = loadMemFont("/usr/share/fonts/DejaVuSansMono-Oblique.ttf", "monospace.italic", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face_italic); if (error) return 1; - - font = loadMemFont("/usr/share/fonts/DejaVuSansMono-BoldOblique.ttf", "monospace.bolditalic", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face_bold_italic); if (error) return 1; - - error = FT_New_Face(library, "/usr/share/fonts/VLGothic.ttf", 0, &face_extra); - - error = FT_New_Face(library, "/usr/share/fonts/Symbola.ttf", 0, &face_symbol); - - font = loadMemFont("/usr/share/fonts/DejaVuSans.ttf", "sans-serif", &s); - error = FT_New_Memory_Face(library, font, s, 0, &face_variable); if (error) return 1; - - } - - syscall_openpty(&fd_master, &fd_slave, NULL, NULL, NULL); - - terminal = fdopen(fd_slave, "w"); - - reinit(0); - - fflush(stdin); - - int pid = getpid(); - uint32_t f = fork(); - - if (getpid() != pid) { - dup2(fd_slave, 0); - dup2(fd_slave, 1); - dup2(fd_slave, 2); - - if (argv[optind] != NULL) { - char * tokens[] = {argv[optind], NULL}; - int i = execvp(tokens[0], tokens); - fprintf(stderr, "Failed to launch requested startup application.\n"); - } else { - if (_login_shell) { - char * tokens[] = {"/bin/login",NULL}; - int i = execvp(tokens[0], tokens); - } else { - char * shell = getenv("SHELL"); - if (!shell) shell = "/bin/sh"; /* fallback */ - char * tokens[] = {shell,NULL}; - int i = execvp(tokens[0], tokens); - } - } - - exit_application = 1; - - return 1; - } else { - - if (_force_kernel) { - /* Request kernel output to this terminal */ - //syscall_system_function(4, (char **)fd_slave); - } - - child_pid = f; - - int fds[2] = {fileno(yctx->sock), fd_master}; - - unsigned char buf[1024]; - while (!exit_application) { - - int index = syscall_fswait2(2,fds,200); - - check_for_exit(); - - if (index == 1) { - maybe_flip_cursor(); - int r = read(fd_master, buf, 1024); - for (uint32_t i = 0; i < r; ++i) { - ansi_put(ansi_state, buf[i]); - } - display_flip(); - } else if (index == 0) { - maybe_flip_cursor(); - handle_incoming(); - } else if (index == 2) { - maybe_flip_cursor(); - } - } - - } - - yutani_close(yctx, window); - - return 0; -} diff --git a/userspace/lib/dlfcn.h b/userspace/lib/dlfcn.h deleted file mode 100644 index 0b88be5e..00000000 --- a/userspace/lib/dlfcn.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#define RTLD_LAZY 0 -#define RTLD_NOW 1 - - -extern void * dlopen(const char *, int); -extern int dlclose(void *); -extern void * dlsym(void *, const char *); -extern char * dlerror(void); - diff --git a/userspace/lib/graphics.h b/userspace/lib/graphics.h deleted file mode 100644 index 548dcb69..00000000 --- a/userspace/lib/graphics.h +++ /dev/null @@ -1,86 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ -#pragma once - -#include -#include -#include -#include -#include - -#define GFX_W(ctx) ((ctx)->width) /* Display width */ -#define GFX_H(ctx) ((ctx)->height) /* Display height */ -#define GFX_B(ctx) ((ctx)->depth / 8) /* Display byte depth */ - -#define _RED(color) ((color & 0x00FF0000) / 0x10000) -#define _GRE(color) ((color & 0x0000FF00) / 0x100) -#define _BLU(color) ((color & 0x000000FF) / 0x1) -#define _ALP(color) ((color & 0xFF000000) / 0x1000000) - -/* - * Macros make verything easier. - */ -#define GFX(ctx,x,y) *((uint32_t *)&((ctx)->backbuffer)[(GFX_W(ctx) * (y) + (x)) * GFX_B(ctx)]) -#define GFXR(ctx,x,y) *((uint32_t *)&((ctx)->buffer)[(GFX_W(ctx) * (y) + (x)) * GFX_B(ctx)]) -#define SPRITE(sprite,x,y) sprite->bitmap[sprite->width * (y) + (x)] -#define SMASKS(sprite,x,y) sprite->masks[sprite->width * (y) + (x)] - -typedef struct sprite { - uint16_t width; - uint16_t height; - uint32_t * bitmap; - uint32_t * masks; - uint32_t blank; - uint8_t alpha; -} sprite_t; - -typedef struct context { - uint16_t width; - uint16_t height; - uint16_t depth; - uint32_t size; - char * buffer; - char * backbuffer; -} gfx_context_t; - -gfx_context_t * init_graphics_fullscreen(); -gfx_context_t * init_graphics_fullscreen_double_buffer(); -void reinit_graphics_fullscreen(gfx_context_t * ctx); - -#define ALPHA_OPAQUE 0 -#define ALPHA_MASK 1 -#define ALPHA_EMBEDDED 2 -#define ALPHA_INDEXED 3 - -uint32_t rgb(uint8_t r, uint8_t g, uint8_t b); -uint32_t rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -uint32_t alpha_blend(uint32_t bottom, uint32_t top, uint32_t mask); -uint32_t alpha_blend_rgba(uint32_t bottom, uint32_t top); -uint32_t framebuffer_stride(void); - -void flip(gfx_context_t * ctx); -void clear_buffer(gfx_context_t * ctx); - -gfx_context_t * init_graphics_sprite(sprite_t * sprite); -sprite_t * create_sprite(size_t width, size_t height, int alpha); - -void blur_context(gfx_context_t * _dst, gfx_context_t * _src, double amount); -void blur_context_no_vignette(gfx_context_t * _dst, gfx_context_t * _src, double amount); -void blur_context_box(gfx_context_t * _src, int radius); -void sprite_free(sprite_t * sprite); - -void load_sprite(sprite_t * sprite, char * filename); -int load_sprite_png(sprite_t * sprite, char * file); -void draw_sprite(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y); -void draw_line(gfx_context_t * ctx, int32_t x0, int32_t x1, int32_t y0, int32_t y1, uint32_t color); -void draw_line_thick(gfx_context_t * ctx, int32_t x0, int32_t x1, int32_t y0, int32_t y1, uint32_t color, char thickness); -void draw_fill(gfx_context_t * ctx, uint32_t color); - -void draw_sprite_scaled(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, uint16_t width, uint16_t height); -void draw_sprite_scaled_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, uint16_t width, uint16_t height, float alpha); -void draw_sprite_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, float alpha); - -void context_to_png(FILE * file, gfx_context_t * ctx); - -uint32_t premultiply(uint32_t color); - diff --git a/userspace/lib/hashmap.c b/userspace/lib/hashmap.c deleted file mode 120000 index 71c03f87..00000000 --- a/userspace/lib/hashmap.c +++ /dev/null @@ -1 +0,0 @@ -../../kernel/ds/hashmap.c \ No newline at end of file diff --git a/userspace/lib/hashmap.h b/userspace/lib/hashmap.h deleted file mode 120000 index 41f1615e..00000000 --- a/userspace/lib/hashmap.h +++ /dev/null @@ -1 +0,0 @@ -../../kernel/include/hashmap.h \ No newline at end of file diff --git a/userspace/lib/http_parser.c b/userspace/lib/http_parser.c deleted file mode 100644 index 99f5a23a..00000000 --- a/userspace/lib/http_parser.c +++ /dev/null @@ -1,2470 +0,0 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include "http_parser.h" -#include -#include -#include -#include -#include -#include - -#ifndef ULLONG_MAX -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ -#endif - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -#ifndef BIT_AT -# define BIT_AT(a, i) \ - (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ - (1 << ((unsigned int) (i) & 7)))) -#endif - -#ifndef ELEM_AT -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) -#endif - -#define SET_ERRNO(e) \ -do { \ - parser->http_errno = (e); \ -} while(0) - -#define CURRENT_STATE() p_state -#define UPDATE_STATE(V) p_state = (enum state) (V); -#define RETURN(V) \ -do { \ - parser->state = CURRENT_STATE(); \ - return (V); \ -} while (0); -#define REEXECUTE() \ - goto reexecute; \ - - -#ifdef __GNUC__ -# define LIKELY(X) __builtin_expect(!!(X), 1) -# define UNLIKELY(X) __builtin_expect(!!(X), 0) -#else -# define LIKELY(X) (X) -# define UNLIKELY(X) (X) -#endif - - -/* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (LIKELY(settings->on_##FOR)) { \ - parser->state = CURRENT_STATE(); \ - if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - UPDATE_STATE(parser->state); \ - \ - /* We either errored above or got paused; get out */ \ - if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ - return (ER); \ - } \ - } \ -} while (0) - -/* Run the notify callback FOR and consume the current byte */ -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) - -/* Run the notify callback FOR and don't consume the current byte */ -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) - -/* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (FOR##_mark) { \ - if (LIKELY(settings->on_##FOR)) { \ - parser->state = CURRENT_STATE(); \ - if (UNLIKELY(0 != \ - settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - UPDATE_STATE(parser->state); \ - \ - /* We either errored above or got paused; get out */ \ - if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ - return (ER); \ - } \ - } \ - FOR##_mark = NULL; \ - } \ -} while (0) - -/* Run the data callback FOR and consume the current byte */ -#define CALLBACK_DATA(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) - -/* Run the data callback FOR and don't consume the current byte */ -#define CALLBACK_DATA_NOADVANCE(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) - -/* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ -do { \ - if (!FOR##_mark) { \ - FOR##_mark = p; \ - } \ -} while (0) - -/* Don't allow the total size of the HTTP headers (including the status - * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect - * embedders against denial-of-service attacks where the attacker feeds - * us a never-ending header that the embedder keeps buffering. - * - * This check is arguably the responsibility of embedders but we're doing - * it on the embedder's behalf because most won't bother and this way we - * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger - * than any reasonable request or response so this should never affect - * day-to-day operation. - */ -#define COUNT_HEADER_SIZE(V) \ -do { \ - parser->nread += (V); \ - if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \ - SET_ERRNO(HPE_HEADER_OVERFLOW); \ - goto error; \ - } \ -} while (0) - - -#define PROXY_CONNECTION "proxy-connection" -#define CONNECTION "connection" -#define CONTENT_LENGTH "content-length" -#define TRANSFER_ENCODING "transfer-encoding" -#define UPGRADE "upgrade" -#define CHUNKED "chunked" -#define KEEP_ALIVE "keep-alive" -#define CLOSE "close" - - -static const char *method_strings[] = - { -#define XX(num, name, string) #string, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -/* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ -static const char tokens[256] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, '!', 0, '#', '$', '%', '&', '\'', -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0 }; - - -static const int8_t unhex[256] = - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; - - -#if HTTP_PARSER_STRICT -# define T(v) 0 -#else -# define T(v) v -#endif - - -static const uint8_t normal_url_char[32] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; - -#undef T - -enum state - { s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status_start - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_server_start - , s_req_server - , s_req_server_with_at - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_discard_ws - , s_header_value_discard_ws_almost_done - , s_header_value_discard_lws - , s_header_value_start - , s_header_value - , s_header_value_lws - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - , s_headers_done - - /* Important: 's_headers_done' must be the last 'header' state. All - * states beyond this must be 'body' states. It is used for overflow - * checking. See the PARSING_HEADER() macro. - */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - - , s_message_done - }; - - -#define PARSING_HEADER(state) (state <= s_headers_done) - - -enum header_states - { h_general = 0 - , h_C - , h_CO - , h_CON - - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade - - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade - - , h_matching_transfer_encoding_chunked - , h_matching_connection_token_start - , h_matching_connection_keep_alive - , h_matching_connection_close - , h_matching_connection_upgrade - , h_matching_connection_token - - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - , h_connection_upgrade - }; - -enum http_host_state - { - s_http_host_dead = 1 - , s_http_userinfo_start - , s_http_userinfo - , s_http_host_start - , s_http_host_v6_start - , s_http_host - , s_http_host_v6 - , s_http_host_v6_end - , s_http_host_v6_zone_start - , s_http_host_v6_zone - , s_http_host_port_start - , s_http_host_port -}; - -/* Macros for character classes; depends on strict-mode */ -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ - (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ - (c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ - (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ - (c) == '$' || (c) == ',') - -#define STRICT_TOKEN(c) (tokens[(unsigned char)c]) - -#if HTTP_PARSER_STRICT -#define TOKEN(c) (tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') -#else -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) \ - (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -#define IS_HOST_CHAR(c) \ - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') -#endif - - -#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) - - -#if HTTP_PARSER_STRICT -# define STRICT_CHECK(cond) \ -do { \ - if (cond) { \ - SET_ERRNO(HPE_STRICT); \ - goto error; \ - } \ -} while (0) -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -#else -# define STRICT_CHECK(cond) -# define NEW_MESSAGE() start_state -#endif - - -/* Map errno values to strings for human-readable output */ -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, -static struct { - const char *name; - const char *description; -} http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -}; -#undef HTTP_STRERROR_GEN - -int http_message_needs_eof(const http_parser *parser); - -/* Our URL parser. - * - * This is designed to be shared by http_parser_execute() for URL validation, - * hence it has a state transition + byte-for-byte interface. In addition, it - * is meant to be embedded in http_parser_parse_url(), which does the dirty - * work of turning state transitions URL components for its API. - * - * This function should only be invoked with non-space characters. It is - * assumed that the caller cares about (and can detect) the transition between - * URL and non-URL states by looking for these. - */ -static enum state -parse_url_char(enum state s, const char ch) -{ - if (ch == ' ' || ch == '\r' || ch == '\n') { - return s_dead; - } - -#if HTTP_PARSER_STRICT - if (ch == '\t' || ch == '\f') { - return s_dead; - } -#endif - - switch (s) { - case s_req_spaces_before_url: - /* Proxied requests are followed by scheme of an absolute URI (alpha). - * All methods except CONNECT are followed by '/' or '*'. - */ - - if (ch == '/' || ch == '*') { - return s_req_path; - } - - if (IS_ALPHA(ch)) { - return s_req_schema; - } - - break; - - case s_req_schema: - if (IS_ALPHA(ch)) { - return s; - } - - if (ch == ':') { - return s_req_schema_slash; - } - - break; - - case s_req_schema_slash: - if (ch == '/') { - return s_req_schema_slash_slash; - } - - break; - - case s_req_schema_slash_slash: - if (ch == '/') { - return s_req_server_start; - } - - break; - - case s_req_server_with_at: - if (ch == '@') { - return s_dead; - } - - /* FALLTHROUGH */ - case s_req_server_start: - case s_req_server: - if (ch == '/') { - return s_req_path; - } - - if (ch == '?') { - return s_req_query_string_start; - } - - if (ch == '@') { - return s_req_server_with_at; - } - - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_server; - } - - break; - - case s_req_path: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - return s_req_query_string_start; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_query_string_start: - case s_req_query_string: - if (IS_URL_CHAR(ch)) { - return s_req_query_string; - } - - switch (ch) { - case '?': - /* allow extra '?' in query string */ - return s_req_query_string; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_fragment_start: - if (IS_URL_CHAR(ch)) { - return s_req_fragment; - } - - switch (ch) { - case '?': - return s_req_fragment; - - case '#': - return s; - } - - break; - - case s_req_fragment: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - case '#': - return s; - } - - break; - - default: - break; - } - - /* We should never fall out of the switch above unless there's an error */ - return s_dead; -} - -size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) -{ - char c, ch; - int8_t unhex_val; - const char *p = data; - const char *header_field_mark = 0; - const char *header_value_mark = 0; - const char *url_mark = 0; - const char *body_mark = 0; - const char *status_mark = 0; - enum state p_state = (enum state) parser->state; - - /* We're in an error state. Don't bother doing anything. */ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return 0; - } - - if (len == 0) { - switch (CURRENT_STATE()) { - case s_body_identity_eof: - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if - * we got paused. - */ - CALLBACK_NOTIFY_NOADVANCE(message_complete); - return 0; - - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; - - default: - SET_ERRNO(HPE_INVALID_EOF_STATE); - return 1; - } - } - - - if (CURRENT_STATE() == s_header_field) - header_field_mark = data; - if (CURRENT_STATE() == s_header_value) - header_value_mark = data; - switch (CURRENT_STATE()) { - case s_req_path: - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_server: - case s_req_server_with_at: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - url_mark = data; - break; - case s_res_status: - status_mark = data; - break; - default: - break; - } - - for (p=data; p != data + len; p++) { - ch = *p; - - if (PARSING_HEADER(CURRENT_STATE())) - COUNT_HEADER_SIZE(1); - -reexecute: - switch (CURRENT_STATE()) { - - case s_dead: - /* this state is used after a 'Connection: close' message - * the parser will error out if it reads another message - */ - if (LIKELY(ch == CR || ch == LF)) - break; - - SET_ERRNO(HPE_CLOSED_CONNECTION); - goto error; - - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') { - UPDATE_STATE(s_res_or_resp_H); - - CALLBACK_NOTIFY(message_begin); - } else { - parser->type = HTTP_REQUEST; - UPDATE_STATE(s_start_req); - REEXECUTE(); - } - - break; - } - - case s_res_or_resp_H: - if (ch == 'T') { - parser->type = HTTP_RESPONSE; - UPDATE_STATE(s_res_HT); - } else { - if (UNLIKELY(ch != 'E')) { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - parser->index = 2; - UPDATE_STATE(s_req_method); - } - break; - - case s_start_res: - { - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - switch (ch) { - case 'H': - UPDATE_STATE(s_res_H); - break; - - case CR: - case LF: - break; - - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - CALLBACK_NOTIFY(message_begin); - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_res_HT); - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_res_HTT); - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - UPDATE_STATE(s_res_HTTP); - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - UPDATE_STATE(s_res_first_http_major); - break; - - case s_res_first_http_major: - if (UNLIKELY(ch < '0' || ch > '9')) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - UPDATE_STATE(s_res_http_major); - break; - - /* major HTTP version or dot */ - case s_res_http_major: - { - if (ch == '.') { - UPDATE_STATE(s_res_first_http_minor); - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (UNLIKELY(parser->http_major > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_res_first_http_minor: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - UPDATE_STATE(s_res_http_minor); - break; - - /* minor HTTP version or end of request line */ - case s_res_http_minor: - { - if (ch == ' ') { - UPDATE_STATE(s_res_first_status_code); - break; - } - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (UNLIKELY(parser->http_minor > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - case s_res_first_status_code: - { - if (!IS_NUM(ch)) { - if (ch == ' ') { - break; - } - - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - parser->status_code = ch - '0'; - UPDATE_STATE(s_res_status_code); - break; - } - - case s_res_status_code: - { - if (!IS_NUM(ch)) { - switch (ch) { - case ' ': - UPDATE_STATE(s_res_status_start); - break; - case CR: - UPDATE_STATE(s_res_line_almost_done); - break; - case LF: - UPDATE_STATE(s_header_field_start); - break; - default: - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (UNLIKELY(parser->status_code > 999)) { - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - - break; - } - - case s_res_status_start: - { - if (ch == CR) { - UPDATE_STATE(s_res_line_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - break; - } - - MARK(status); - UPDATE_STATE(s_res_status); - parser->index = 0; - break; - } - - case s_res_status: - if (ch == CR) { - UPDATE_STATE(s_res_line_almost_done); - CALLBACK_DATA(status); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - CALLBACK_DATA(status); - break; - } - - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - UPDATE_STATE(s_header_field_start); - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (UNLIKELY(!IS_ALPHA(ch))) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - parser->method = (enum http_method) 0; - parser->index = 1; - switch (ch) { - case 'A': parser->method = HTTP_ACL; break; - case 'B': parser->method = HTTP_BIND; break; - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ - break; - case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND */ break; - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - UPDATE_STATE(s_req_method); - - CALLBACK_NOTIFY(message_begin); - - break; - } - - case s_req_method: - { - const char *matcher; - if (UNLIKELY(ch == '\0')) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[parser->index] == '\0') { - UPDATE_STATE(s_req_spaces_before_url); - } else if (ch == matcher[parser->index]) { - ; /* nada */ - } else if (parser->method == HTTP_CONNECT) { - if (parser->index == 1 && ch == 'H') { - parser->method = HTTP_CHECKOUT; - } else if (parser->index == 2 && ch == 'P') { - parser->method = HTTP_COPY; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_MKCOL) { - if (parser->index == 1 && ch == 'O') { - parser->method = HTTP_MOVE; - } else if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_MERGE; - } else if (parser->index == 1 && ch == '-') { - parser->method = HTTP_MSEARCH; - } else if (parser->index == 2 && ch == 'A') { - parser->method = HTTP_MKACTIVITY; - } else if (parser->index == 3 && ch == 'A') { - parser->method = HTTP_MKCALENDAR; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_SUBSCRIBE) { - if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_SEARCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_REPORT) { - if (parser->index == 2 && ch == 'B') { - parser->method = HTTP_REBIND; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->index == 1 && parser->method == HTTP_POST) { - if (ch == 'R') { - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ - } else if (ch == 'U') { - parser->method = HTTP_PUT; /* or HTTP_PURGE */ - } else if (ch == 'A') { - parser->method = HTTP_PATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->index == 2) { - if (parser->method == HTTP_PUT) { - if (ch == 'R') { - parser->method = HTTP_PURGE; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_UNLOCK) { - if (ch == 'S') { - parser->method = HTTP_UNSUBSCRIBE; - } else if(ch == 'B') { - parser->method = HTTP_UNBIND; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { - parser->method = HTTP_PROPPATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - ++parser->index; - break; - } - - case s_req_spaces_before_url: - { - if (ch == ' ') break; - - MARK(url); - if (parser->method == HTTP_CONNECT) { - UPDATE_STATE(s_req_server_start); - } - - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - - break; - } - - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - { - switch (ch) { - /* No whitespace allowed here */ - case ' ': - case CR: - case LF: - SET_ERRNO(HPE_INVALID_URL); - goto error; - default: - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - - break; - } - - case s_req_server: - case s_req_server_with_at: - case s_req_path: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - { - switch (ch) { - case ' ': - UPDATE_STATE(s_req_http_start); - CALLBACK_DATA(url); - break; - case CR: - case LF: - parser->http_major = 0; - parser->http_minor = 9; - UPDATE_STATE((ch == CR) ? - s_req_line_almost_done : - s_header_field_start); - CALLBACK_DATA(url); - break; - default: - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - break; - } - - case s_req_http_start: - switch (ch) { - case 'H': - UPDATE_STATE(s_req_http_H); - break; - case ' ': - break; - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_req_http_HT); - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_req_http_HTT); - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - UPDATE_STATE(s_req_http_HTTP); - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - UPDATE_STATE(s_req_first_http_major); - break; - - /* first digit of major HTTP version */ - case s_req_first_http_major: - if (UNLIKELY(ch < '1' || ch > '9')) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - UPDATE_STATE(s_req_http_major); - break; - - /* major HTTP version or dot */ - case s_req_http_major: - { - if (ch == '.') { - UPDATE_STATE(s_req_first_http_minor); - break; - } - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (UNLIKELY(parser->http_major > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_req_first_http_minor: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - UPDATE_STATE(s_req_http_minor); - break; - - /* minor HTTP version or end of request line */ - case s_req_http_minor: - { - if (ch == CR) { - UPDATE_STATE(s_req_line_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - break; - } - - /* XXX allow spaces after digit? */ - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (UNLIKELY(parser->http_minor > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (UNLIKELY(ch != LF)) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - UPDATE_STATE(s_header_field_start); - break; - } - - case s_header_field_start: - { - if (ch == CR) { - UPDATE_STATE(s_headers_almost_done); - break; - } - - if (ch == LF) { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - UPDATE_STATE(s_headers_almost_done); - REEXECUTE(); - } - - c = TOKEN(ch); - - if (UNLIKELY(!c)) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - MARK(header_field); - - parser->index = 0; - UPDATE_STATE(s_header_field); - - switch (c) { - case 'c': - parser->header_state = h_C; - break; - - case 'p': - parser->header_state = h_matching_proxy_connection; - break; - - case 't': - parser->header_state = h_matching_transfer_encoding; - break; - - case 'u': - parser->header_state = h_matching_upgrade; - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - const char* start = p; - for (; p != data + len; p++) { - ch = *p; - c = TOKEN(ch); - - if (!c) - break; - - switch (parser->header_state) { - case h_general: - break; - - case h_C: - parser->index++; - parser->header_state = (c == 'o' ? h_CO : h_general); - break; - - case h_CO: - parser->index++; - parser->header_state = (c == 'n' ? h_CON : h_general); - break; - - case h_CON: - parser->index++; - switch (c) { - case 'n': - parser->header_state = h_matching_connection; - break; - case 't': - parser->header_state = h_matching_content_length; - break; - default: - parser->header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - parser->index++; - if (parser->index > sizeof(CONNECTION)-1 - || c != CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { - parser->header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING)-1 - || c != TRANSFER_ENCODING[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { - parser->header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE)-1 - || c != UPGRADE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(UPGRADE)-2) { - parser->header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - } - - COUNT_HEADER_SIZE(p - start); - - if (p == data + len) { - --p; - break; - } - - if (ch == ':') { - UPDATE_STATE(s_header_value_discard_ws); - CALLBACK_DATA(header_field); - break; - } - - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - case s_header_value_discard_ws: - if (ch == ' ' || ch == '\t') break; - - if (ch == CR) { - UPDATE_STATE(s_header_value_discard_ws_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_value_discard_lws); - break; - } - - /* FALLTHROUGH */ - - case s_header_value_start: - { - MARK(header_value); - - UPDATE_STATE(s_header_value); - parser->index = 0; - - c = LOWER(ch); - - switch (parser->header_state) { - case h_upgrade: - parser->flags |= F_UPGRADE; - parser->header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) { - parser->header_state = h_matching_transfer_encoding_chunked; - } else { - parser->header_state = h_general; - } - break; - - case h_content_length: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = ch - '0'; - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - parser->header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - parser->header_state = h_matching_connection_close; - } else if (c == 'u') { - parser->header_state = h_matching_connection_upgrade; - } else { - parser->header_state = h_matching_connection_token; - } - break; - - /* Multi-value `Connection` header */ - case h_matching_connection_token_start: - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - const char* start = p; - enum header_states h_state = (enum header_states) parser->header_state; - for (; p != data + len; p++) { - ch = *p; - if (ch == CR) { - UPDATE_STATE(s_header_almost_done); - parser->header_state = h_state; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_almost_done); - COUNT_HEADER_SIZE(p - start); - parser->header_state = h_state; - CALLBACK_DATA_NOADVANCE(header_value); - REEXECUTE(); - } - - c = LOWER(ch); - - switch (h_state) { - case h_general: - { - const char* p_cr; - const char* p_lf; - size_t limit = data + len - p; - - limit = MIN(limit, HTTP_MAX_HEADER_SIZE); - - p_cr = (const char*) memchr(p, CR, limit); - p_lf = (const char*) memchr(p, LF, limit); - if (p_cr != NULL) { - if (p_lf != NULL && p_cr >= p_lf) - p = p_lf; - else - p = p_cr; - } else if (UNLIKELY(p_lf != NULL)) { - p = p_lf; - } else { - p = data + len; - } - --p; - - break; - } - - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; - - case h_content_length: - { - uint64_t t; - - if (ch == ' ') break; - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; - } - - t = parser->content_length; - t *= 10; - t += ch - '0'; - - /* Overflow? Test against a conservative limit for simplicity. */ - if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; - } - - parser->content_length = t; - break; - } - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - parser->index++; - if (parser->index > sizeof(CHUNKED)-1 - || c != CHUNKED[parser->index]) { - h_state = h_general; - } else if (parser->index == sizeof(CHUNKED)-2) { - h_state = h_transfer_encoding_chunked; - } - break; - - case h_matching_connection_token_start: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - h_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - h_state = h_matching_connection_close; - } else if (c == 'u') { - h_state = h_matching_connection_upgrade; - } else if (STRICT_TOKEN(c)) { - h_state = h_matching_connection_token; - } else if (c == ' ' || c == '\t') { - /* Skip lws */ - } else { - h_state = h_general; - } - break; - - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - parser->index++; - if (parser->index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(KEEP_ALIVE)-2) { - h_state = h_connection_keep_alive; - } - break; - - /* looking for 'Connection: close' */ - case h_matching_connection_close: - parser->index++; - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(CLOSE)-2) { - h_state = h_connection_close; - } - break; - - /* looking for 'Connection: upgrade' */ - case h_matching_connection_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE) - 1 || - c != UPGRADE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(UPGRADE)-2) { - h_state = h_connection_upgrade; - } - break; - - case h_matching_connection_token: - if (ch == ',') { - h_state = h_matching_connection_token_start; - parser->index = 0; - } - break; - - case h_transfer_encoding_chunked: - if (ch != ' ') h_state = h_general; - break; - - case h_connection_keep_alive: - case h_connection_close: - case h_connection_upgrade: - if (ch == ',') { - if (h_state == h_connection_keep_alive) { - parser->flags |= F_CONNECTION_KEEP_ALIVE; - } else if (h_state == h_connection_close) { - parser->flags |= F_CONNECTION_CLOSE; - } else if (h_state == h_connection_upgrade) { - parser->flags |= F_CONNECTION_UPGRADE; - } - h_state = h_matching_connection_token_start; - parser->index = 0; - } else if (ch != ' ') { - h_state = h_matching_connection_token; - } - break; - - default: - UPDATE_STATE(s_header_value); - h_state = h_general; - break; - } - } - parser->header_state = h_state; - - COUNT_HEADER_SIZE(p - start); - - if (p == data + len) - --p; - break; - } - - case s_header_almost_done: - { - STRICT_CHECK(ch != LF); - - UPDATE_STATE(s_header_value_lws); - break; - } - - case s_header_value_lws: - { - if (ch == ' ' || ch == '\t') { - UPDATE_STATE(s_header_value_start); - REEXECUTE(); - } - - /* finished the header */ - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - case h_connection_upgrade: - parser->flags |= F_CONNECTION_UPGRADE; - break; - default: - break; - } - - UPDATE_STATE(s_header_field_start); - REEXECUTE(); - } - - case s_header_value_discard_ws_almost_done: - { - STRICT_CHECK(ch != LF); - UPDATE_STATE(s_header_value_discard_lws); - break; - } - - case s_header_value_discard_lws: - { - if (ch == ' ' || ch == '\t') { - UPDATE_STATE(s_header_value_discard_ws); - break; - } else { - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_connection_upgrade: - parser->flags |= F_CONNECTION_UPGRADE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - default: - break; - } - - /* header value was empty */ - MARK(header_value); - UPDATE_STATE(s_header_field_start); - CALLBACK_DATA_NOADVANCE(header_value); - REEXECUTE(); - } - } - - case s_headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) { - /* End of a chunked request */ - UPDATE_STATE(s_message_done); - CALLBACK_NOTIFY_NOADVANCE(chunk_complete); - REEXECUTE(); - } - - UPDATE_STATE(s_headers_done); - - /* Set this here so that on_headers_complete() callbacks can see it */ - parser->upgrade = - ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) == - (F_UPGRADE | F_CONNECTION_UPGRADE) || - parser->method == HTTP_CONNECT); - - /* Here we call the headers_complete callback. This is somewhat - * different than other callbacks because if the user returns 1, we - * will interpret that as saying that this message has no body. This - * is needed for the annoying case of recieving a response to a HEAD - * request. - * - * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so - * we have to simulate it by handling a change in errno below. - */ - if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: - SET_ERRNO(HPE_CB_headers_complete); - RETURN(p - data); /* Error */ - } - } - - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - RETURN(p - data); - } - - REEXECUTE(); - } - - case s_headers_done: - { - int hasBody; - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - hasBody = parser->flags & F_CHUNKED || - (parser->content_length > 0 && parser->content_length != ULLONG_MAX); - if (parser->upgrade && (parser->method == HTTP_CONNECT || - (parser->flags & F_SKIPBODY) || !hasBody)) { - /* Exit, the rest of the message is in a different protocol. */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - RETURN((p - data) + 1); - } - - if (parser->flags & F_SKIPBODY) { - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else if (parser->flags & F_CHUNKED) { - /* chunked encoding - ignore Content-Length header */ - UPDATE_STATE(s_chunk_size_start); - } else { - if (parser->content_length == 0) { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else if (parser->content_length != ULLONG_MAX) { - /* Content-Length header given and non-zero */ - UPDATE_STATE(s_body_identity); - } else { - if (!http_message_needs_eof(parser)) { - /* Assume content-length 0 - read the next */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else { - /* Read body until EOF */ - UPDATE_STATE(s_body_identity_eof); - } - } - } - - break; - } - - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* The difference between advancing content_length and p is because - * the latter will automaticaly advance on the next loop iteration. - * Further, if content_length ends up at 0, we want to see the last - * byte again for our message complete callback. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - UPDATE_STATE(s_message_done); - - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. - * - * The alternative to doing this is to wait for the next byte to - * trigger the data callback, just as in every other case. The - * problem with this is that this makes it difficult for the test - * harness to distinguish between complete-on-EOF and - * complete-on-length. It's not clear that this distinction is - * important for applications, but let's keep it for now. - */ - CALLBACK_DATA_(body, p - body_mark + 1, p - data); - REEXECUTE(); - } - - break; - } - - /* read until EOF */ - case s_body_identity_eof: - MARK(body); - p = data + len - 1; - - break; - - case s_message_done: - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - if (parser->upgrade) { - /* Exit, the rest of the message is in a different protocol. */ - RETURN((p - data) + 1); - } - break; - - case s_chunk_size_start: - { - assert(parser->nread == 1); - assert(parser->flags & F_CHUNKED); - - unhex_val = unhex[(unsigned char)ch]; - if (UNLIKELY(unhex_val == -1)) { - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - parser->content_length = unhex_val; - UPDATE_STATE(s_chunk_size); - break; - } - - case s_chunk_size: - { - uint64_t t; - - assert(parser->flags & F_CHUNKED); - - if (ch == CR) { - UPDATE_STATE(s_chunk_size_almost_done); - break; - } - - unhex_val = unhex[(unsigned char)ch]; - - if (unhex_val == -1) { - if (ch == ';' || ch == ' ') { - UPDATE_STATE(s_chunk_parameters); - break; - } - - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - t = parser->content_length; - t *= 16; - t += unhex_val; - - /* Overflow? Test against a conservative limit for simplicity. */ - if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this shit. TODO check for overflow */ - if (ch == CR) { - UPDATE_STATE(s_chunk_size_almost_done); - break; - } - break; - } - - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - if (parser->content_length == 0) { - parser->flags |= F_TRAILING; - UPDATE_STATE(s_header_field_start); - } else { - UPDATE_STATE(s_chunk_data); - } - CALLBACK_NOTIFY(chunk_header); - break; - } - - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* See the explanation in s_body_identity for why the content - * length and data pointers are managed this way. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - UPDATE_STATE(s_chunk_data_almost_done); - } - - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - assert(parser->content_length == 0); - STRICT_CHECK(ch != CR); - UPDATE_STATE(s_chunk_data_done); - CALLBACK_DATA(body); - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - parser->nread = 0; - UPDATE_STATE(s_chunk_size_start); - CALLBACK_NOTIFY(chunk_complete); - break; - - default: - assert(0 && "unhandled state"); - SET_ERRNO(HPE_INVALID_INTERNAL_STATE); - goto error; - } - } - - /* Run callbacks for any marks that we have leftover after we ran our of - * bytes. There should be at most one of these set, so it's OK to invoke - * them in series (unset marks will not result in callbacks). - * - * We use the NOADVANCE() variety of callbacks here because 'p' has already - * overflowed 'data' and this allows us to correct for the off-by-one that - * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' - * value that's in-bounds). - */ - - assert(((header_field_mark ? 1 : 0) + - (header_value_mark ? 1 : 0) + - (url_mark ? 1 : 0) + - (body_mark ? 1 : 0) + - (status_mark ? 1 : 0)) <= 1); - - CALLBACK_DATA_NOADVANCE(header_field); - CALLBACK_DATA_NOADVANCE(header_value); - CALLBACK_DATA_NOADVANCE(url); - CALLBACK_DATA_NOADVANCE(body); - CALLBACK_DATA_NOADVANCE(status); - - RETURN(len); - -error: - if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { - SET_ERRNO(HPE_UNKNOWN); - } - - RETURN(p - data); -} - - -/* Does the parser need to see an EOF to find the end of the message? */ -int -http_message_needs_eof (const http_parser *parser) -{ - if (parser->type == HTTP_REQUEST) { - return 0; - } - - /* See RFC 2616 section 4.4 */ - if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ - parser->status_code == 204 || /* No Content */ - parser->status_code == 304 || /* Not Modified */ - parser->flags & F_SKIPBODY) { /* response to a HEAD request */ - return 0; - } - - if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { - return 0; - } - - return 1; -} - - -int -http_should_keep_alive (const http_parser *parser) -{ - if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) { - return 0; - } - } else { - /* HTTP/1.0 or earlier */ - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { - return 0; - } - } - - return !http_message_needs_eof(parser); -} - - -const char * -http_method_str (enum http_method m) -{ - return ELEM_AT(method_strings, m, ""); -} - - -void -http_parser_init (http_parser *parser, enum http_parser_type t) -{ - void *data = parser->data; /* preserve application data */ - memset(parser, 0, sizeof(*parser)); - parser->data = data; - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); - parser->http_errno = HPE_OK; -} - -void -http_parser_settings_init(http_parser_settings *settings) -{ - memset(settings, 0, sizeof(*settings)); -} - -const char * -http_errno_name(enum http_errno err) { - assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); - return http_strerror_tab[err].name; -} - -const char * -http_errno_description(enum http_errno err) { - assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); - return http_strerror_tab[err].description; -} - -static enum http_host_state -http_parse_host_char(enum http_host_state s, const char ch) { - switch(s) { - case s_http_userinfo: - case s_http_userinfo_start: - if (ch == '@') { - return s_http_host_start; - } - - if (IS_USERINFO_CHAR(ch)) { - return s_http_userinfo; - } - break; - - case s_http_host_start: - if (ch == '[') { - return s_http_host_v6_start; - } - - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - break; - - case s_http_host: - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - /* FALLTHROUGH */ - case s_http_host_v6_end: - if (ch == ':') { - return s_http_host_port_start; - } - - break; - - case s_http_host_v6: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_start: - if (IS_HEX(ch) || ch == ':' || ch == '.') { - return s_http_host_v6; - } - - if (s == s_http_host_v6 && ch == '%') { - return s_http_host_v6_zone_start; - } - break; - - case s_http_host_v6_zone: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_zone_start: - /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ - if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || - ch == '~') { - return s_http_host_v6_zone; - } - break; - - case s_http_host_port: - case s_http_host_port_start: - if (IS_NUM(ch)) { - return s_http_host_port; - } - - break; - - default: - break; - } - return s_http_host_dead; -} - -static int -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { - assert(u->field_set & (1 << UF_HOST)); - enum http_host_state s; - - const char *p; - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; - - u->field_data[UF_HOST].len = 0; - - s = found_at ? s_http_userinfo_start : s_http_host_start; - - for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { - enum http_host_state new_s = http_parse_host_char(s, *p); - - if (new_s == s_http_host_dead) { - return 1; - } - - switch(new_s) { - case s_http_host: - if (s != s_http_host) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6: - if (s != s_http_host_v6) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6_zone_start: - case s_http_host_v6_zone: - u->field_data[UF_HOST].len++; - break; - - case s_http_host_port: - if (s != s_http_host_port) { - u->field_data[UF_PORT].off = p - buf; - u->field_data[UF_PORT].len = 0; - u->field_set |= (1 << UF_PORT); - } - u->field_data[UF_PORT].len++; - break; - - case s_http_userinfo: - if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = p - buf ; - u->field_data[UF_USERINFO].len = 0; - u->field_set |= (1 << UF_USERINFO); - } - u->field_data[UF_USERINFO].len++; - break; - - default: - break; - } - s = new_s; - } - - /* Make sure we don't end somewhere unexpected */ - switch (s) { - case s_http_host_start: - case s_http_host_v6_start: - case s_http_host_v6: - case s_http_host_v6_zone_start: - case s_http_host_v6_zone: - case s_http_host_port_start: - case s_http_userinfo: - case s_http_userinfo_start: - return 1; - default: - break; - } - - return 0; -} - -int -http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) -{ - enum state s; - const char *p; - enum http_parser_url_fields uf, old_uf; - int found_at = 0; - - u->port = u->field_set = 0; - s = is_connect ? s_req_server_start : s_req_spaces_before_url; - old_uf = UF_MAX; - - for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); - - /* Figure out the next field that we're operating on */ - switch (s) { - case s_dead: - return 1; - - /* Skip delimeters */ - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_query_string_start: - case s_req_fragment_start: - continue; - - case s_req_schema: - uf = UF_SCHEMA; - break; - - case s_req_server_with_at: - found_at = 1; - - /* FALLTROUGH */ - case s_req_server: - uf = UF_HOST; - break; - - case s_req_path: - uf = UF_PATH; - break; - - case s_req_query_string: - uf = UF_QUERY; - break; - - case s_req_fragment: - uf = UF_FRAGMENT; - break; - - default: - assert(!"Unexpected state"); - return 1; - } - - /* Nothing's changed; soldier on */ - if (uf == old_uf) { - u->field_data[uf].len++; - continue; - } - - u->field_data[uf].off = p - buf; - u->field_data[uf].len = 1; - - u->field_set |= (1 << uf); - old_uf = uf; - } - - /* host must be present if there is a schema */ - /* parsing http:///toto will fail */ - if ((u->field_set & (1 << UF_SCHEMA)) && - (u->field_set & (1 << UF_HOST)) == 0) { - return 1; - } - - if (u->field_set & (1 << UF_HOST)) { - if (http_parse_host(buf, u, found_at) != 0) { - return 1; - } - } - - /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { - return 1; - } - - if (u->field_set & (1 << UF_PORT)) { - /* Don't bother with endp; we've already validated the string */ - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); - - /* Ports have a max value of 2^16 */ - if (v > 0xffff) { - return 1; - } - - u->port = (uint16_t) v; - } - - return 0; -} - -void -http_parser_pause(http_parser *parser, int paused) { - /* Users should only be pausing/unpausing a parser that is not in an error - * state. In non-debug builds, there's not much that we can do about this - * other than ignore it. - */ - if (HTTP_PARSER_ERRNO(parser) == HPE_OK || - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); - } else { - assert(0 && "Attempting to pause parser in error state"); - } -} - -int -http_body_is_final(const struct http_parser *parser) { - return parser->state == s_message_done; -} - -unsigned long -http_parser_version(void) { - return HTTP_PARSER_VERSION_MAJOR * 0x10000 | - HTTP_PARSER_VERSION_MINOR * 0x00100 | - HTTP_PARSER_VERSION_PATCH * 0x00001; -} diff --git a/userspace/lib/http_parser.h b/userspace/lib/http_parser.h deleted file mode 100644 index 3ad94dd6..00000000 --- a/userspace/lib/http_parser.h +++ /dev/null @@ -1,346 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -/* Also update SONAME in the Makefile whenever you change these. */ -#define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 5 -#define HTTP_PARSER_VERSION_PATCH 0 - -#include -#if defined(_WIN32) && !defined(__MINGW32__) && \ - (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) -#include -#include -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif - -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ -#ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 -#endif - -/* Maximium header size allowed. If the macro is not defined - * before including this header then the default is used. To - * change the maximum header size, define the macro in the build - * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove - * the effective limit on the size of the header, define the macro - * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) - */ -#ifndef HTTP_MAX_HEADER_SIZE -# define HTTP_MAX_HEADER_SIZE (80*1024) -#endif - -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; - - -/* Callbacks should return non-zero to indicate an error. The parser will - * then halt execution. - * - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser - * returning '1' from on_headers_complete will tell the parser that it - * should not expect a body. This is used when receiving a response to a - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: - * chunked' headers that indicate the presence of a body. - * - * http_data_cb does not return data chunks. It will be called arbitrarily - * many times for each string. E.G. you might get 10 callbacks for "on_url" - * each providing just a few characters more data. - */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); - - -/* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ - XX(0, DELETE, DELETE) \ - XX(1, GET, GET) \ - XX(2, HEAD, HEAD) \ - XX(3, POST, POST) \ - XX(4, PUT, PUT) \ - /* pathological */ \ - XX(5, CONNECT, CONNECT) \ - XX(6, OPTIONS, OPTIONS) \ - XX(7, TRACE, TRACE) \ - /* WebDAV */ \ - XX(8, COPY, COPY) \ - XX(9, LOCK, LOCK) \ - XX(10, MKCOL, MKCOL) \ - XX(11, MOVE, MOVE) \ - XX(12, PROPFIND, PROPFIND) \ - XX(13, PROPPATCH, PROPPATCH) \ - XX(14, SEARCH, SEARCH) \ - XX(15, UNLOCK, UNLOCK) \ - XX(16, BIND, BIND) \ - XX(17, REBIND, REBIND) \ - XX(18, UNBIND, UNBIND) \ - XX(19, ACL, ACL) \ - /* subversion */ \ - XX(20, REPORT, REPORT) \ - XX(21, MKACTIVITY, MKACTIVITY) \ - XX(22, CHECKOUT, CHECKOUT) \ - XX(23, MERGE, MERGE) \ - /* upnp */ \ - XX(24, MSEARCH, M-SEARCH) \ - XX(25, NOTIFY, NOTIFY) \ - XX(26, SUBSCRIBE, SUBSCRIBE) \ - XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - XX(28, PATCH, PATCH) \ - XX(29, PURGE, PURGE) \ - /* CalDAV */ \ - XX(30, MKCALENDAR, MKCALENDAR) \ - -enum http_method - { -#define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; - - -/* Flag values for http_parser.flags field */ -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_CONNECTION_UPGRADE = 1 << 3 - , F_TRAILING = 1 << 4 - , F_UPGRADE = 1 << 5 - , F_SKIPBODY = 1 << 6 - }; - - -/* Map for errno-related constants - * - * The provided argument should be a macro that takes 2 arguments. - */ -#define HTTP_ERRNO_MAP(XX) \ - /* No error */ \ - XX(OK, "success") \ - \ - /* Callback-related errors */ \ - XX(CB_message_begin, "the on_message_begin callback failed") \ - XX(CB_url, "the on_url callback failed") \ - XX(CB_header_field, "the on_header_field callback failed") \ - XX(CB_header_value, "the on_header_value callback failed") \ - XX(CB_headers_complete, "the on_headers_complete callback failed") \ - XX(CB_body, "the on_body callback failed") \ - XX(CB_message_complete, "the on_message_complete callback failed") \ - XX(CB_status, "the on_status callback failed") \ - XX(CB_chunk_header, "the on_chunk_header callback failed") \ - XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ - \ - /* Parsing-related errors */ \ - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - XX(INVALID_VERSION, "invalid HTTP version") \ - XX(INVALID_STATUS, "invalid HTTP status code") \ - XX(INVALID_METHOD, "invalid HTTP method") \ - XX(INVALID_URL, "invalid URL") \ - XX(INVALID_HOST, "invalid host") \ - XX(INVALID_PORT, "invalid port") \ - XX(INVALID_PATH, "invalid path") \ - XX(INVALID_QUERY_STRING, "invalid query string") \ - XX(INVALID_FRAGMENT, "invalid fragment") \ - XX(LF_EXPECTED, "LF character expected") \ - XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - XX(INVALID_CONSTANT, "invalid constant string") \ - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - XX(STRICT, "strict mode assertion failed") \ - XX(PAUSED, "parser is paused") \ - XX(UNKNOWN, "an unknown error occurred") - - -/* Define HPE_* values for each errno value above */ -#define HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) -}; -#undef HTTP_ERRNO_GEN - - -/* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) - - -struct http_parser { - /** PRIVATE **/ - unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 7; /* F_* values from 'flags' enum; semi-public */ - unsigned int state : 7; /* enum state from http_parser.c */ - unsigned int header_state : 8; /* enum header_state from http_parser.c */ - unsigned int index : 8; /* index into current matcher */ - - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned int status_code : 16; /* responses only */ - unsigned int method : 8; /* requests only */ - unsigned int http_errno : 7; - - /* 1 = Upgrade header was present and the parser has exited because of that. - * 0 = No upgrade header present. - * Should be checked when http_parser_execute() returns in addition to - * error checking. - */ - unsigned int upgrade : 1; - - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ -}; - - -struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_data_cb on_status; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; - /* When on_chunk_header is called, the current chunk length is stored - * in parser->content_length. - */ - http_cb on_chunk_header; - http_cb on_chunk_complete; -}; - - -enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; - - -/* Result structure for http_parser_parse_url(). - * - * Callers should index into field_data[] with UF_* values iff field_set - * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and - * because we probably have padding left over), we convert any port to - * a uint16_t. - */ -struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ - - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; -}; - - -/* Returns the library version. Bits 16-23 contain the major version number, - * bits 8-15 the minor version number and bits 0-7 the patch level. - * Usage example: - * - * unsigned long version = http_parser_version(); - * unsigned major = (version >> 16) & 255; - * unsigned minor = (version >> 8) & 255; - * unsigned patch = version & 255; - * printf("http_parser v%u.%u.%u\n", major, minor, patch); - */ -unsigned long http_parser_version(void); - -void http_parser_init(http_parser *parser, enum http_parser_type type); - - -/* Initialize http_parser_settings members to 0 - */ -void http_parser_settings_init(http_parser_settings *settings); - - -/* Executes the parser. Returns number of parsed bytes. Sets - * `parser->http_errno` on error. */ -size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); - - -/* If http_should_keep_alive() in the on_headers_complete or - * on_message_complete callback returns 0, then this should be - * the last message on the connection. - * If you are the server, respond with the "Connection: close" header. - * If you are the client, close the connection. - */ -int http_should_keep_alive(const http_parser *parser); - -/* Returns a string version of the HTTP method. */ -const char *http_method_str(enum http_method m); - -/* Return a string name of the given error */ -const char *http_errno_name(enum http_errno err); - -/* Return a string description of the given error */ -const char *http_errno_description(enum http_errno err); - -/* Parse a URL; return nonzero on failure */ -int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); - -/* Pause or un-pause the parser; a nonzero value pauses */ -void http_parser_pause(http_parser *parser, int paused); - -/* Checks if this is the final chunk of the body. */ -int http_body_is_final(const http_parser *parser); - -#ifdef __cplusplus -} -#endif diff --git a/userspace/lib/list.c b/userspace/lib/list.c deleted file mode 120000 index 1e2c67cf..00000000 --- a/userspace/lib/list.c +++ /dev/null @@ -1 +0,0 @@ -../../kernel/ds/list.c \ No newline at end of file diff --git a/userspace/lib/list.h b/userspace/lib/list.h deleted file mode 120000 index f7ef3827..00000000 --- a/userspace/lib/list.h +++ /dev/null @@ -1 +0,0 @@ -../../kernel/include/list.h \ No newline at end of file diff --git a/userspace/lib/mouse.h b/userspace/lib/mouse.h deleted file mode 120000 index b2f85de2..00000000 --- a/userspace/lib/mouse.h +++ /dev/null @@ -1 +0,0 @@ -../../kernel/include/mouse.h \ No newline at end of file diff --git a/userspace/lib/pex.h b/userspace/lib/pex.h deleted file mode 100644 index 6ffc0371..00000000 --- a/userspace/lib/pex.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include - -typedef struct pex_packet { - uintptr_t source; - size_t size; - uint8_t data[]; -} pex_packet_t; -#define MAX_PACKET_SIZE 1024 -#define PACKET_SIZE (sizeof(pex_packet_t) + MAX_PACKET_SIZE) - -typedef struct pex_header { - uintptr_t target; - uint8_t data[]; -} pex_header_t; - -size_t pex_send(FILE * sock, unsigned int rcpt, size_t size, char * blob); -size_t pex_broadcast(FILE * sock, size_t size, char * blob); -size_t pex_listen(FILE * sock, pex_packet_t * packet); - -size_t pex_reply(FILE * sock, size_t size, char * blob); -size_t pex_recv(FILE * sock, char * blob); -size_t pex_query(FILE * sock); - -FILE * pex_bind(char * target); -FILE * pex_connect(char * target); - diff --git a/userspace/lib/pthread.h b/userspace/lib/pthread.h deleted file mode 100644 index d731e7d7..00000000 --- a/userspace/lib/pthread.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include - -typedef struct { - uint32_t id; - char * stack; - void * ret_val; -} pthread_t; -typedef unsigned int pthread_attr_t; - -int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg); -void pthread_exit(void * value); -int pthread_kill(pthread_t thread, int sig); - -int clone(uintptr_t,uintptr_t,void*); -int gettid(); - diff --git a/userspace/lib/sha2.c b/userspace/lib/sha2.c deleted file mode 100644 index fb42adee..00000000 --- a/userspace/lib/sha2.c +++ /dev/null @@ -1,1064 +0,0 @@ -/* - * FILE: sha2.c - * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ - * - * Copyright (c) 2000-2001, Aaron D. Gifford - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include /* memcpy()/memset() or bcopy()/bzero() */ -#include /* assert() */ -#include "sha2.h" - -/* - * ASSERT NOTE: - * Some sanity checking code is included using assert(). On my FreeBSD - * system, this additional code can be removed by compiling with NDEBUG - * defined. Check your own systems manpage on assert() to see how to - * compile WITHOUT the sanity checking code on your system. - * - * UNROLLED TRANSFORM LOOP NOTE: - * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform - * loop version for the hash transform rounds (defined using macros - * later in this file). Either define on the command line, for example: - * - * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c - * - * or define below: - * - * #define SHA2_UNROLL_TRANSFORM - * - */ - - -/*** SHA-256/384/512 Machine Architecture Definitions *****************/ -/* - * BYTE_ORDER NOTE: - * - * Please make sure that your system defines BYTE_ORDER. If your - * architecture is little-endian, make sure it also defines - * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are - * equivilent. - * - * If your system does not define the above, then you can do so by - * hand like this: - * - * #define LITTLE_ENDIAN 1234 - * #define BIG_ENDIAN 4321 - * - * And for little-endian machines, add: - * - * #define BYTE_ORDER LITTLE_ENDIAN - * - * Or for big-endian machines: - * - * #define BYTE_ORDER BIG_ENDIAN - * - * The FreeBSD machine this was written on defines BYTE_ORDER - * appropriately by including (which in turn includes - * where the appropriate definitions are actually - * made). - */ -#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) -#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN -#endif - -/* - * Define the followingsha2_* types to types of the correct length on - * the native archtecture. Most BSD systems and Linux define u_intXX_t - * types. Machines with very recent ANSI C headers, can use the - * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H - * during compile or in the sha.h header file. - * - * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t - * will need to define these three typedefs below (and the appropriate - * ones in sha.h too) by hand according to their system architecture. - * - * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t - * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. - */ -#ifdef SHA2_USE_INTTYPES_H - -typedef uint8_t sha2_byte; /* Exactly 1 byte */ -typedef uint32_t sha2_word32; /* Exactly 4 bytes */ -typedef uint64_t sha2_word64; /* Exactly 8 bytes */ - -#else /* SHA2_USE_INTTYPES_H */ - -typedef u_int8_t sha2_byte; /* Exactly 1 byte */ -typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ -typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ - -#endif /* SHA2_USE_INTTYPES_H */ - - -/*** SHA-256/384/512 Various Length Definitions ***********************/ -/* NOTE: Most of these are in sha2.h */ -#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) -#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) -#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) - - -/*** ENDIAN REVERSAL MACROS *******************************************/ -#if BYTE_ORDER == LITTLE_ENDIAN -#define REVERSE32(w,x) { \ - sha2_word32 tmp = (w); \ - tmp = (tmp >> 16) | (tmp << 16); \ - (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ -} -#define REVERSE64(w,x) { \ - sha2_word64 tmp = (w); \ - tmp = (tmp >> 32) | (tmp << 32); \ - tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ - ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ - (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ - ((tmp & 0x0000ffff0000ffffULL) << 16); \ -} -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -/* - * Macro for incrementally adding the unsigned 64-bit integer n to the - * unsigned 128-bit integer (represented using a two-element array of - * 64-bit words): - */ -#define ADDINC128(w,n) { \ - (w)[0] += (sha2_word64)(n); \ - if ((w)[0] < (n)) { \ - (w)[1]++; \ - } \ -} - -/* - * Macros for copying blocks of memory and for zeroing out ranges - * of memory. Using these macros makes it easy to switch from - * using memset()/memcpy() and using bzero()/bcopy(). - * - * Please define either SHA2_USE_MEMSET_MEMCPY or define - * SHA2_USE_BZERO_BCOPY depending on which function set you - * choose to use: - */ -#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) -/* Default to memset()/memcpy() if no option is specified */ -#define SHA2_USE_MEMSET_MEMCPY 1 -#endif -#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) -/* Abort with an error if BOTH options are defined */ -#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! -#endif - -#ifdef SHA2_USE_MEMSET_MEMCPY -#define MEMSET_BZERO(p,l) memset((p), 0, (l)) -#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) -#endif -#ifdef SHA2_USE_BZERO_BCOPY -#define MEMSET_BZERO(p,l) bzero((p), (l)) -#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) -#endif - - -/*** THE SIX LOGICAL FUNCTIONS ****************************************/ -/* - * Bit shifting and rotation (used by the six SHA-XYZ logical functions: - * - * NOTE: The naming of R and S appears backwards here (R is a SHIFT and - * S is a ROTATION) because the SHA-256/384/512 description document - * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this - * same "backwards" definition. - */ -/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ -#define R(b,x) ((x) >> (b)) -/* 32-bit Rotate-right (used in SHA-256): */ -#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) -/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ -#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) - -/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ -#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) - -/* Four of six logical functions used in SHA-256: */ -#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) -#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) -#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) -#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) - -/* Four of six logical functions used in SHA-384 and SHA-512: */ -#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) -#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) -#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) -#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) - -/*** INTERNAL FUNCTION PROTOTYPES *************************************/ -/* NOTE: These should not be accessed directly from outside this - * library -- they are intended for private internal visibility/use - * only. - */ -void SHA512_Last(SHA512_CTX*); -void SHA256_Transform(SHA256_CTX*, const sha2_word32*); -void SHA512_Transform(SHA512_CTX*, const sha2_word64*); - - -/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ -/* Hash constant words K for SHA-256: */ -const static sha2_word32 K256[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, - 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, - 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, - 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, - 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, - 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, - 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - -/* Initial hash value H for SHA-256: */ -const static sha2_word32 sha256_initial_hash_value[8] = { - 0x6a09e667UL, - 0xbb67ae85UL, - 0x3c6ef372UL, - 0xa54ff53aUL, - 0x510e527fUL, - 0x9b05688cUL, - 0x1f83d9abUL, - 0x5be0cd19UL -}; - -/* Hash constant words K for SHA-384 and SHA-512: */ -const static sha2_word64 K512[80] = { - 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, - 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, - 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, - 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, - 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, - 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, - 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, - 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, - 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, - 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, - 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, - 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, - 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, - 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, - 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, - 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, - 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, - 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, - 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, - 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, - 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, - 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL -}; - -/* Initial hash value H for SHA-384 */ -const static sha2_word64 sha384_initial_hash_value[8] = { - 0xcbbb9d5dc1059ed8ULL, - 0x629a292a367cd507ULL, - 0x9159015a3070dd17ULL, - 0x152fecd8f70e5939ULL, - 0x67332667ffc00b31ULL, - 0x8eb44a8768581511ULL, - 0xdb0c2e0d64f98fa7ULL, - 0x47b5481dbefa4fa4ULL -}; - -/* Initial hash value H for SHA-512 */ -const static sha2_word64 sha512_initial_hash_value[8] = { - 0x6a09e667f3bcc908ULL, - 0xbb67ae8584caa73bULL, - 0x3c6ef372fe94f82bULL, - 0xa54ff53a5f1d36f1ULL, - 0x510e527fade682d1ULL, - 0x9b05688c2b3e6c1fULL, - 0x1f83d9abfb41bd6bULL, - 0x5be0cd19137e2179ULL -}; - -/* - * Constant used by SHA256/384/512_End() functions for converting the - * digest to a readable hexadecimal character string: - */ -static const char *sha2_hex_digits = "0123456789abcdef"; - - -/*** SHA-256: *********************************************************/ -void SHA256_Init(SHA256_CTX* context) { - if (context == (SHA256_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); - context->bitcount = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-256 round macros: */ - -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE32(*data++, W256[j]); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + W256[j]; \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + (W256[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND256(a,b,c,d,e,f,g,h) \ - s0 = W256[(j+1)&0x0f]; \ - s0 = sigma0_256(s0); \ - s1 = W256[(j+14)&0x0f]; \ - s1 = sigma1_256(s1); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, *W256; - int j; - - W256 = (sha2_word32*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - /* Rounds 0 to 15 (unrolled): */ - ROUND256_0_TO_15(a,b,c,d,e,f,g,h); - ROUND256_0_TO_15(h,a,b,c,d,e,f,g); - ROUND256_0_TO_15(g,h,a,b,c,d,e,f); - ROUND256_0_TO_15(f,g,h,a,b,c,d,e); - ROUND256_0_TO_15(e,f,g,h,a,b,c,d); - ROUND256_0_TO_15(d,e,f,g,h,a,b,c); - ROUND256_0_TO_15(c,d,e,f,g,h,a,b); - ROUND256_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds to 64: */ - do { - ROUND256(a,b,c,d,e,f,g,h); - ROUND256(h,a,b,c,d,e,f,g); - ROUND256(g,h,a,b,c,d,e,f); - ROUND256(f,g,h,a,b,c,d,e); - ROUND256(e,f,g,h,a,b,c,d); - ROUND256(d,e,f,g,h,a,b,c); - ROUND256(c,d,e,f,g,h,a,b); - ROUND256(b,c,d,e,f,g,h,a); - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, T2, *W256; - int j; - - W256 = (sha2_word32*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Copy data while converting to host byte order */ - REVERSE32(*data++,W256[j]); - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-256 compression function to update a..h with copy */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W256[(j+1)&0x0f]; - s0 = sigma0_256(s0); - s1 = W256[(j+14)&0x0f]; - s1 = sigma1_256(s1); - - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); - - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA256_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - context->bitcount += freespace << 3; - len -= freespace; - data += freespace; - SHA256_Transform(context, (sha2_word32*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - context->bitcount += len << 3; - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA256_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - SHA256_Transform(context, (sha2_word32*)data); - context->bitcount += SHA256_BLOCK_LENGTH << 3; - len -= SHA256_BLOCK_LENGTH; - data += SHA256_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - context->bitcount += len << 3; - } - /* Clean up: */ - usedspace = freespace = 0; -} - -void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { - sha2_word32 *d = (sha2_word32*)digest; - unsigned int usedspace; - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount,context->bitcount); -#endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA256_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - } - } else { - /* Set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Set the bit count: */ - *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; - - /* Final transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); - -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE32(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); -#endif - } - - /* Clean up state data: */ - MEMSET_BZERO(context, sizeof(SHA256_CTX)); - usedspace = 0; -} - -char *SHA256_End(SHA256_CTX* context, char buffer[]) { - sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); - - if (buffer != (char*)0) { - SHA256_Final(digest, context); - - for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(SHA256_CTX)); - } - MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); - return buffer; -} - -char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { - SHA256_CTX context; - - SHA256_Init(&context); - SHA256_Update(&context, data, len); - return SHA256_End(&context, digest); -} - - -/*** SHA-512: *********************************************************/ -void SHA512_Init(SHA512_CTX* context) { - if (context == (SHA512_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-512 round macros: */ -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE64(*data++, W512[j]); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ - K512[j] + W512[j]; \ - (d) += T1, \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ - K512[j] + (W512[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ - -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND512(a,b,c,d,e,f,g,h) \ - s0 = W512[(j+1)&0x0f]; \ - s0 = sigma0_512(s0); \ - s1 = W512[(j+14)&0x0f]; \ - s1 = sigma1_512(s1); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ - -void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { - sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; - int j; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - ROUND512_0_TO_15(a,b,c,d,e,f,g,h); - ROUND512_0_TO_15(h,a,b,c,d,e,f,g); - ROUND512_0_TO_15(g,h,a,b,c,d,e,f); - ROUND512_0_TO_15(f,g,h,a,b,c,d,e); - ROUND512_0_TO_15(e,f,g,h,a,b,c,d); - ROUND512_0_TO_15(d,e,f,g,h,a,b,c); - ROUND512_0_TO_15(c,d,e,f,g,h,a,b); - ROUND512_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds up to 79: */ - do { - ROUND512(a,b,c,d,e,f,g,h); - ROUND512(h,a,b,c,d,e,f,g); - ROUND512(g,h,a,b,c,d,e,f); - ROUND512(f,g,h,a,b,c,d,e); - ROUND512(e,f,g,h,a,b,c,d); - ROUND512(d,e,f,g,h,a,b,c); - ROUND512(c,d,e,f,g,h,a,b); - ROUND512(b,c,d,e,f,g,h,a); - } while (j < 80); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { - sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; - int j; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - REVERSE64(*data++, W512[j]); - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-512 compression function to update a..h with copy */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W512[(j+1)&0x0f]; - s0 = sigma0_512(s0); - s1 = W512[(j+14)&0x0f]; - s1 = sigma1_512(s1); - - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 80); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); - - usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA512_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - ADDINC128(context->bitcount, freespace << 3); - len -= freespace; - data += freespace; - SHA512_Transform(context, (sha2_word64*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - ADDINC128(context->bitcount, len << 3); - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA512_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - SHA512_Transform(context, (sha2_word64*)data); - ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); - len -= SHA512_BLOCK_LENGTH; - data += SHA512_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - ADDINC128(context->bitcount, len << 3); - } - /* Clean up: */ - usedspace = freespace = 0; -} - -void SHA512_Last(SHA512_CTX* context) { - unsigned int usedspace; - - usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount[0],context->bitcount[0]); - REVERSE64(context->bitcount[1],context->bitcount[1]); -#endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA512_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA512_Transform(context, (sha2_word64*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); - } - } else { - /* Prepare for final transform: */ - MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Store the length of input data (in bits): */ - *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; - *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; - - /* Final transform: */ - SHA512_Transform(context, (sha2_word64*)context->buffer); -} - -void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { - sha2_word64 *d = (sha2_word64*)digest; - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - SHA512_Last(context); - - /* Save the hash data for output: */ -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); -#endif - } - - /* Zero out state data */ - MEMSET_BZERO(context, sizeof(SHA512_CTX)); -} - -char *SHA512_End(SHA512_CTX* context, char buffer[]) { - sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0); - - if (buffer != (char*)0) { - SHA512_Final(digest, context); - - for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(SHA512_CTX)); - } - MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); - return buffer; -} - -char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { - SHA512_CTX context; - - SHA512_Init(&context); - SHA512_Update(&context, data, len); - return SHA512_End(&context, digest); -} - - -/*** SHA-384: *********************************************************/ -void SHA384_Init(SHA384_CTX* context) { - if (context == (SHA384_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; -} - -void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { - SHA512_Update((SHA512_CTX*)context, data, len); -} - -void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { - sha2_word64 *d = (sha2_word64*)digest; - - /* Sanity check: */ - assert(context != (SHA384_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - SHA512_Last((SHA512_CTX*)context); - - /* Save the hash data for output: */ -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 6; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); -#endif - } - - /* Zero out state data */ - MEMSET_BZERO(context, sizeof(SHA384_CTX)); -} - -char *SHA384_End(SHA384_CTX* context, char buffer[]) { - sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA384_CTX*)0); - - if (buffer != (char*)0) { - SHA384_Final(digest, context); - - for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(SHA384_CTX)); - } - MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); - return buffer; -} - -char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { - SHA384_CTX context; - - SHA384_Init(&context); - SHA384_Update(&context, data, len); - return SHA384_End(&context, digest); -} - diff --git a/userspace/lib/sha2.h b/userspace/lib/sha2.h deleted file mode 100644 index 20fc92b6..00000000 --- a/userspace/lib/sha2.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * FILE: sha2.h - * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ - * - * Copyright (c) 2000-2001, Aaron D. Gifford - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - - -/* - * Import u_intXX_t size_t type definitions from system headers. You - * may need to change this, or define these things yourself in this - * file. - */ -#include - -#define BYTE_ORDER LITTLE_ENDIAN - -#define SHA2_USE_INTTYPES_H -#ifdef SHA2_USE_INTTYPES_H - -#include - -#endif /* SHA2_USE_INTTYPES_H */ - - -/*** SHA-256/384/512 Various Length Definitions ***********************/ -#define SHA256_BLOCK_LENGTH 64 -#define SHA256_DIGEST_LENGTH 32 -#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) -#define SHA384_BLOCK_LENGTH 128 -#define SHA384_DIGEST_LENGTH 48 -#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) -#define SHA512_BLOCK_LENGTH 128 -#define SHA512_DIGEST_LENGTH 64 -#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) - - -/*** SHA-256/384/512 Context Structures *******************************/ -/* NOTE: If your architecture does not define either u_intXX_t types or - * uintXX_t (from inttypes.h), you may need to define things by hand - * for your system: - */ -#if 0 -typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ -typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ -typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ -#endif -/* - * Most BSD systems already define u_intXX_t types, as does Linux. - * Some systems, however, like Compaq's Tru64 Unix instead can use - * uintXX_t types defined by very recent ANSI C standards and included - * in the file: - * - * #include - * - * If you choose to use then please define: - * - * #define SHA2_USE_INTTYPES_H - * - * Or on the command line during compile: - * - * cc -DSHA2_USE_INTTYPES_H ... - */ -#ifdef SHA2_USE_INTTYPES_H - -typedef struct _SHA256_CTX { - uint32_t state[8]; - uint64_t bitcount; - uint8_t buffer[SHA256_BLOCK_LENGTH]; -} SHA256_CTX; -typedef struct _SHA512_CTX { - uint64_t state[8]; - uint64_t bitcount[2]; - uint8_t buffer[SHA512_BLOCK_LENGTH]; -} SHA512_CTX; - -#else /* SHA2_USE_INTTYPES_H */ - -typedef struct _SHA256_CTX { - u_int32_t state[8]; - u_int64_t bitcount; - u_int8_t buffer[SHA256_BLOCK_LENGTH]; -} SHA256_CTX; -typedef struct _SHA512_CTX { - u_int64_t state[8]; - u_int64_t bitcount[2]; - u_int8_t buffer[SHA512_BLOCK_LENGTH]; -} SHA512_CTX; - -#endif /* SHA2_USE_INTTYPES_H */ - -typedef SHA512_CTX SHA384_CTX; - - -/*** SHA-256/384/512 Function Prototypes ******************************/ -#ifndef NOPROTO -#ifdef SHA2_USE_INTTYPES_H - -void SHA256_Init(SHA256_CTX *); -void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t); -void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); -char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); -char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); - -void SHA384_Init(SHA384_CTX*); -void SHA384_Update(SHA384_CTX*, const uint8_t*, size_t); -void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); -char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); -char* SHA384_Data(const uint8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); - -void SHA512_Init(SHA512_CTX*); -void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); -void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); -char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); -char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); - -#else /* SHA2_USE_INTTYPES_H */ - -void SHA256_Init(SHA256_CTX *); -void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t); -void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); -char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); -char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); - -void SHA384_Init(SHA384_CTX*); -void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t); -void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); -char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); -char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); - -void SHA512_Init(SHA512_CTX*); -void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t); -void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); -char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); -char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); - -#endif /* SHA2_USE_INTTYPES_H */ - -#else /* NOPROTO */ - -void SHA256_Init(); -void SHA256_Update(); -void SHA256_Final(); -char* SHA256_End(); -char* SHA256_Data(); - -void SHA384_Init(); -void SHA384_Update(); -void SHA384_Final(); -char* SHA384_End(); -char* SHA384_Data(); - -void SHA512_Init(); -void SHA512_Update(); -void SHA512_Final(); -char* SHA512_End(); -char* SHA512_Data(); - -#endif /* NOPROTO */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - diff --git a/userspace/lib/shmemfonts.h b/userspace/lib/shmemfonts.h deleted file mode 100644 index e75288a2..00000000 --- a/userspace/lib/shmemfonts.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "graphics.h" -#include "yutani.h" - -void init_shmemfonts(); -void draw_string(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string); -uint32_t draw_string_width(char * string); -void draw_string_shadow(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string, uint32_t shadow_color, int darkness, int offset_x, int offset_y, double radius); -void set_font_size(int size); -void set_font_face(int face_num); -char * shmem_font_name(int i); - -#define FONT_SANS_SERIF 0 -#define FONT_SANS_SERIF_BOLD 1 -#define FONT_SANS_SERIF_ITALIC 2 -#define FONT_SANS_SERIF_BOLD_ITALIC 3 -#define FONT_MONOSPACE 4 -#define FONT_MONOSPACE_BOLD 5 -#define FONT_MONOSPACE_ITALIC 6 -#define FONT_MONOSPACE_BOLD_ITALIC 7 -#define FONT_JAPANESE 8 -#define FONT_SYMBOLA 9 - -#define FONTS_TOTAL 10 - diff --git a/userspace/lib/testing.c b/userspace/lib/testing.c deleted file mode 100644 index b4206d59..00000000 --- a/userspace/lib/testing.c +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include - -#include "testing.h" - -void notice(char * type, char * fmt, ...) { - va_list argp; - va_start(argp, fmt); - /* core-tests header */ - - printf("core-tests : %s : ", type); - vprintf(fmt, argp); - printf("\n"); -} diff --git a/userspace/lib/testing.h b/userspace/lib/testing.h deleted file mode 100644 index 5bafba65..00000000 --- a/userspace/lib/testing.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -#define INFO(...) notice("INFO", __VA_ARGS__) -#define WARN(...) notice("WARN", __VA_ARGS__) -#define DONE(...) notice("DONE", __VA_ARGS__) -#define PASS(...) notice("PASS", __VA_ARGS__) -#define FAIL(...) notice("FAIL", __VA_ARGS__) -#define FATAL(...) notice("FATAL", __VA_ARGS__) - -void notice(char * type, char * fmt, ...); - diff --git a/userspace/lib/toastd.h b/userspace/lib/toastd.h deleted file mode 100644 index 43d747f0..00000000 --- a/userspace/lib/toastd.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -typedef struct { - unsigned int ttl; - char strings[]; -} notification_t; - diff --git a/userspace/lib/tree.c b/userspace/lib/tree.c deleted file mode 120000 index 7efcacf0..00000000 --- a/userspace/lib/tree.c +++ /dev/null @@ -1 +0,0 @@ -../../kernel/ds/tree.c \ No newline at end of file diff --git a/userspace/lib/tree.h b/userspace/lib/tree.h deleted file mode 120000 index 147e5e65..00000000 --- a/userspace/lib/tree.h +++ /dev/null @@ -1 +0,0 @@ -../../kernel/include/tree.h \ No newline at end of file diff --git a/userspace/lib/utf8decode.h b/userspace/lib/utf8decode.h deleted file mode 100644 index b119895d..00000000 --- a/userspace/lib/utf8decode.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - - Copyright (c) 2008-2009 Bjoern Hoehrmann - - Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - - The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#pragma once - -#include - -#define UTF8_ACCEPT 0 -#define UTF8_REJECT 1 - -static const uint8_t utf8d[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df - 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef - 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff - 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 - 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 - 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 - 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 -}; - -static uint32_t inline -decode(uint32_t* state, uint32_t* codep, uint32_t byte) { - uint32_t type = utf8d[byte]; - - *codep = (*state != UTF8_ACCEPT) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); - - *state = utf8d[256 + *state*16 + type]; - return *state; -} - diff --git a/userspace/lib/yutani.c b/userspace/lib/yutani.c deleted file mode 100644 index af4c503e..00000000 --- a/userspace/lib/yutani.c +++ /dev/null @@ -1,881 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include - -#include "yutani.h" -#include "mouse.h" - -#include "lib/pex.h" -#include "lib/graphics.h" -#include "lib/kbd.h" -#include "lib/hashmap.h" -#include "lib/list.h" - -yutani_msg_t * yutani_wait_for(yutani_t * y, uint32_t type) { - do { - yutani_msg_t * out; - size_t size; - { - char tmp[MAX_PACKET_SIZE]; - size = pex_recv(y->sock, tmp); - out = malloc(size); - memcpy(out, tmp, size); - } - - if (out->type == type) { - return out; - } else { - list_insert(y->queued, out); - } - } while (1); /* XXX: (!y->abort) */ -} - -size_t yutani_query(yutani_t * y) { - if (y->queued->length > 0) return 1; - return pex_query(y->sock); -} - -yutani_msg_t * yutani_poll(yutani_t * y) { - yutani_msg_t * out; - - if (y->queued->length > 0) { - node_t * node = list_dequeue(y->queued); - out = (yutani_msg_t *)node->value; - free(node); - return out; - } - - size_t size; - { - char tmp[MAX_PACKET_SIZE]; - size = pex_recv(y->sock, tmp); - out = malloc(size); - memcpy(out, tmp, size); - } - - if (out->type == YUTANI_MSG_WELCOME) { - struct yutani_msg_welcome * mw = (void *)out->data; - y->display_width = mw->display_width; - y->display_height = mw->display_height; - } - - return out; -} - -yutani_msg_t * yutani_poll_async(yutani_t * y) { - if (yutani_query(y) > 0) { - return yutani_poll(y); - } - return NULL; -} - -yutani_msg_t * yutani_msg_build_hello(void) { - size_t s = sizeof(struct yutani_message); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_HELLO; - msg->size = s; - - return msg; -} - -yutani_msg_t * yutani_msg_build_flip(yutani_wid_t wid) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_flip); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_FLIP; - msg->size = s; - - struct yutani_msg_flip * mw = (void *)msg->data; - - mw->wid = wid; - - return msg; -} - -yutani_msg_t * yutani_msg_build_welcome(uint32_t width, uint32_t height) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_welcome); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WELCOME; - msg->size = s; - - struct yutani_msg_welcome * mw = (void *)msg->data; - - mw->display_width = width; - mw->display_height = height; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_new(uint32_t width, uint32_t height) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_new); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_NEW; - msg->size = s; - - struct yutani_msg_window_new * mw = (void *)msg->data; - - mw->width = width; - mw->height = height; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_new_flags(uint32_t width, uint32_t height, uint32_t flags) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_new_flags); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_NEW_FLAGS; - msg->size = s; - - struct yutani_msg_window_new_flags * mw = (void *)msg->data; - - mw->width = width; - mw->height = height; - mw->flags = flags; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_init(yutani_wid_t wid, uint32_t width, uint32_t height, uint32_t bufid) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_init); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_INIT; - msg->size = s; - - struct yutani_msg_window_init * mw = (void *)msg->data; - - mw->wid = wid; - mw->width = width; - mw->height = height; - mw->bufid = bufid; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_close(yutani_wid_t wid) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_close); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_CLOSE; - msg->size = s; - - struct yutani_msg_window_close * mw = (void *)msg->data; - - mw->wid = wid; - - return msg; -} - -yutani_msg_t * yutani_msg_build_key_event(yutani_wid_t wid, key_event_t * event, key_event_state_t * state) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_key_event); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_KEY_EVENT; - msg->size = s; - - struct yutani_msg_key_event * mw = (void *)msg->data; - - mw->wid = wid; - memcpy(&mw->event, event, sizeof(key_event_t)); - memcpy(&mw->state, state, sizeof(key_event_state_t)); - - return msg; -} - -yutani_msg_t * yutani_msg_build_mouse_event(yutani_wid_t wid, mouse_device_packet_t * event, int32_t type) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_mouse_event); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_MOUSE_EVENT; - msg->size = s; - - struct yutani_msg_mouse_event * mw = (void *)msg->data; - - mw->wid = wid; - memcpy(&mw->event, event, sizeof(mouse_device_packet_t)); - mw->type = type; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_move(yutani_wid_t wid, int32_t x, int32_t y) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_move); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_MOVE; - msg->size = s; - - struct yutani_msg_window_move * mw = (void *)msg->data; - - mw->wid = wid; - mw->x = x; - mw->y = y; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_stack(yutani_wid_t wid, int z) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_stack); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_STACK; - msg->size = s; - - struct yutani_msg_window_stack * mw = (void *)msg->data; - - mw->wid = wid; - mw->z = z; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_focus_change(yutani_wid_t wid, int focused) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_focus_change); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_FOCUS_CHANGE; - msg->size = s; - - struct yutani_msg_window_focus_change * mw = (void *)msg->data; - - mw->wid = wid; - mw->focused = focused; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_mouse_event(yutani_wid_t wid, int32_t new_x, int32_t new_y, int32_t old_x, int32_t old_y, uint8_t buttons, uint8_t command) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_mouse_event); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_MOUSE_EVENT; - msg->size = s; - - struct yutani_msg_window_mouse_event * mw = (void *)msg->data; - - mw->wid = wid; - mw->new_x = new_x; - mw->new_y = new_y; - mw->old_x = old_x; - mw->old_y = old_y; - mw->buttons = buttons; - mw->command = command; - - return msg; -} - -yutani_msg_t * yutani_msg_build_flip_region(yutani_wid_t wid, int32_t x, int32_t y, int32_t width, int32_t height) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_flip_region); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_FLIP_REGION; - msg->size = s; - - struct yutani_msg_flip_region * mw = (void *)msg->data; - - mw->wid = wid; - mw->x = x; - mw->y = y; - mw->width = width; - mw->height = height; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_resize(uint32_t type, yutani_wid_t wid, uint32_t width, uint32_t height, uint32_t bufid) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_resize); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = type; - msg->size = s; - - struct yutani_msg_window_resize * mw = (void *)msg->data; - - mw->wid = wid; - mw->width = width; - mw->height = height; - mw->bufid = bufid; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_advertise(yutani_wid_t wid, uint32_t flags, uint16_t * offsets, size_t length, char * data) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_advertise) + length; - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_ADVERTISE; - msg->size = s; - - struct yutani_msg_window_advertise * mw = (void *)msg->data; - - mw->wid = wid; - mw->flags = flags; - mw->size = length; - if (offsets) { - memcpy(mw->offsets, offsets, sizeof(uint16_t)*5); - } else { - memset(mw->offsets, 0, sizeof(uint16_t)*5); - } - if (data) { - memcpy(mw->strings, data, mw->size); - } - - return msg; -} - -yutani_msg_t * yutani_msg_build_subscribe(void) { - size_t s = sizeof(struct yutani_message); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_SUBSCRIBE; - msg->size = s; - - return msg; -} - -yutani_msg_t * yutani_msg_build_unsubscribe(void) { - size_t s = sizeof(struct yutani_message); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_UNSUBSCRIBE; - msg->size = s; - - return msg; -} - -yutani_msg_t * yutani_msg_build_query_windows(void) { - size_t s = sizeof(struct yutani_message); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_QUERY_WINDOWS; - msg->size = s; - - return msg; -} - -yutani_msg_t * yutani_msg_build_notify(void) { - size_t s = sizeof(struct yutani_message); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_NOTIFY; - msg->size = s; - - return msg; -} - -yutani_msg_t * yutani_msg_build_session_end(void) { - size_t s = sizeof(struct yutani_message); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_SESSION_END; - msg->size = s; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_focus(yutani_wid_t wid) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_focus); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_FOCUS; - msg->size = s; - - struct yutani_msg_window_focus * mw = (void *)msg->data; - - mw->wid = wid; - - return msg; -} - -yutani_msg_t * yutani_msg_build_key_bind(kbd_key_t key, kbd_mod_t mod, int response) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_key_bind); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_KEY_BIND; - msg->size = s; - - struct yutani_msg_key_bind * mw = (void *)msg->data; - - mw->key = key; - mw->modifiers = mod; - mw->response = response; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_drag_start(yutani_wid_t wid) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_drag_start); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_DRAG_START; - msg->size = s; - - struct yutani_msg_window_drag_start * mw = (void *)msg->data; - - mw->wid = wid; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_update_shape(yutani_wid_t wid, int set_shape) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_update_shape); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_UPDATE_SHAPE; - msg->size = s; - - struct yutani_msg_window_update_shape * mw = (void *)msg->data; - - mw->wid = wid; - mw->set_shape = set_shape; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_warp_mouse(yutani_wid_t wid, int32_t x, int32_t y) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_warp_mouse); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_WARP_MOUSE; - msg->size = s; - - struct yutani_msg_window_warp_mouse * mw = (void *)msg->data; - - mw->wid = wid; - mw->x = x; - mw->y = y; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_show_mouse(yutani_wid_t wid, int32_t show_mouse) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_show_mouse); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_SHOW_MOUSE; - msg->size = s; - - struct yutani_msg_window_show_mouse * mw = (void *)msg->data; - - mw->wid = wid; - mw->show_mouse = show_mouse; - - return msg; -} - -yutani_msg_t * yutani_msg_build_window_resize_start(yutani_wid_t wid, yutani_scale_direction_t direction) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_resize_start); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_WINDOW_RESIZE_START; - msg->size = s; - - struct yutani_msg_window_resize_start * mw = (void *)msg->data; - - mw->wid = wid; - mw->direction = direction; - - return msg; -} - -yutani_msg_t * yutani_msg_build_timer_request(uint32_t precision, uint32_t flags) { - size_t s = sizeof(struct yutani_message) + sizeof(struct yutani_msg_timer_request); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_TIMER_REQUEST; - msg->size = s; - - struct yutani_msg_timer_request * tr = (void *)msg->data; - - tr->precision = precision; - tr->flags = flags; - - return msg; -} - -yutani_msg_t * yutani_msg_build_timer_tick(void) { - size_t s = sizeof(struct yutani_message); - yutani_msg_t * msg = malloc(s); - - msg->magic = YUTANI_MSG__MAGIC; - msg->type = YUTANI_MSG_TIMER_TICK; - msg->size = s; - - return msg; -} - - -int yutani_msg_send(yutani_t * y, yutani_msg_t * msg) { - return pex_reply(y->sock, msg->size, (char *)msg); -} - -yutani_t * yutani_context_create(FILE * socket) { - yutani_t * out = malloc(sizeof(yutani_t)); - - out->sock = socket; - out->display_width = 0; - out->display_height = 0; - out->windows = hashmap_create_int(10); - out->queued = list_create(); - return out; -} - -yutani_t * yutani_init(void) { - /* XXX: Display, etc? */ - if (!getenv("DISPLAY")) { - return NULL; - } - - char * server_name = getenv("DISPLAY"); - FILE * c = pex_connect(server_name); - - if (!c) return NULL; /* Connection failed. */ - - yutani_t * y = yutani_context_create(c); - yutani_msg_t * m = yutani_msg_build_hello(); - int result = yutani_msg_send(y, m); - free(m); - - m = yutani_wait_for(y, YUTANI_MSG_WELCOME); - struct yutani_msg_welcome * mw = (void *)&m->data; - y->display_width = mw->display_width; - y->display_height = mw->display_height; - y->server_ident = server_name; - free(m); - - return y; -} - -yutani_window_t * yutani_window_create_flags(yutani_t * y, int width, int height, uint32_t flags) { - yutani_window_t * win = malloc(sizeof(yutani_window_t)); - - yutani_msg_t * m = yutani_msg_build_window_new_flags(width, height, flags); - int result = yutani_msg_send(y, m); - free(m); - - m = yutani_wait_for(y, YUTANI_MSG_WINDOW_INIT); - struct yutani_msg_window_init * mw = (void *)&m->data; - - win->width = mw->width; - win->height = mw->height; - win->bufid = mw->bufid; - win->wid = mw->wid; - win->focused = 0; - - hashmap_set(y->windows, (void*)win->wid, win); - - char key[1024]; - YUTANI_SHMKEY(y->server_ident, key, 1024, win); - - size_t size = (width * height * 4); - win->buffer = (uint8_t *)syscall_shm_obtain(key, &size); - return win; - -} - -yutani_window_t * yutani_window_create(yutani_t * y, int width, int height) { - return yutani_window_create_flags(y,width,height,0); -} - -void yutani_flip(yutani_t * y, yutani_window_t * win) { - yutani_msg_t * m = yutani_msg_build_flip(win->wid); - int result = yutani_msg_send(y, m); - free(m); -} - -void yutani_flip_region(yutani_t * yctx, yutani_window_t * win, int32_t x, int32_t y, int32_t width, int32_t height) { - yutani_msg_t * m = yutani_msg_build_flip_region(win->wid, x, y, width, height); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_close(yutani_t * y, yutani_window_t * win) { - yutani_msg_t * m = yutani_msg_build_window_close(win->wid); - int result = yutani_msg_send(y, m); - free(m); - - /* Now destroy our end of the window */ - { - char key[1024]; - YUTANI_SHMKEY_EXP(y->server_ident, key, 1024, win->bufid); - syscall_shm_release(key); - } - - hashmap_remove(y->windows, (void*)win->wid); - free(win); -} - -void yutani_window_move(yutani_t * yctx, yutani_window_t * window, int x, int y) { - yutani_msg_t * m = yutani_msg_build_window_move(window->wid, x, y); - int reuslt = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_set_stack(yutani_t * yctx, yutani_window_t * window, int z) { - yutani_msg_t * m = yutani_msg_build_window_stack(window->wid, z); - int reuslt = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_resize(yutani_t * yctx, yutani_window_t * window, uint32_t width, uint32_t height) { - yutani_msg_t * m = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_REQUEST, window->wid, width, height, 0); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_resize_offer(yutani_t * yctx, yutani_window_t * window, uint32_t width, uint32_t height) { - yutani_msg_t * m = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_OFFER, window->wid, width, height, 0); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_resize_accept(yutani_t * yctx, yutani_window_t * window, uint32_t width, uint32_t height) { - yutani_msg_t * m = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_ACCEPT, window->wid, width, height, 0); - int result = yutani_msg_send(yctx, m); - free(m); - - /* Now wait for the new bufid */ - m = yutani_wait_for(yctx, YUTANI_MSG_RESIZE_BUFID); - struct yutani_msg_window_resize * wr = (void*)m->data; - - if (window->wid != wr->wid) { - /* I am not sure what to do here. */ - return; - } - - /* Update the window */ - window->width = wr->width; - window->height = wr->height; - window->oldbufid = window->bufid; - window->bufid = wr->bufid; - free(m); - - /* Allocate the buffer */ - { - char key[1024]; - YUTANI_SHMKEY(yctx->server_ident, key, 1024, window); - - size_t size = (window->width * window->height * 4); - window->buffer = (uint8_t *)syscall_shm_obtain(key, &size); - } -} - -void yutani_window_resize_done(yutani_t * yctx, yutani_window_t * window) { - /* Destroy the old buffer */ - { - char key[1024]; - YUTANI_SHMKEY_EXP(yctx->server_ident, key, 1024, window->oldbufid); - syscall_shm_release(key); - } - - yutani_msg_t * m = yutani_msg_build_window_resize(YUTANI_MSG_RESIZE_DONE, window->wid, window->width, window->height, window->bufid); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_advertise(yutani_t * yctx, yutani_window_t * window, char * name) { - - uint32_t flags = 0; /* currently, no client flags */ - uint16_t offsets[5] = {0,0,0,0,0}; - uint32_t length = 0; - char * strings; - - if (!name) { - length = 1; - strings = " "; - } else { - length = strlen(name) + 1; - strings = name; - /* All the other offsets will point to null characters */ - offsets[1] = strlen(name); - offsets[2] = strlen(name); - offsets[3] = strlen(name); - offsets[4] = strlen(name); - } - - yutani_msg_t * m = yutani_msg_build_window_advertise(window->wid, flags, offsets, length, strings); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_advertise_icon(yutani_t * yctx, yutani_window_t * window, char * name, char * icon) { - - uint32_t flags = 0; /* currently no client flags */ - uint16_t offsets[5] = {0,0,0,0,0}; - uint32_t length = strlen(name) + strlen(icon) + 2; - char * strings = malloc(length); - - if (name) { - memcpy(&strings[0], name, strlen(name)+1); - offsets[0] = 0; - offsets[1] = strlen(name); - offsets[2] = strlen(name); - offsets[3] = strlen(name); - offsets[4] = strlen(name); - } - if (icon) { - memcpy(&strings[offsets[1]+1], icon, strlen(icon)+1); - offsets[1] = strlen(name)+1; - offsets[2] = strlen(name)+1+strlen(icon); - offsets[3] = strlen(name)+1+strlen(icon); - offsets[4] = strlen(name)+1+strlen(icon); - } - - yutani_msg_t * m = yutani_msg_build_window_advertise(window->wid, flags, offsets, length, strings); - int result = yutani_msg_send(yctx, m); - free(m); - free(strings); -} - -void yutani_subscribe_windows(yutani_t * y) { - yutani_msg_t * m = yutani_msg_build_subscribe(); - int result = yutani_msg_send(y, m); - free(m); -} - -void yutani_unsubscribe_windows(yutani_t * y) { - yutani_msg_t * m = yutani_msg_build_unsubscribe(); - int result = yutani_msg_send(y, m); - free(m); -} - -void yutani_query_windows(yutani_t * y) { - yutani_msg_t * m = yutani_msg_build_query_windows(); - int result = yutani_msg_send(y, m); - free(m); -} - -void yutani_session_end(yutani_t * y) { - yutani_msg_t * m = yutani_msg_build_session_end(); - int result = yutani_msg_send(y, m); - free(m); -} - -void yutani_focus_window(yutani_t * yctx, yutani_wid_t wid) { - yutani_msg_t * m = yutani_msg_build_window_focus(wid); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_key_bind(yutani_t * yctx, kbd_key_t key, kbd_mod_t mod, int response) { - yutani_msg_t * m = yutani_msg_build_key_bind(key,mod,response); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_drag_start(yutani_t * yctx, yutani_window_t * window) { - yutani_msg_t * m = yutani_msg_build_window_drag_start(window->wid); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_drag_start_wid(yutani_t * yctx, yutani_wid_t wid) { - yutani_msg_t * m = yutani_msg_build_window_drag_start(wid); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_update_shape(yutani_t * yctx, yutani_window_t * window, int set_shape) { - yutani_msg_t * m = yutani_msg_build_window_update_shape(window->wid, set_shape); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_warp_mouse(yutani_t * yctx, yutani_window_t * window, int32_t x, int32_t y) { - yutani_msg_t * m = yutani_msg_build_window_warp_mouse(window->wid, x, y); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_show_mouse(yutani_t * yctx, yutani_window_t * window, int32_t show_mouse) { - yutani_msg_t * m = yutani_msg_build_window_show_mouse(window->wid, show_mouse); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_window_resize_start(yutani_t * yctx, yutani_window_t * window, yutani_scale_direction_t direction) { - yutani_msg_t * m = yutani_msg_build_window_resize_start(window->wid, direction); - int result = yutani_msg_send(yctx, m); - free(m); -} - -void yutani_timer_request(yutani_t * yctx, uint32_t precision, uint32_t flags) { - yutani_msg_t * m = yutani_msg_build_timer_request(precision, flags); - int result = yutani_msg_send(yctx, m); - free(m); -} - -gfx_context_t * init_graphics_yutani(yutani_window_t * window) { - gfx_context_t * out = malloc(sizeof(gfx_context_t)); - out->width = window->width; - out->height = window->height; - out->depth = 32; - out->size = GFX_H(out) * GFX_W(out) * GFX_B(out); - out->buffer = window->buffer; - out->backbuffer = out->buffer; - return out; -} - -gfx_context_t * init_graphics_yutani_double_buffer(yutani_window_t * window) { - gfx_context_t * out = init_graphics_yutani(window); - out->backbuffer = malloc(GFX_B(out) * GFX_W(out) * GFX_H(out)); - return out; -} - -void reinit_graphics_yutani(gfx_context_t * out, yutani_window_t * window) { - out->width = window->width; - out->height = window->height; - out->depth = 32; - out->size = GFX_H(out) * GFX_W(out) * GFX_B(out); - if (out->buffer == out->backbuffer) { - out->buffer = window->buffer; - out->backbuffer = out->buffer; - } else { - out->buffer = window->buffer; - out->backbuffer = realloc(out->backbuffer, GFX_B(out) * GFX_W(out) * GFX_H(out)); - } -} - -void release_graphics_yutani(gfx_context_t * gfx) { - if (gfx->backbuffer != gfx->buffer) { - free(gfx->backbuffer); - } - free(gfx); -} diff --git a/userspace/net/irc.c b/userspace/net/irc.c deleted file mode 100644 index 7e399734..00000000 --- a/userspace/net/irc.c +++ /dev/null @@ -1,606 +0,0 @@ -/* vim: ts=4 sw=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Kevin Lange - * - * irc - Curses IRC client. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#ifndef A_ITALIC -#define A_ITALIC A_REVERSE -#endif - -#include "lib/pthread.h" -#include "lib/spinlock.h" - -#define _ITALIC "\033[3m" -#define _END "\033[0m\n" - -#define VERSION_STRING "0.2.0" - -static char * nick = "toaru-user"; -static char * host = NULL; -static unsigned short port = 6667; -static pthread_t read_thread; - -static char * channel = NULL; - -static WINDOW * main_win; -static WINDOW * topic_win; -static WINDOW * body_win; -static WINDOW * status_win; -static WINDOW * input_win; - -static FILE * sock; -static FILE * sockb; - -#define TIME_FMT "%02d:%02d:%02d" -#define TIME_ARGS hr, min, sec - -static volatile int c_lock; - -void show_usage(int argc, char * argv[]) { - fprintf(stderr, - "irc - Curses IRC client.\n" - "\n" - "usage: %s [-h] [-p port] [-n nick] host\n" - "\n" - " -p port " _ITALIC "Specify port to connect to" _END - " -n nick " _ITALIC "Specify a nick to use" _END - " -h " _ITALIC "Print this help message" _END - "\n", argv[0]); - exit(1); -} - -int user_color(char * user) { - int i = 0; - while (*user) { - i += *user; - user++; - } - i = i % 5; - switch (i) { - case 0: return 2; - case 1: return 3; - case 2: return 4; - case 3: return 6; - case 4: return 10; - } - return 0; -} - -int irc_color_to_pair(int fg, int bg) { - int _fg = 0; - int _bg = 0; - if (fg == -1) { - if (bg == -1) { - _fg = 0; - } else { - _fg = COLOR_WHITE; - } - } else { - fg = fg % 16; - switch (fg) { - case 0: _fg = COLOR_WHITE + 8; break; - case 1: _fg = COLOR_BLACK; break; - case 2: _fg = COLOR_BLUE; break; - case 3: _fg = COLOR_GREEN; break; - case 4: _fg = COLOR_RED + 8; break; - case 5: _fg = COLOR_RED; break; - case 6: _fg = COLOR_MAGENTA; break; - case 7: _fg = COLOR_YELLOW; break; - case 8: _fg = COLOR_YELLOW + 8; break; - case 9: _fg = COLOR_GREEN + 8; break; - case 10: _fg = COLOR_CYAN; break; - case 11: _fg = COLOR_CYAN + 8; break; - case 12: _fg = COLOR_BLUE + 8; break; - case 13: _fg = COLOR_MAGENTA + 8; break; - case 14: _fg = COLOR_BLACK + 8; break; - case 15: _fg = COLOR_WHITE; break; - } - } - if (bg == -1) { - _bg = 0; - } else { - bg = bg % 16; - switch (bg) { - case 0: _bg = COLOR_WHITE + 8; break; - case 1: _bg = COLOR_BLACK; break; - case 2: _bg = COLOR_BLUE; break; - case 3: _bg = COLOR_GREEN; break; - case 4: _bg = COLOR_RED + 8; break; - case 5: _bg = COLOR_RED; break; - case 6: _bg = COLOR_MAGENTA; break; - case 7: _bg = COLOR_YELLOW; break; - case 8: _bg = COLOR_YELLOW + 8; break; - case 9: _bg = COLOR_GREEN + 8; break; - case 10: _bg = COLOR_CYAN; break; - case 11: _bg = COLOR_CYAN + 8; break; - case 12: _bg = COLOR_BLUE + 8; break; - case 13: _bg = COLOR_MAGENTA + 8; break; - case 14: _bg = COLOR_BLACK + 8; break; - case 15: _bg = COLOR_WHITE; break; - } - } - return _fg + _bg * 16; -} - -void WRITE(const char *fmt, ...) { - - static int line_feed_pending = 0; - - int last_color = 0xFFFFFFFF; - int bold_on = 0; - int italic_on = 0; - - va_list args; - va_start(args, fmt); - char * tmp; - vasprintf(&tmp, fmt, args); - va_end(args); - - spin_lock(&c_lock); - char * c = tmp; - while (*c) { - if (*c == '\n') { - if (line_feed_pending) { - wprintw(body_win, "\n"); - } - line_feed_pending = 1; - c++; - continue; - } else { - if (line_feed_pending) { - line_feed_pending = 0; - wprintw(body_win, "\n"); - } - } - if (*c == 0x03) { - c++; - int i = -1; - int j = -1; - if (*c >= '0' && *c <= '9') { - i = (*c - '0'); - c++; - } - if (*c >= '0' && *c <= '9') { - i *= 10; - i += (*c - '0'); - c++; - } - if (*c == ',') { - c++; - if (*c >= '0' && *c <= '9') { - j = (*c - '0'); - c++; - } - if (*c >= '0' && *c <= '9') { - j *= 10; - j += (*c - '0'); - c++; - } - } - int t = irc_color_to_pair(i,j); - if (t != last_color && last_color != 0xFFFFFFFF) { - wattroff(body_win, COLOR_PAIR(last_color)); - } - if (i != -1) { - wattron(body_win, COLOR_PAIR(t)); - last_color = t; - } - continue; - } - if (*c == 0x02) { - if (bold_on) { - wattroff(body_win, A_BOLD); - bold_on = 0; - } else { - wattron(body_win, A_BOLD); - bold_on = 1; - } - c++; - continue; - } - if (*c == 0x16) { - if (italic_on) { - wattroff(body_win, A_ITALIC); - italic_on = 0; - } else { - wattron(body_win, A_ITALIC); - italic_on = 1; - } - c++; - continue; - } - if (*c == 0x0f) { - if (last_color != 0xFFFFFFFF) { - wattroff(body_win, COLOR_PAIR(last_color)); - last_color = 0xFFFFFFFF; - } - bold_on = 0; - wattroff(body_win, A_BOLD); - c++; - continue; - } - - wprintw(body_win, "%c", *c); - c++; - } - wattroff(body_win, COLOR_PAIR(last_color)); - wattroff(body_win, A_BOLD); - wattroff(body_win, A_ITALIC); - free(tmp); - wrefresh(body_win); - spin_unlock(&c_lock); -} - -void redraw_status(void) { - - spin_lock(&c_lock); - wclear(status_win); - wmove(status_win, 0, 0); - wprintw(status_win, "[%s] ", nick); - spin_unlock(&c_lock); - -} - -void refresh_all(void) { - - wrefresh(topic_win); - wrefresh(body_win); - wrefresh(status_win); - wrefresh(input_win); - -} - -void get_time(int * h, int * m, int * s) { - time_t rawtime; - time(&rawtime); - struct tm *tm_struct = localtime(&rawtime); - - *h = tm_struct->tm_hour; - *m = tm_struct->tm_min; - *s = tm_struct->tm_sec; -} - -void handle(char * line) { - char * c = line; - - while (c < line + strlen(line)) { - char * e = strstr(c, "\r\n"); - if (e > line + strlen(line)) { - break; - } - - if (!e) { - WRITE(c); - goto next; - } - - *e = '\0'; - - if (strstr(c, "PING") == c) { - char tmp[100]; - char * t = strstr(c, ":"); - fprintf(sock, "PONG %s\r\n", t); - fflush(sock); - goto next; - } - - char * user; - char * command; - char * channel; - char * message; - - user = c; - if (user[0] == ':') { user++; } - - command = strstr(user, " "); - if (!command) { - WRITE("%s\n", user); - goto next; - } - command[0] = '\0'; - command++; - - channel = strstr(command, " "); - if (!channel) { - WRITE("%s %s\n", user, command); - goto next; - } - channel[0] = '\0'; - channel++; - - message = strstr(channel, " "); - if (message) { - message[0] = '\0'; - message++; - if (message[0] == ':') { message++; } - } - - int hr, min, sec; - get_time(&hr, &min, &sec); - - if (!strcmp(command, "PRIVMSG")) { - if (!message) continue; - char * t = strstr(user, "!"); - if (t) { t[0] = '\0'; } - t = strstr(user, "@"); - if (t) { t[0] = '\0'; } - - if (strstr(message, "\001ACTION ") == message) { - message = message + 8; - char * x = strstr(message, "\001"); - if (x) *x = '\0'; - WRITE(TIME_FMT " * %d%s %s\n", TIME_ARGS, user_color(user), user, message); - } else { - WRITE(TIME_FMT " 14<%d%s14> %s\n", TIME_ARGS, user_color(user), user, message); - } - } else if (!strcmp(command, "332")) { - if (!message) { - continue; - } - spin_lock(&c_lock); - wmove(topic_win, 0, 0); - wprintw(topic_win, " %s", message); - wrefresh(topic_win); - spin_unlock(&c_lock); - } else if (!strcmp(command, "JOIN")) { - char * t = strstr(user, "!"); - if (t) { t[0] = '\0'; } - t = strstr(user, "@"); - if (t) { t[0] = '\0'; } - if (channel[0] == ':') { channel++; } - - WRITE(TIME_FMT " 12-!12-11 %s has joined %s\n", TIME_ARGS, user, channel); - } else if (!strcmp(command, "PART")) { - char * t = strstr(user, "!"); - if (t) { t[0] = '\0'; } - t = strstr(user, "@"); - if (t) { t[0] = '\0'; } - if (channel[0] == ':') { channel++; } - - WRITE(TIME_FMT " 12-!12-10 %s has left %s\n", TIME_ARGS, user, channel); - } else if (!strcmp(command,"372")) { - WRITE(TIME_FMT " 14%s %s\n", TIME_ARGS, user, message ? message : ""); - } else if (!strcmp(command,"376")) { - WRITE(TIME_FMT " 14%s (end of MOTD)\n", TIME_ARGS, user); - } else { - WRITE(TIME_FMT " 10%s %s %s %s\n", TIME_ARGS, user, command, channel, message ? message : ""); - } - - -next: - if (!e) break; - c = e + 2; - } -} - -void * irc_read_thread(void * garbage) { - - char * line = malloc(1024); - - while (1) { - memset(line, 0, 1024); - fgets(line, 1024, sockb); - handle(line); - } - -} - -void do_thing(char * thing) { - if (!strcmp(thing, "/help")) { - WRITE("[help] Herp derp you asked for help, silly you, there is none!\n"); - } else if (!strcmp(thing, "/quit") || strstr(thing,"/quit ") == thing) { - char * m = strstr(thing, " "); if (m) m++; - endwin(); - fprintf(sock,"QUIT :%s\r\n", m ? m : "http://toaruos.org/"); - fflush(sock); - pthread_kill(read_thread, SIGQUIT); - exit(0); - } else if (!strcmp(thing, "/part") || strstr(thing,"/part ") == thing) { - char * m = strstr(thing, " "); if (m) m++; - fprintf(sock,"PART %s%s%s\r\n",channel,m?" :":"",m?m:""); - fflush(sock); - free(channel); - } else if (strstr(thing, "/join ") == thing) { - char * m = strstr(thing, " "); - m++; - fprintf(sock, "JOIN %s\r\n", m); - fflush(sock); - channel = strdup(m); - } else if (strstr(thing, "/nick ") == thing) { - char * m = strstr(thing, " "); - m++; - fprintf(sock, "NICK %s\r\n", m); - fflush(sock); - /* We should totally free that, but whatever. */ - nick = strdup(m); - redraw_status(); - refresh_all(); - } else if (strstr(thing, "/me ") == thing) { - char * m = strstr(thing, " "); - m++; - int hr, min, sec; - get_time(&hr, &min, &sec); - WRITE("%02d:%02d:%02d * %s %s\n", hr, min, sec, nick, m); - fprintf(sock, "PRIVMSG %s :\001ACTION %s\001\r\n", channel, m); - fflush(sock); - } else if (strstr(thing, "/quote ") == thing) { - char * m = strstr(thing, " "); - m++; - fprintf(sock, "%s\r\n", m); - fflush(sock); - } else if (strlen(thing) > 0 && thing[0] == '/') { - WRITE("[system] Unknown command: %s\n", thing); - } else if (strlen(thing) > 0) { - if (!channel) { - WRITE("[system] Not in a channel.\n"); - } else { - int hr, min, sec; - get_time(&hr, &min, &sec); - WRITE("%02d:%02d:%02d 14<%s14> %s\n", hr, min, sec, nick, thing); - fprintf(sock, "PRIVMSG %s :%s\r\n", channel, thing); - fflush(sock); - } - } -} - -void SIGWINCH_handler(int sig) { - (void)sig; - - spin_lock(&c_lock); - - endwin(); - - refresh(); - clear(); - - int w = COLS; - int h = LINES; - - /* Move */ - mvwin(topic_win,0,0); - mvwin(body_win,1,0); - mvwin(status_win,h-2,0); - mvwin(input_win,h-1,0); - - /* Resize */ - wresize(topic_win,1,w); - wresize(body_win,h-3,w); - wresize(status_win,1,w); - wresize(input_win,1,w); - - refresh_all(); - - spin_unlock(&c_lock); -} - - -int main(int argc, char * argv[]) { - - int c; - - while ((c = getopt(argc, argv, "hp:n:")) != -1) { - switch (c) { - - case 'n': - nick = optarg; - break; - - case 'p': - port = atoi(optarg); - break; - - case 'h': - default: - show_usage(argc,argv); - } - } - - if (optind >= argc) { - show_usage(argc,argv); - } - - setlocale (LC_ALL, ""); - - host = argv[optind]; - - char tmphost[512]; - sprintf(tmphost, "/dev/net/%s:%d", host, port); - int sockfd = open(tmphost, O_RDWR); - sock = fdopen(sockfd, "w"); - sockb = fdopen(sockfd, "r"); - - if (!sock) { - fprintf(stderr, "%s: Connection failed or network not available.\n", argv[0]); - return 1; - } - - main_win = initscr(); - start_color(); - use_default_colors(); - assume_default_colors(-1,-1); - - for (int bg = 1; bg < 16; ++bg) { - for (int fg = 0; fg < 16; ++fg) { - init_pair(fg+bg*16, fg, bg); - } - } - - for (int fg = 1; fg < 16; ++fg) { - init_pair(fg, fg, -1); - } - - - int w, h; - getmaxyx(main_win, h, w); - - topic_win = newwin(1, w, 0, 0); - body_win = newwin(h-3, w, 1, 0); - status_win = newwin(1, w, h-2, 0); - input_win = newwin(1, w, h-1, 0); - - signal(SIGWINCH, SIGWINCH_handler); - - scrollok(body_win, TRUE); - - wbkgd(topic_win, COLOR_PAIR(COLOR_WHITE+COLOR_BLUE*16)); - wbkgd(body_win, COLOR_PAIR(0)); - wbkgd(status_win, COLOR_PAIR(COLOR_WHITE+COLOR_BLUE*16)); - wbkgd(input_win, COLOR_PAIR(0)); - - /* Write the welcome thing to the body */ - wprintw(body_win, " - Toaru IRC v. %s - \n", VERSION_STRING); - wprintw(body_win, " Copyright 2015 Kevin Lange\n"); - wprintw(body_win, " http://toaruos.org - http://github.com/klange/toaruos\n"); - wprintw(body_win, "\n"); - wprintw(body_win, " For help, type /help.\n"); - - wmove(topic_win, 0, 0); - wprintw(topic_win, " Toaru IRC v. %s", VERSION_STRING); - - /* Update status */ - wmove(status_win, 0, 0); - wprintw(status_win, "[%s] ", nick); - - refresh_all(); - - pthread_create(&read_thread, NULL, irc_read_thread, NULL); - - fprintf(sock, "NICK %s\r\nUSER %s * 0 :%s\r\n", nick, nick, nick); - fflush(sock); - - char * buf = malloc(1024); - - while (1) { - spin_lock(&c_lock); - wmove(input_win, 0, 0); - wprintw(input_win, "[%s] ", channel ? channel : "(none)"); - memset(buf, 0, sizeof(buf)); - spin_unlock(&c_lock); - wgetstr(input_win, buf); - - do_thing(buf); - - spin_lock(&c_lock); - wclear(input_win); - wrefresh(input_win); - spin_unlock(&c_lock); - } - - endwin(); - - return 0; -} - diff --git a/userspace/py/bin/about-applet.py b/userspace/py/bin/about-applet.py deleted file mode 100755 index a10b5636..00000000 --- a/userspace/py/bin/about-applet.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -""" -'About ToaruOS' applet -""" -import os -import sys - -import yutani -import yutani_mainloop - -from about_applet import AboutAppletWindow - -def version(): - """Get a release from uname without a git short sha.""" - release = os.uname().release - if '-' in release: - return release[:release.index('-')] - return release - -_default_text = f"ToaruOS {version()}\n© 2011-2017 Kevin Lange, et al.\n\nToaruOS is free software released under the NCSA/University of Illinois license.\n\nhttp://toaruos.org\nhttps://github.com/klange/toaruos" - - -if __name__ == '__main__': - yutani.Yutani() - d = yutani.Decor() - - def quit(): - sys.exit(0) - - if len(sys.argv) > 4: - window = AboutAppletWindow(d,sys.argv[1],sys.argv[3],sys.argv[4],sys.argv[2],on_close=quit) - else: - window = AboutAppletWindow(d,"About ToaruOS",'/usr/share/logo_login.png',_default_text,on_close=quit) - - yutani_mainloop.mainloop() - diff --git a/userspace/py/bin/check-updates.py b/userspace/py/bin/check-updates.py deleted file mode 100755 index 373ce9e3..00000000 --- a/userspace/py/bin/check-updates.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/python3 -import os -import subprocess -import sys - -import yutani -from dialog import DialogWindow -import yutani_mainloop - -def version(): - """Get a release from uname without a git short sha.""" - release = os.uname().release - if '-' in release: - return release[:release.index('-')] - return release - -def compare_version(left,right): - if left[0] > right[0]: return True - if left[0] == right[0] and left[1] > right[1]: return True - if left[0] == right[0] and left[1] == right[1] and left[2] > right[2]: return True - return False - -if __name__ == '__main__': - - # Verify network is available first. - with open('/proc/netif','r') as f: - lines = f.readlines() - if len(lines) < 4 or "no network" in lines[0]: - print("No network available, can't check for updates.") - sys.exit(1) - - # Check for updates... - try: - current = list(map(int,version().split("."))) - latest_str = subprocess.check_output(['fetch','http://toaruos.org/latest']).decode('utf-8').strip() - latest = list(map(int,latest_str.split("."))) - except: - print("Unable to parse latest version.") - sys.exit(1) - - if compare_version(latest,current): - yutani.Yutani() - d = yutani.Decor() - def derp(): - sys.exit(0) - def updates(): - subprocess.Popen(['help-browser.py','http://toaruos.org/update.trt']) - sys.exit(0) - - DialogWindow(d,"Update Available",f"A new release of ToaruOS (v{latest_str}) is available.\nPlease visit https://github.com/klange/toaruos to upgrade.",callback=derp,cancel_callback=updates,icon='star',cancel_label="What's New?",close_is_cancel=False) - - yutani_mainloop.mainloop() - - - diff --git a/userspace/py/bin/login.py b/userspace/py/bin/login.py deleted file mode 100755 index 803871eb..00000000 --- a/userspace/py/bin/login.py +++ /dev/null @@ -1,303 +0,0 @@ -#!/usr/bin/python3 -""" -Login Manager - -""" -import math -import os -import sys -import time - -import cairo - -import yutani -import text_region -import toaru_fonts -import fswait - -import panel -from panel import PanelWindow, FillWidget, VolumeWidget, NetworkWidget, DateWidget, ClockWidget, RestartMenuWidget, LabelWidget - -from input_box import InputBox -from dialog import DialogWindow - -import yutani_mainloop - -def rounded_rectangle(ctx,x,y,w,h,r): - degrees = math.pi / 180 - ctx.new_sub_path() - - ctx.arc(x + w - r, y + r, r, -90 * degrees, 0 * degrees) - ctx.arc(x + w - r, y + h - r, r, 0 * degrees, 90 * degrees) - ctx.arc(x + r, y + h - r, r, 90 * degrees, 180 * degrees) - ctx.arc(x + r, y + r, r, 180 * degrees, 270 * degrees) - ctx.close_path() - -class LoginWindow(yutani.Window): - - def __init__(self): - w = yutani.yutani_ctx._ptr.contents.display_width - h = yutani.yutani_ctx._ptr.contents.display_height - - super(LoginWindow, self).__init__(w, h, doublebuffer=True) - self.move(0,0) - self.set_stack(yutani.WindowStackOrder.ZORDER_BOTTOM) - - self.font = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF, 11, 0xFFFFFFFF) - self.font.set_shadow((0xFF000000, 2, 1, 1, 3.0)) - self.tr = text_region.TextRegion(0,0,200,30,font=self.font) - self.tr.set_text(f"ToaruOS {os.uname().release}") - - self.load_wallpaper() - - def load_wallpaper(self): - tmp = cairo.ImageSurface.create_from_png('/usr/share/wallpapers/default') - self.wallpaper = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.width, self.height) - - x = self.width / tmp.get_width() - y = self.height / tmp.get_height() - - nh = int(x * tmp.get_height()) - nw = int(y * tmp.get_width()) - - ctx = cairo.Context(self.wallpaper) - - if (nw > self.width): - ctx.translate((self.width - nw) / 2, 0) - ctx.scale(y,y) - else: - ctx.translate(0,(self.height - nh) / 2) - ctx.scale(x,x) - - ctx.set_source_surface(tmp,0,0) - ctx.paint() - - buf = yutani.GraphicsBuffer(self.wallpaper.get_width(),self.wallpaper.get_height()) - tmp = buf.get_cairo_surface() - ctx = cairo.Context(tmp) - ctx.set_source_surface(self.wallpaper) - ctx.paint() - yutani.yutani_gfx_lib.blur_context_box(buf._gfx, 20) - yutani.yutani_gfx_lib.blur_context_box(buf._gfx, 20) - yutani.yutani_gfx_lib.blur_context_box(buf._gfx, 20) - - ctx = cairo.Context(self.wallpaper) - ctx.set_source_surface(tmp) - ctx.paint() - buf.destroy() - - def draw(self): - surface = self.get_cairo_surface() - ctx = cairo.Context(surface) - - # Paint blurred wallpaper - ctx.set_source_surface(self.wallpaper) - ctx.paint() - - self.tr.move(10,self.height-24) - self.tr.draw(self) - - self.flip() - - def focus_changed(self, msg): - if msg.focused: - yutani.yutani_ctx.focus_window(prompts.wid) - - def finish_resize(self, msg): - """Accept a resize.""" - self.resize_accept(msg.width, msg.height) - self.reinit() - - self.load_wallpaper() - self.draw() - self.resize_done() - self.flip() - - def keyboard_event(self, msg): - pass - -class InputWindow(yutani.Window): - - def __init__(self): - _w = yutani.yutani_ctx._ptr.contents.display_width - _h = yutani.yutani_ctx._ptr.contents.display_height - - self.logo = cairo.ImageSurface.create_from_png('/usr/share/logo_login.png') - - super(InputWindow, self).__init__(272, self.logo.get_height() + 110 + 50, doublebuffer=True) - self.update_position(_w,_h) - - self.username = InputBox(placeholder="Username",width=180) - self.password = InputBox(password=True,placeholder="Password",width=180) - self.focused_widget = None - - self.username.tab_handler = self.focus_password - self.password.tab_handler = self.focus_username - - self.username.submit = self.password_or_go - self.password.submit = self.go - - self.error_font = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF, 11, 0xFFFF0000) - self.error_font.set_shadow((0xFF000000, 2, 0, 0, 3.0)) - self.error_tr = text_region.TextRegion(0,0,self.width,20,font=self.error_font) - self.error_tr.set_alignment(2) - - self.error = None - - def focus_changed(self, msg): - if not msg.focused: - self.username.focus_leave() - self.password.focus_leave() - - def update_position(self, w, h): - self.move(int((w - self.width)/2),int((h - self.height)/2)) - - def finish_resize(self, msg): - pass # lol no - - def draw(self): - surface = self.get_cairo_surface() - ctx = cairo.Context(surface) - - # Clear - ctx.set_operator(cairo.OPERATOR_SOURCE) - ctx.rectangle(0,0,self.width,self.height) - ctx.set_source_rgba(0,0,0,0) - ctx.fill() - - ctx.set_operator(cairo.OPERATOR_OVER) - - ctx.set_source_surface(self.logo, (self.width - self.logo.get_width())/2, 0) - ctx.paint() - - base = self.height - 110 - - rounded_rectangle(ctx, 0, base, self.width, 110, 4) - ctx.set_source_rgba(0,0,0,0.5) - ctx.fill() - - if self.error: - self.error_tr.move(0,base+8) - self.error_tr.set_text(self.error) - self.error_tr.draw(self) - - ctx.save() - ctx.translate(46,base + 30) - self.username.draw(self,ctx) - ctx.restore() - - ctx.save() - ctx.translate(46,base + 60) - self.password.draw(self,ctx) - ctx.restore() - - self.flip() - - def keyboard_event(self, msg): - if self.focused_widget: - self.focused_widget.keyboard_event(msg) - else: - self.focus_username() - self.focused_widget.keyboard_event(msg) - - def focus_password(self): - self.username.focus_leave() - self.password.focus_enter() - self.focused_widget = self.password - self.draw() - - def focus_username(self): - self.password.focus_leave() - self.username.focus_enter() - self.focused_widget = self.username - self.draw() - - def password_or_go(self): - if self.password.text: - self.go() - else: - self.focus_password() - - def go(self): - print(f"USER {self.username.text}") - print(f"PASS {self.password.text}") - print(f"AUTH",flush=True) - response = input() - if response == "FAIL": - self.error = "Incorrect username or password." - self.username.update_text("") - self.password.update_text("") - self.username.reset_cursor() - self.password.reset_cursor() - self.focus_username() - self.draw() - elif response == "SUCC": - sys.exit(0) - - - def mouse_event(self, msg): - if self.username.mouse_event(msg): - self.focus_username() - elif self.password.mouse_event(msg): - self.focus_password() - elif msg.command == yutani.MouseEvent.DOWN: - self.password.focus_leave() - self.username.focus_leave() - self.focused_widget = None - -def maybe_animate(): - tick = int(time.time()) - if tick != panel.current_time: - try: - os.waitpid(-1,os.WNOHANG) - except ChildProcessError: - pass - panel.current_time = tick - panel_window.draw() - -if __name__ == '__main__': - if os.getuid() != 0: - print("This is the GUI login client. You should not be running this. It is run by the GUI session manager.") - sys.exit(1) - print("Hello",flush=True) - yutani.Yutani() - d = yutani.Decor() # Just in case. - - panel.current_time = int(time.time()) - - window = LoginWindow() - window.draw() - - prompts = InputWindow() - prompts.draw() - - def restart_callback(): - def confirm(): - print(f"RESTART",flush=True) - sys.exit(0) - DialogWindow(d,"Restart","Are you sure you want to restart?",callback=confirm,icon='exit') - - restart = RestartMenuWidget() - restart.callback = restart_callback - - widgets = [LabelWidget(os.uname().nodename), FillWidget(),VolumeWidget(),NetworkWidget(),DateWidget(),ClockWidget(),restart] - panel_window = PanelWindow(widgets) - panel_window.draw() - - fds = [yutani.yutani_ctx] - while 1: - # Poll for events. - fd = fswait.fswait(fds,500) - maybe_animate() - if fd == 0: - while yutani.yutani_ctx.query(): - msg = yutani.yutani_ctx.poll() - if msg.type == yutani.Message.MSG_WELCOME: - panel_window.resize(msg.display_width, panel_window.height) - window.resize(msg.display_width, msg.display_height) - prompts.update_position(msg.display_width, msg.display_height) - else: - if not yutani_mainloop.handle_event(msg): - sys.exit(0) - - diff --git a/userspace/py/bin/migrate.py b/userspace/py/bin/migrate.py deleted file mode 100755 index bf1cd0df..00000000 --- a/userspace/py/bin/migrate.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/python3.6 -""" -Migrate root -""" - -import subprocess -import sys -import os -import shutil -import fcntl -import glob -import pwd - -if not os.getuid() == 0: - print("You almost definitely don't want to be running this (and you can't be cause you're not root).") - sys.exit(1) - -# Figure out what root is -with open('/proc/cmdline','r') as f: - cmdline = f.read() - -if cmdline: - cmdline = cmdline.split() - args = {} - for arg in cmdline: - if "=" in arg: - key, value = arg.split("=",1) - args[key] = value - if 'root' in args: - print("Original root is:", args['root']) - elif 'init' in args and args['init'] == '/dev/ram0': - print("Init is ram0, so this is probably a netboot image, going to assume root is /tmp/netboot.img") - args['root'] = '/tmp/netboot.img' - else: - print("Don't know what root is, bailing.") - sys.exit(1) - -root = args.get('root') -root_type = args.get('root_type','ext2') -start = args.get('_start','') - - -print("Remounting root to /dev/base...") -subprocess.check_output(['mount',root_type,root,'/dev/base']) - -print("Mounting blank tmpfs to /...") -subprocess.check_output(['mount','tmpfs','x','/']) - -print("Migrating root...") -blacklist = ['lost+found'] -for ent in os.listdir('/dev/base'): - if ent in blacklist: - continue - if os.path.isdir(os.path.join('/dev/base',ent)): - try: - print(f"Copying {ent}...") - shutil.copytree('/dev/base/'+ent,'/'+ent,symlinks=True) - except: - print("failed to make",ent) - -print('Migration does not copy permissions, changing home directory owners...') -for path in glob.glob('/home/*'): - user = path.replace('/home/','') - uid = pwd.getpwnam(user).pw_uid - os.chown(path,uid,uid) - for root, dirs, files in os.walk(path): - for name in dirs+files: - os.chown(os.path.join(root, name), uid, uid) - -if '/dev/ram' in root: - print("Freeing ramdisk...") - if ',' in root: - root,_ = root.split(',',1) - with open(root,'r') as f: - fcntl.ioctl(f, 0x4001) -if '/tmp/' in root: - os.remove(root) - -if start == '--single': - os.execv('/bin/compositor',['compositor','--','/bin/terminal','-Fl']) -elif start == '--vga': - os.execv('/bin/terminal-vga',['terminal-vga','-l']) -elif start: - os.execv('/bin/compositor',['compositor','--',start]) -else: - os.execv('/bin/compositor',['compositor']) diff --git a/userspace/py/bin/msk.py b/userspace/py/bin/msk.py deleted file mode 100755 index 4f75125b..00000000 --- a/userspace/py/bin/msk.py +++ /dev/null @@ -1,281 +0,0 @@ -#!/usr/bin/python3.6 -""" -Misaka Package Manager - -Fetches and installs packages in compressed tarballs. -""" - -import glob -import hashlib -import json -import os -import signal -import subprocess -import sys -import tarfile - -server_url = 'http://toaruos.org/packages' -var_dir = '/var/msk' -manifest_path = f'{var_dir}/manifest.json' -manifest_url = f'{server_url}/manifest.json' -index_path = f'{var_dir}/index.json' -local_cache = f'{var_dir}/cache' - -is_gui = False -force_yes = False -start_index = 1 - -def fetch(url, destination, check=False): - """Fetch a package or other file from `url` and write it to `destination`.""" - if is_gui: - args = ['fetch','-m','-o',destination,url] - _fetch = subprocess.Popen(args, stdout=subprocess.PIPE) - _progress = subprocess.Popen(['progress-bar.py',f'Fetching {os.path.basename(url)}...'], stdin=_fetch.stdout) - _fetch.stdout.close() - _progress.wait() - else: - args = ['fetch','-v','-o',destination,url] - subprocess.call(args) - if check: - sha = hashlib.sha512() - with open(destination,'rb') as f: - for chunk in iter(lambda: f.read(4096), b""): - sha.update(chunk) - if sha.hexdigest() != check: - return False - return True - -def try_fetch(url, destination): - """Make multiple attempts to download a file with an integrity checksum.""" - attempts = 0 - while attempts < 3: - if fetch(url, destination, check=True): - return True - else: - attempts += 1 - return False - -def extract_package(path, quiet=True): - with tarfile.open(path, 'r:gz') as package: - try: - manifest_inf = package.getmember('manifest.json') - manifest_br = package.extractfile(manifest_inf) - manifest_str = manifest_br.read() - except KeyError: - if not quiet: - print("Invalid MSK:", path) - return False - - manifest = json.loads(manifest_str) - if not quiet: - print(manifest['package']) - print('.'.join([str(x) for x in manifest['version']])) - - print("contents:") - for member in package.getnames(): - if not member.startswith('./'): - continue - print(member.replace('./','/',1)) - - print("Going to extract to /") - - members = [member for member in package.getmembers() if member.name.startswith('./')] - package.extractall('/',members=members) - -def signal_desktop(pid_file='/tmp/.wallpaper.pid'): - pid = None - if os.path.exists(pid_file): - with open(pid_file,'r') as f: - pid = int(f.read().strip()) - if pid: - os.kill(pid, signal.SIGUSR1) - -def version_str(version_lst): - return '.'.join([str(x) for x in version_lst]) - -def needs_var_dir(): - if not os.path.exists(var_dir): - os.makedirs(var_dir) - -def needs_local_cache(): - needs_var_dir() - if not os.path.exists(local_cache): - os.makedirs(local_cache) - -def fetch_manifest(): - needs_var_dir() - print("Updating manifest...") - fetch(manifest_url, manifest_path) - -def get_manifest(): - if not os.path.exists(manifest_path): - fetch_manifest() - with open(manifest_path, 'r') as f: - return json.loads(f.read()) - -def get_local_index(): - if not os.path.exists(index_path): - return {} - else: - with open(index_path, 'r') as f: - return json.loads(f.read()) - -def commit_local_index(index): - needs_var_dir() - with open(index_path,'w') as f: - f.write(json.dumps(index)) - -def resolve_dependencies(packages, local_index, manifest, output=None): - if not output: - output = [] - for package in packages: - for dep in manifest[package]['depends']: - if not dep in packages and dep not in output and dep not in local_index: - output = resolve_dependencies([dep], local_index, manifest, output) - output.append(package) - return output - -def show_usage(): - print(f"""msk - Download and install packages. - -usage: {sys.argv[0]} install PACKAGE [PACKAGE ...] - {sys.argv[0]} update - {sys.argv[0]} remove PACKAGE [PACKAGE ...] (* unimplemented) - {sys.argv[0]} list - {sys.argv[0]} list-all - {sys.argv[0]} help -""") - return 1 - -def update_manifest(): - fetch_manifest() - return 0 - -def remove_packages(): - print("(Unimplemented)") - return 1 - -def fetch_package(name, manifest): - package = manifest[name] - fetch(f"{server_url}/{package['file']}", f"{local_cache}/{package['file']}", check=package['checksum']) - -def install_fetched_package(name, manifest, local_index, install_candidates): - package = manifest[name] - - # Extract tarball - extract_package(f"{local_cache}/{package['file']}") - - # Remove the extracted package - os.remove(f"{local_cache}/{package['file']}") - - # Update the index to mark the package as installed - if not name in local_index: - local_index[name] = {} - local_index[name].update(manifest[name]) - if name in install_candidates: - local_index[name]['status'] = 'I' # Installed directly. - else: - if 'status' not in local_index[name]: - local_index[name]['status'] = 'i' # Installed as a dependency - -def install_packages(): - needs_local_cache() - local_index = get_local_index() - if local_index is None: - print("Failed to build a local index.") - return 1 - manifest = get_manifest() - if manifest is None: - print("Failed to obtain manifest.") - return 1 - - # Verify the requested package names are valid - packages = sys.argv[start_index:] - install_candidates = [] - for package in packages: - if package in local_index: - continue - if package not in manifest: - print("Package not found:", package) - continue - install_candidates.append(package) - - # Nothing was valid or the input was empty... - if not install_candidates: - print("Nothing to install.") - return 1 - - # Go through each package and calculate dependency tree. - all_packages = resolve_dependencies(install_candidates, local_index, manifest) - - # If the set of packages we are installing differs from what - # was requested (and valid), warn the user before continuing - # (this just means there were dependencies to also install) - if set(all_packages) != set(install_candidates) and not force_yes: - print("Going to install:", ", ".join(all_packages)) - if input("Continue? [y/N] ") not in ['y','Y','yes','YES']: - print("Stopping.") - return 1 - - # Download all of the requested packages - for name in all_packages: - print(f"Downloading {name}...") - fetch_package(name, manifest) - - # Install the packages - for name in all_packages: - print(f"Installing {name}...") - install_fetched_package(name, manifest, local_index, install_candidates) - - # Commit - commit_local_index(local_index) - - # Signal desktop for menu changes - signal_desktop() - - return 0 - -def list_installed_packages(): - local_index = get_local_index() - for name, package in local_index.items(): - print(f"{name} {version_str(package['version'])} - {package['friendly-name']}") - return 0 - -def list_all_packages(): - local_index = get_local_index() - manifest = get_manifest() - for name, package in manifest.items(): - info = " " if name not in local_index else local_index[name]['status'] - print(f"{info} {name} {version_str(package['version'])} - {package['friendly-name']}") - return 0 - -__commands = { - 'update': update_manifest, - 'help': show_usage, - 'install': install_packages, - 'remove': remove_packages, - 'list': list_installed_packages, - 'list-all': list_all_packages, -} - -if __name__ == '__main__': - if len(sys.argv) < 2: - sys.exit(show_usage()) - - i = 1 - while sys.argv[i].startswith('-'): - if sys.argv[i] == '--yes': - force_yes = True - elif sys.argv[i] == '--gui': - is_gui = True - elif sys.argv[i] == '--help': - sys.exit(show_usage()) - i+= 1 - - start_index = i + 1 - if sys.argv[i] in __commands: - sys.exit(__commands[sys.argv[i]]()) - else: - print("Unrecognized command:", sys.argv[i]) - sys.exit(1) - diff --git a/userspace/py/bin/multiline-text-demo.py b/userspace/py/bin/multiline-text-demo.py deleted file mode 100755 index f629ac55..00000000 --- a/userspace/py/bin/multiline-text-demo.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/python3 -""" -Demo of rudimentary (LTR, simple fonts only) text layout. -""" -import sys - -import yutani -import toaru_fonts -import text_region - -ipsum = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque orci mauris, vulputate at purus id, hendrerit volutpat est. Mauris vel nunc nulla. Aliquam justo massa, lacinia ac consequat sed, maximus mollis dolor. Nulla et risus sollicitudin, fermentum diam sed, efficitur dui. これは日本語です。 Ut eu mauris vel lorem ornare finibus vitae finibus massa. Süspendísse dàpibús ipsum eu accumsañ euismod. Proin pellentesque tellus vehicula convallis euismod. Donec aliquam pretium gravida. Quisque laoreet ut dolor non tincidunt. Mauris ultrices magna at ligula dictum accumsan. Nunc eleifend sollicitudin purus. In arcu orci, interdum sed ultricies id, tempor vel massa. Morbi bibendum nunc sed felis gravida tristique. Praesent vestibulum sem id mi pretium posuere. - - Proin maximus bibendum porta. Vestibulum cursus et augue at fermentum. In tincidunt, risus a placerat sollicitudin, nibh nisl tincidunt quam, laoreet tincidunt massa erat id turpis. Sed nulla augue, aliquam sit amet velit id, interdum rutrum lectus. Morbi metus tellus, commodo vitae facilisis sed, porttitor sed sem. Integer dignissim vel sem vitae euismod. Nullam et nunc sit amet felis iaculis mollis. Donec ac metus ex. Sed suscipit felis arcu, et tincidunt magna fringilla eu. Sed hendrerit, odio at condimentum tempus, metus felis volutpat metus, sed gravida lorem mi sit amet turpis. Etiam porta sodales vehicula. Integer iaculis eros sed interdum convallis. Sed rhoncus orci ligula. Proin euismod lorem ut nisl vulputate, a hendrerit felis rhoncus. Ut efficitur placerat ipsum, eu consequat nisl fermentum eget. Pellentesque id volutpat arcu, ac molestie leo.""" - -rich_demo="""This is a demonstration of rich text in ToaruOS. このデモは日本語も出来ます。 At the moment, this demo only supports a few markup options in an HTML-esque syntax.\nWe can combine multiple different options.""" - - -if __name__ == '__main__': - # Connect to the server. - yutani.Yutani() - - # Initialize the decoration library. - d = yutani.Decor() - - # Create a new window. - w = yutani.Window(600+d.width(),150+d.height(),title="Text Layout Demo",doublebuffer=True) - - # We can set window shaping... - w.update_shape(yutani.WindowShape.THRESHOLD_HALF) - - pad = 4 - - tr = text_region.TextRegion(d.left_width() + pad,d.top_height() + pad, w.width - d.width() - pad * 2, w.height - d.height() - pad * 2) - tr.set_line_height(20) - bold = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF_BOLD,13) - blue = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF,13,0xFF0000FF) - #with open('/usr/share/licenses') as f: - # tr.set_text(f.read()) - # for unit in tr.text_units: - # if unit.string.startswith("http://") or unit.string.startswith("https://"): - # unit.set_font(blue) - # if unit.string == "Software": - # unit.set_font(bold) - # tr.reflow() - #tr.set_text(ipsum) - if len(sys.argv) > 1: - with open(sys.argv[1]) as f: - tr.set_richtext(f.read()) - else: - tr.set_richtext(rich_demo) - - # Move the window... - w.move(100, 100) - - def draw_decors(): - """Render decorations for the window.""" - d.render(w) - - def draw_window(): - """Draw the window.""" - def rgb(r,g,b): - return yutani.yutani_gfx_lib.rgb(r,g,b) - w.fill(rgb(214,214,214)) - - tr.draw(w) - - draw_decors() - - def finish_resize(msg): - """Accept a resize.""" - - if msg.width < 100 or msg.height < 100: - w.resize_offer(max(msg.width,100),max(msg.height,100)) - return - - # Tell the server we accept. - w.resize_accept(msg.width, msg.height) - - # Reinitialize internal graphics context. - w.reinit() - - tr.resize(msg.width - d.width() - pad * 2, msg.height - d.height() - pad * 2) - - # Redraw the window buffer. - draw_window() - - # Inform the server we are done. - w.resize_done() - - # And flip. - w.flip() - - # Do an initial draw. - draw_window() - - # Don't forget to flip. Our single-buffered window only needs - # the Yutani flip call, but the API will perform both if needed. - w.flip() - - while 1: - # Poll for events. - msg = yutani.yutani_ctx.poll() - if msg.type == yutani.Message.MSG_SESSION_END: - # All applications should attempt to exit on SESSION_END. - w.close() - break - elif msg.type == yutani.Message.MSG_KEY_EVENT: - if msg.event.action != 0x01: - continue - if msg.event.key == b'c': - tr.set_alignment(2) - draw_window() - w.flip() - elif msg.event.key == b'l': - tr.set_alignment(0) - draw_window() - w.flip() - elif msg.event.key == b'r': - tr.set_alignment(1) - draw_window() - w.flip() - elif msg.event.key == b'm': - tr.set_valignment(2) - draw_window() - w.flip() - elif msg.event.key == b'b': - tr.set_valignment(1) - draw_window() - w.flip() - elif msg.event.key == b't': - tr.set_valignment(0) - draw_window() - w.flip() - elif msg.event.keycode == 2015: - tr.scroll = 0 - draw_window() - w.flip() - elif msg.event.keycode == 2016: - tr.scroll = len(tr.lines)-tr.visible_lines() - draw_window() - w.flip() - elif msg.event.key == b' ' or msg.event.keycode == 2013: - tr.scroll += int(tr.visible_lines() / 2) - if tr.scroll > len(tr.lines)-tr.visible_lines(): - tr.scroll = len(tr.lines)-tr.visible_lines() - draw_window() - w.flip() - elif msg.event.keycode == 2014: - tr.scroll -= int(tr.visible_lines() / 2) - if tr.scroll < 0: - tr.scroll = 0 - draw_window() - w.flip() - elif msg.event.key == b'o': - tr.set_one_line() - tr.set_ellipsis() - draw_window() - w.flip() - elif msg.event.key == b'i': - tr.set_one_line(False) - tr.set_ellipsis("") - draw_window() - w.flip() - elif msg.event.key == b'q': - # Convention says to close windows when 'q' is pressed, - # unless we're using keyboard input "normally". - w.close() - break - elif msg.type == yutani.Message.MSG_WINDOW_FOCUS_CHANGE: - # If the focus of our window changes, redraw the borders. - if msg.wid == w.wid: - # This attribute is stored in the underlying struct - # and used by the decoration library to pick which - # version of the decorations to draw for the window. - w.focused = msg.focused - draw_decors() - w.flip() - elif msg.type == yutani.Message.MSG_RESIZE_OFFER: - # Resize the window. - finish_resize(msg) - elif msg.type == yutani.Message.MSG_WINDOW_MOUSE_EVENT: - # Handle mouse events, first by passing them - # to the decorator library for processing. - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: - # Close the window when the 'X' button is clicked. - w.close() - break - else: - e = tr.click(msg.new_x,msg.new_y) - if e and msg.command == 0: - new_font = toaru_fonts.Font(e.font.font_number,e.font.font_size,0xFFFF0000) - e.set_font(new_font) - draw_window() - w.flip() - msg.free() - diff --git a/userspace/py/bin/package_manager.py b/userspace/py/bin/package_manager.py deleted file mode 100755 index f1de9ac0..00000000 --- a/userspace/py/bin/package_manager.py +++ /dev/null @@ -1,397 +0,0 @@ -#!/usr/bin/python3 -""" -Package Manager -""" -import os -import math -import stat -import sys -import subprocess - -import cairo - -import yutani -import text_region -import toaru_fonts -import msk - -from menu_bar import MenuBarWidget, MenuEntryAction, MenuEntrySubmenu, MenuEntryDivider, MenuWindow -from icon_cache import get_icon -from about_applet import AboutAppletWindow -from dialog import DialogWindow -from button import Button - -import yutani_mainloop - -app_name = "Package Manager" -version = "1.2.0" -_description = f"{app_name} {version}\n© 2017 Kevin Lange\n\nBrowse and install software packages.\n\nhttp://github.com/klange/toaruos" - -hilight_border_top = (54/255,128/255,205/255) -hilight_gradient_top = (93/255,163/255,236/255) -hilight_gradient_bottom = (56/255,137/255,220/55) -hilight_border_bottom = (47/255,106/255,167/255) - -_local_index = None -_manifest = None - -package_height = 70 - -def install(name): - msk.needs_local_cache() - all_packages = msk.resolve_dependencies([name], _local_index, _manifest) - - for name in all_packages: - msk.fetch_package(name, _manifest) - - for name in all_packages: - msk.install_fetched_package(name, _manifest, _local_index, [name]) - - msk.commit_local_index(_local_index) - msk.signal_desktop() - -class Package(object): - - def __init__(self, name): - self.name = name - self.y = 0 - self.x = 0 - self.hilight = False - - @property - def installed(self): - return self.name in _local_index - - @property - def description(self): - d = _manifest[self.name]['description'].replace('\n',' ') - while ' ' in d: - d = d.replace(' ',' ') - return d - - @property - def icon(self): - return _manifest[self.name]['icon'] - - @property - def version(self): - a,b,c= _manifest[self.name]['version'] - return f"{a}.{b}.{c}" - - @property - def friendly_name(self): - return _manifest[self.name]['friendly-name'] - - @property - def text(self): - return f"

{self.friendly_name} - {self.version}

\n{self.name} {self.description}" - - def do_action(self): - if self.installed: - return False - def do_it(): - install(self.name) - window.redraw_buf() - window.draw() - DialogWindow(window.decorator,f"Install {self.name}?",f"The package `{self.name}` will now be installed. Continue?",callback=do_it,window=window,icon='package') - return True - -class NoPackages(object): - - def __init__(self): - self.name = "No available packages or could not reach package server." - self.y = 0 - self.x = 0 - self.hilight = False - self.installed = False - self.version = '' - self.text = self.name - - def do_action(self): - pass - -class PackageManagerWindow(yutani.Window): - - base_width = 640 - base_height = 480 - - def __init__(self, decorator): - super(PackageManagerWindow, self).__init__(self.base_width + decorator.width(), self.base_height + decorator.height(), title=app_name, icon="package", doublebuffer=True) - self.move(100,100) - self.x = 100 - self.y = 100 - self.decorator = decorator - - def exit_app(action): - menus = [x for x in self.menus.values()] - for x in menus: - x.definitely_close() - self.close() - sys.exit(0) - def about_window(action): - AboutAppletWindow(self.decorator,f"About {app_name}","/usr/share/icons/48/package.png",_description,"package") - def help_browser(action): - subprocess.Popen(["help-browser.py","packages.trt"]) - def refresh_index(action): - global _manifest - msk.fetch_manifest() - _manifest = msk.get_manifest() - self.redraw_buf() - self.draw() - menus = [ - ("File", [ - MenuEntryAction("Exit","exit",exit_app,None), - ]), - ("Index", [ - MenuEntryAction("Refresh","refresh",refresh_index,None), - ]), - ("Help", [ - MenuEntryAction("Contents","help",help_browser,None), - MenuEntryDivider(), - MenuEntryAction(f"About {app_name}","star",about_window,None), - ]), - ] - - self.menubar = MenuBarWidget(self,menus) - - self.menus = {} - self.hovered_menu = None - - self.scroll_y = 0 - self.hilighted = None - self.buf = None - self.hilighted = None - - def load_packages(self): - self.packages = sorted([Package(name) for name in _manifest.keys()],key=lambda x: x.name) - - def redraw_buf(self,clips=None): - if self.buf: - self.buf.destroy() - w = self.width - self.decorator.width() - self.buf = yutani.GraphicsBuffer(w,len(self.packages)*package_height) - - surface = self.buf.get_cairo_surface() - ctx = cairo.Context(surface) - - if clips: - for clip in clips: - ctx.rectangle(clip.x,clip.y,w,package_height) - ctx.clip() - - ctx.rectangle(0,0,surface.get_width(),surface.get_height()) - ctx.set_source_rgb(1,1,1) - ctx.fill() - - offset_y = 0 - - button = Button('Install', None) - - for f in self.packages: - f.y = offset_y - if not clips or f in clips: - tr = text_region.TextRegion(64,offset_y+4,w-64 - 120,package_height-4) - tr.line_height = 19 - if False and f.hilight: - gradient = cairo.LinearGradient(0,0,0,18) - gradient.add_color_stop_rgba(0.0,*hilight_gradient_top,1.0) - gradient.add_color_stop_rgba(1.0,*hilight_gradient_bottom,1.0) - ctx.rectangle(0,offset_y+4,w,1) - ctx.set_source_rgb(*hilight_border_top) - ctx.fill() - ctx.rectangle(0,offset_y+package_height-1,w,1) - ctx.set_source_rgb(*hilight_border_bottom) - ctx.fill() - ctx.save() - ctx.translate(0,offset_y+4+1) - ctx.rectangle(0,0,w,package_height-6) - ctx.set_source(gradient) - ctx.fill() - ctx.restore() - tr.font.font_color = 0xFFFFFFFF - else: - ctx.rectangle(0,offset_y+4,w,package_height-4) - ctx.set_source_rgb(1,1,1) - ctx.fill() - tr.font.font_color = 0xFF000000 - if f.installed: - package_icon = get_icon(f.icon if f.icon else 'package',48,'package') - else: - if f.hilight: - button.hilight = f.hilight - else: - button.hilight = 0 - button.draw(self.buf,ctx,w-110,offset_y+11,100,32) - package_icon = get_icon('package-uninstalled',48) - ctx.set_source_surface(package_icon,8,11+offset_y) - ctx.paint() - tr.set_richtext(f.text) - tr.set_ellipsis() - tr.set_max_lines(3) - tr.draw(self.buf) - offset_y += package_height - - def draw(self): - surface = self.get_cairo_surface() - - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() - - ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) - ctx.rectangle(0,0,WIDTH,HEIGHT) - ctx.set_source_rgb(1,1,1) - ctx.fill() - - ctx.save() - ctx.translate(0,self.menubar.height) - text = self.buf.get_cairo_surface() - ctx.set_source_surface(text,0,self.scroll_y) - ctx.paint() - ctx.restore() - - self.menubar.draw(ctx,0,0,WIDTH) - - self.decorator.render(self) - self.flip() - - def finish_resize(self, msg): - """Accept a resize.""" - if msg.width < 120 or msg.height < 120: - self.resize_offer(max(msg.width,120),max(msg.height,120)) - return - self.resize_accept(msg.width, msg.height) - self.reinit() - self.redraw_buf() - self.draw() - self.resize_done() - self.flip() - - def scroll(self, amount): - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() - self.menubar.height - self.scroll_y += amount - if self.scroll_y > 0: - self.scroll_y = 0 - max_scroll = self.buf.height - h if h < self.buf.height else 0 - if self.scroll_y < -max_scroll: - self.scroll_y = -max_scroll - - def mouse_event(self, msg): - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: - window.close() - sys.exit(0) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() - - if x >= 0 and x < w and y >= 0 and y < self.menubar.height: - self.menubar.mouse_event(msg, x, y) - return - - if x < 0 or x >= w or y < 0 or y >= h: - return - - if x >= 0 and x < w and y >= self.menubar.height and y < h: - if msg.buttons & yutani.MouseButton.SCROLL_UP: - self.scroll(30) - self.draw() - return - elif msg.buttons & yutani.MouseButton.SCROLL_DOWN: - self.scroll(-30) - self.draw() - return - - if msg.buttons & yutani.MouseButton.BUTTON_RIGHT: - if not self.menus: - pass # no context menu at the moment - #menu_entries = [ - # MenuEntryAction("Up",None,self.go_up,None), - #] - #menu = MenuWindow(menu_entries,(self.x+msg.new_x,self.y+msg.new_y),root=self) - return - - if y < 0: return - - offset_y = self.scroll_y + self.menubar.height - - redraw = [] - hit = False - - for f in self.packages: - if offset_y > h: break - if y >= offset_y + 11 and y < offset_y + 11 + 32 and x >= w - 110 and x <= w - 10: # button height - if not f.hilight: - redraw.append(f) - if self.hilighted: - redraw.append(self.hilighted) - self.hilighted.hilight = False - f.hilight = True - self.hilighted = f - hit = True - break - offset_y += package_height - - if not hit: - if self.hilighted: - redraw.append(self.hilighted) - self.hilighted.hilight = False - self.hilighted = None - - if self.hilighted: - if msg.command == yutani.MouseEvent.DOWN: - self.hilighted.hilight = 2 - redraw.append(self.hilighted) - if msg.command == yutani.MouseEvent.RAISE or msg.command == yutani.MouseEvent.CLICK: - if self.hilighted.do_action(): - redraw = [] - self.redraw_buf() - self.draw() - - if redraw: - self.redraw_buf(redraw) - self.draw() - - def keyboard_event(self, msg): - if msg.event.action != yutani.KeyAction.ACTION_DOWN: - return # Ignore anything that isn't a key down. - if msg.event.key == b"q": - self.close() - sys.exit(0) - elif msg.event.keycode == yutani.Keycode.PAGE_UP: - h = self.height - self.decorator.height() - self.menubar.height - self.scroll(int(h/2)) - self.draw() - elif msg.event.keycode == yutani.Keycode.PAGE_DOWN: - h = self.height - self.decorator.height() - self.menubar.height - self.scroll(-int(h/2)) - self.draw() - elif msg.event.keycode == yutani.Keycode.HOME: - self.scroll_y = 0 - self.draw() - elif msg.event.keycode == yutani.Keycode.END: - h = self.height - self.decorator.height() - self.menubar.height - self.scroll_y = -(self.buf.height - h if h < self.buf.height else 0) - self.draw() - -if __name__ == '__main__': - yutani.Yutani() - d = yutani.Decor() - - try: - msk.is_gui = True - _manifest = msk.get_manifest() - _local_index = msk.get_local_index() - packages = [] - except: - packages = [NoPackages()] - - window = PackageManagerWindow(d) - if not packages: - try: - window.load_packages() - except: - window.packages = packages - else: - window.packages = packages - window.redraw_buf() - window.draw() - - yutani_mainloop.mainloop() diff --git a/userspace/py/bin/painting.py b/userspace/py/bin/painting.py deleted file mode 100755 index eb8fa404..00000000 --- a/userspace/py/bin/painting.py +++ /dev/null @@ -1,454 +0,0 @@ -#!/usr/bin/python3 -""" -Painting -""" -import os -import math -import stat -import sys -import subprocess - -import cairo - -import yutani -import text_region -import toaru_fonts - -from color_picker import ColorPickerWindow - -from menu_bar import MenuBarWidget, MenuEntryAction, MenuEntrySubmenu, MenuEntryDivider, MenuWindow -from icon_cache import get_icon -from about_applet import AboutAppletWindow - -from dialog import DialogWindow, OpenFileDialog -from input_box import TextInputWindow - -import yutani_mainloop - -app_name = "ToaruPaint" -version = "1.0.0" -_description = f"{app_name} {version}\n© 2017 Kevin Lange\n\nDraw stuff, maybe.\n\nhttp://github.com/klange/toaruos" - -class PaintingWindow(yutani.Window): - - base_width = 600 - base_height = 600 - - def __init__(self, decorator, path): - super(PaintingWindow, self).__init__(self.base_width + decorator.width(), self.base_height + decorator.height(), title=app_name, icon="applications-painting", doublebuffer=True) - self.move(100,100) - self.x = 100 - self.y = 100 - self.decorator = decorator - self.picker = None - self.last_color = (0,0,0) - self.modifiers = None - self.checkpattern = self.checkerboard(24) - - def about_window(action): - AboutAppletWindow(self.decorator,f"About {app_name}","/usr/share/icons/48/applications-painting.png",_description,"applications-painting") - - def help_browser(action): - subprocess.Popen(["help-browser.py","painting.trt"]) - - def close_picker(): - self.last_color = self.picker.color - self.picker = None - - def open_file(action): - OpenFileDialog(self.decorator,"Open...",glob="*.png",callback=self.load_buffer,window=self) - - def new_surface(action): - # TODO: prompt for size - if self.buf: - self.buf.destroy() - self.new_buffer(*action) - self.draw() - - def new_prompt(action): - def input_callback(input_window): - width = int(input_window.tr.text) - input_window.close() - def second_callback(input_window): - height = int(input_window.tr.text) - input_window.close() - new_surface((width,height)) - - TextInputWindow(self.decorator,"Height?","new",text="500",callback=second_callback,window=self) - TextInputWindow(self.decorator,"Width?","new",text="500",callback=input_callback,window=self) - - def save_file(action): - self.modified = False - path = '/tmp/painting.png' - self.set_title(f'{os.path.basename(path)} - {app_name}',self.icon) - self.surface.write_to_png(path) - - def select_color(action): - if self.picker: - return - else: - self.picker = ColorPickerWindow(self.decorator, close_picker) - self.picker.draw() - - def clear_everything(action): - self.draw_ctx.save() - self.draw_ctx.set_operator(cairo.OPERATOR_SOURCE) - self.draw_ctx.rectangle(0,0,self.surface.get_width(),self.surface.get_height()) - self.draw_ctx.set_source_rgba(0,0,0,0) - self.draw_ctx.fill() - self.draw_ctx.restore() - - menus = [ - ("File", [ - MenuEntrySubmenu("New...",[ - MenuEntryAction("500×500","new",new_surface,(500,500)), - MenuEntryAction("800×600","new",new_surface,(800,600)), - MenuEntryAction("Custom...","new",new_prompt,None), - ],icon="new"), - MenuEntryAction("Open","open",open_file,None), - MenuEntryAction("Save","save",save_file,None), - MenuEntryDivider(), - MenuEntryAction("Exit","exit",self.exit_app,None), - ]), - ("Tools", [ - MenuEntryAction("Color",None,select_color,None), - MenuEntryAction("Clear Everything",None,clear_everything,None), - ]), - ("Help", [ - MenuEntryAction("Contents","help",help_browser,None), - MenuEntryDivider(), - MenuEntryAction(f"About {app_name}","star",about_window,None), - ]), - ] - - self.menubar = MenuBarWidget(self,menus) - - self.menus = {} - self.hovered_menu = None - - if not path: - self.new_buffer(500,500) - else: - self.load_buffer(path) - - self.hilighted = None - self.was_drawing = False - self.line_width = 2.0 - self.curs_x = None - self.curs_y = None - self.moving = False - self.scale = 1.0 - self.modified = False - - def actually_exit(self): - menus = [x for x in self.menus.values()] - for x in menus: - x.definitely_close() - self.close() - sys.exit(0) - - def exit_app(self, action=None): - if self.modified: - DialogWindow(self.decorator,app_name,"You have unsaved changes.\nAre you sure you want to quit?",callback=self.actually_exit,window=self) - else: - self.actually_exit() - - - def load_buffer(self,path): - self.set_title(f'{os.path.basename(path)} - {app_name}',self.icon) - s = cairo.ImageSurface.create_from_png(path) - - self.init_buffer(s.get_width(),s.get_height()) - self.draw_ctx.save() - self.draw_ctx.set_operator(cairo.OPERATOR_SOURCE) - self.draw_ctx.rectangle(0,0,self.surface.get_width(),self.surface.get_height()) - self.draw_ctx.set_source_rgba(0,0,0,0) - self.draw_ctx.fill() - self.draw_ctx.restore() - self.draw_ctx.set_source_surface(s,0,0) - self.draw_ctx.paint() - - def init_buffer(self,w,h): - self.modified = False - self.buf = yutani.GraphicsBuffer(w,h) - self.surface = self.buf.get_cairo_surface() - self.draw_ctx = cairo.Context(self.surface) - self.offset_x = int((self.width-self.decorator.width()-self.buf.width)/2) - self.offset_y = int((self.height-self.decorator.height()-self.buf.height-self.menubar.height)/2) - - def new_buffer(self,w,h): - self.init_buffer(w,h) - self.set_title(f'Untitled - {app_name}', self.icon) - self.draw_ctx.rectangle(0,0,self.surface.get_width(),self.surface.get_height()) - self.draw_ctx.set_source_rgb(1,1,1) - self.draw_ctx.fill() - - def color(self): - if self.picker: - return self.picker.color - else: - return self.last_color - - def checkerboard(self,size): - s = cairo.ImageSurface(cairo.FORMAT_ARGB32,size,size) - c = cairo.Context(s) - c.set_source_rgb(128/255,128/255,128/255) - c.paint() - c.set_source_rgb(200/255,200/255,200/255) - c.rectangle(size/2,0,size/2,size/2) - c.rectangle(0,size/2,size/2,size/2) - c.fill() - return s - - def draw(self,decor=True,menu=True,clips=None): - surface = self.get_cairo_surface() - - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() - - ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) - - if clips: - for clip in clips: - x,y,a,b = clip - width = a - x - height = b - y - ctx.rectangle(x,y,width,height) - ctx.clip() - - ctx.save() - ctx.set_source_surface(self.checkpattern,0,0) - ctx.get_source().set_filter(cairo.FILTER_NEAREST) - ctx.get_source().set_extend(cairo.EXTEND_REPEAT) - ctx.rectangle(0,self.menubar.height,WIDTH,HEIGHT-self.menubar.height) - ctx.fill() - ctx.restore() - - ctx.save() - ctx.translate(0,self.menubar.height) - ctx.rectangle(0,0,WIDTH,HEIGHT-self.menubar.height) - ctx.clip() - - - ctx.save() - ctx.scale(self.scale,self.scale) - ctx.set_source_surface(self.surface,self.offset_x/self.scale,self.offset_y/self.scale) - ctx.get_source().set_filter(cairo.FILTER_FAST) - ctx.paint() - - if not self.curs_x is None: - if self.scale < 1.0: - ctx.set_line_width(0.5/self.scale) - else: - ctx.set_line_width(0.5) - ctx.arc(self.curs_x/self.scale,self.curs_y/self.scale,self.line_width/2,0,2*math.pi) - ctx.set_source_rgba(0,0,0,0.7) - ctx.stroke() - ctx.arc(self.curs_x/self.scale,self.curs_y/self.scale,self.line_width/2-0.5,0,2*math.pi) - ctx.set_source_rgba(1,1,1,0.7) - ctx.stroke() - - ctx.restore() - ctx.restore() - - # For debugging clip regions. - #if clips: - # for clip in clips: - # x,y,a,b = clip - # width = a - x - # height = b - y - # ctx.rectangle(x,y,width,height) - # ctx.set_source_rgba(1.0,0,0,0.4) - # ctx.paint() - - if menu: - self.menubar.draw(ctx,0,0,WIDTH) - - if decor: - self.decorator.render(self) - - self.flip() - - def finish_resize(self, msg): - """Accept a resize.""" - if msg.width < 120 or msg.height < 120: - self.resize_offer(max(msg.width,120),max(msg.height,120)) - return - self.resize_accept(msg.width, msg.height) - self.reinit() - self.offset_x = int((self.width-self.decorator.width()-self.buf.width)/2) - self.offset_y = int((self.height-self.decorator.height()-self.buf.height-self.menubar.height)/2) - self.draw() - self.resize_done() - self.flip() - - def get_color(self,x,y): - c = self.buf.get_value(x,y) - a = (c >> 24) & 0xFF - r = (c >> 16) & 0xFF - g = (c >> 8) & 0xFF - b = (c) & 0xFF - return (r,g,b) - - def mouse_event(self, msg): - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: - self.exit_app() - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() - - if not self.was_drawing: - if x >= 0 and x < w and y >= 0 and y < self.menubar.height: - self.menubar.mouse_event(msg, x, y) - return - - if x < 0 or x >= w or y < 0 or y >= h: - return - - if x >= 0 and x < w and y >= self.menubar.height and y < h: - if msg.buttons & yutani.MouseButton.BUTTON_RIGHT: - if self.picker: - _x,_y = x-self.offset_x,y-self.menubar.height-self.offset_y - if _x >= 0 and _x < self.surface.get_width() and _y >= 0 and _y < self.surface.get_height(): - self.picker.set_color(*self.get_color(_x,_y)) - if not self.menus: - pass # No context menu at the moment. - #menu_entries = [ - # MenuEntryAction("Up",None,self.go_up,None), - #] - #menu = MenuWindow(menu_entries,(self.x+msg.new_x,self.y+msg.new_y),root=self) - return - - if y < 0: return - - decor = False - regions = [] - - if not self.modifiers: - if msg.buttons & yutani.MouseButton.SCROLL_UP: - self.line_width *= 1.2 - elif msg.buttons & yutani.MouseButton.SCROLL_DOWN: - self.line_width /= 1.2 - elif self.modifiers & yutani.Modifier.MOD_LEFT_CTRL: - if msg.buttons & yutani.MouseButton.SCROLL_UP: - self.scale += 0.1 - regions.append((0,0,w,h)) - elif msg.buttons & yutani.MouseButton.SCROLL_DOWN: - self.scale -= 0.1 - if self.scale < 0.1: - self.scale = 0.1 - regions.append((0,0,w,h)) - - if not (msg.buttons & yutani.MouseButton.BUTTON_LEFT): - self.was_drawing = False - - if (msg.buttons & yutani.MouseButton.BUTTON_MIDDLE): - if not self.moving: - self.initial = msg.new_x, msg.new_y - self.initial_off = self.offset_x, self.offset_y - self.moving = True - regions.append( - ( - self.offset_x, - self.offset_y+self.menubar.height, - self.offset_x+int(self.buf.width*self.scale), - self.offset_y+self.menubar.height+int(self.buf.height*self.scale) - ) - ) - self.offset_x = self.initial_off[0] + msg.new_x - self.initial[0] - self.offset_y = self.initial_off[1] + msg.new_y - self.initial[1] - regions.append( - ( - self.offset_x, - self.offset_y+self.menubar.height, - self.offset_x+int(self.buf.width*self.scale), - self.offset_y+self.menubar.height+int(self.buf.height*self.scale) - ) - ) - else: - self.moving = False - - - cur_x_new = msg.new_x - self.decorator.left_width() - cur_y_new = msg.new_y - self.decorator.top_height() - - cur_x_old = msg.old_x - self.decorator.left_width() - cur_y_old = msg.old_y - self.decorator.top_height() - - if (msg.command == yutani.MouseEvent.DRAG or msg.command == yutani.MouseEvent.DOWN) and msg.buttons & yutani.MouseButton.BUTTON_LEFT: - self.was_drawing = True - self.draw_ctx.set_line_cap(cairo.LINE_CAP_ROUND) - self.draw_ctx.set_line_join(cairo.LINE_JOIN_ROUND) - self.draw_ctx.set_source_rgb(*self.color()) - self.draw_ctx.set_line_width(self.line_width) - - x_1 = 0.5 + (cur_x_new - self.offset_x) / self.scale - y_1 = 0.5 + (cur_y_new - self.offset_y - self.menubar.height) / self.scale - if msg.command == yutani.MouseEvent.DOWN: - x_0 = x_1 - y_0 = y_1 - regions.append( - ( - int(cur_x_new - self.line_width * self.scale), - int(cur_y_new - self.line_width * self.scale), - int(cur_x_new + self.line_width * self.scale), - int(cur_y_new + self.line_width * self.scale), - ) - ) - else: - x_0 = 0.5 + (cur_x_old - self.offset_x) / self.scale - y_0 = 0.5 + (cur_y_old - self.offset_y - self.menubar.height) / self.scale - regions.append( - ( - int(min(cur_x_new,cur_x_old) - self.line_width * self.scale), - int(min(cur_y_new,cur_y_old) - self.line_width * self.scale), - int(max(cur_x_new,cur_x_old) + self.line_width * self.scale), - int(max(cur_y_new,cur_y_old) + self.line_width * self.scale), - ) - ) - - self.draw_ctx.move_to(x_0,y_0) - self.draw_ctx.line_to(x_1,y_1) - self.draw_ctx.stroke() - if not self.modified: - self.modified = True - self.set_title("*" + self.title, self.icon) - decor = True - else: - regions.append( - ( - int(cur_x_new - self.line_width * self.scale), - int(cur_y_new - self.line_width * self.scale), - int(cur_x_new + self.line_width * self.scale), - int(cur_y_new + self.line_width * self.scale), - ) - ) - - - if self.curs_x: - regions.append( - ( - int(self.curs_x - self.line_width * self.scale - 1.0), - int(self.curs_y - self.line_width * self.scale + self.menubar.height - 1.0), - int(self.curs_x + self.line_width * self.scale + 1.0), - int(self.curs_y + self.line_width * self.scale + self.menubar.height + 1.0), - ) - ) - self.curs_x = 0.5+msg.new_x - self.decorator.left_width() - self.curs_y = 0.5+msg.new_y - self.decorator.top_height() - self.menubar.height - self.draw(menu=False,decor=decor,clips=regions) - - def keyboard_event(self, msg): - self.modifiers = msg.event.modifiers - if msg.event.action != yutani.KeyAction.ACTION_DOWN: - return # Ignore anything that isn't a key down. - if msg.event.key == b"q": - self.exit_app() - -if __name__ == '__main__': - yutani.Yutani() - d = yutani.Decor() - - window = PaintingWindow(d,sys.argv[1] if len(sys.argv) > 1 else None) - window.draw() - - yutani_mainloop.mainloop() diff --git a/userspace/py/bin/qemu_display_hack.py b/userspace/py/bin/qemu_display_hack.py deleted file mode 100755 index 6882297e..00000000 --- a/userspace/py/bin/qemu_display_hack.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python3 -""" -Client for communicating with qemu-harness. -Reads events from serial and sets display resolution. -""" - -import os - -if os.getuid() != 0: - # Need to be root, going to do fun stuff. - os.execve('/bin/gsudo',['gsudo',__file__],os.environ) - -import fcntl -import struct - -with open('/dev/fb0','r') as fb: - with open('/dev/ttyS0','r+') as f: - while 1: - data = f.readline().strip() - if data.startswith('geometry-changed'): - # geometry-changed width height - _, width, height = data.split() - data = bytearray(struct.pack("II",int(width),int(height))) - try: - fcntl.ioctl(fb, 0x5006, data) # IO_VID_SET - except: - pass - f.write('X') - f.flush() - diff --git a/userspace/py/bin/select_wallpaper.py b/userspace/py/bin/select_wallpaper.py deleted file mode 100755 index c74e13f6..00000000 --- a/userspace/py/bin/select_wallpaper.py +++ /dev/null @@ -1,288 +0,0 @@ -#!/usr/bin/python3 -""" -'Select Wallpaper' app -""" -import configparser -import os -import signal -import sys - -import cairo - -import yutani -import text_region -import toaru_fonts -import toaru_webp - -from button import Button -import yutani_mainloop - -class SideButton(Button): - - def draw(self, window, ctx, x, y, w, h): - self.x, self.y, self.width, self.height = x, y, w, h - - if self.hilight == 0: - return - - ctx.rectangle(x,y,w,h) - if self.hilight == 1: - ctx.set_source_rgba(0,0,0,0.7) - elif self.hilight == 2: - ctx.set_source_rgba(1,1,1,0.7) - ctx.fill() - - - x_, y_ = ctx.user_to_device(x,y) - font = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF,18,0xFFFFFFFF) - tr = text_region.TextRegion(int(x_),int(y_),w,h,font=font) - tr.set_alignment(2) - tr.set_valignment(2) - tr.set_text(self.text) - tr.draw(window) - -class WallpaperSelectorWindow(yutani.Window): - - base_width = 640 - base_height = 480 - fallback = '/usr/share/wallpapers/default' - - def __init__(self, decorator): - super(WallpaperSelectorWindow, self).__init__(self.base_width + decorator.width(), self.base_height + decorator.height(), title="Select Wallpaper", icon="select-wallpaper", doublebuffer=True) - self.move(100,100) - self.decorator = decorator - - self.find_wallpapers() - self.read_wallpaper() - self.load_wallpaper() - - with open('/tmp/.wallpaper.pid','r') as f: - self.wallpaper_pid = int(f.read().strip()) - - if self.path in self.wallpapers: - self.index = self.wallpapers.index(self.path) - else: - self.index = -2 - - def save(button): - with open(f'{os.environ["HOME"]}/.desktop.conf','w') as f: - f.write(f"wallpaper={self.path}\n") - os.kill(self.wallpaper_pid, signal.SIGUSR1) - - def exit(button): - self.close() - sys.exit(0) - - def previous_wallpaper(button): - self.index -= 1 - if self.index < 0: - self.index = len(self.wallpapers)-1 - self.update() - - def next_wallpaper(button): - self.index += 1 - if self.index == len(self.wallpapers) or self.index == -1: - self.index = 0 - self.update() - - self.buttons = [ - Button("Apply",save), - Button("Exit",exit), - ] - - self.previous_button = SideButton("❰",previous_wallpaper) - self.next_button = SideButton("❱",next_wallpaper) - self.extra_buttons = [ - self.previous_button, - self.next_button, - ] - - self.font = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF,13,0xFFFFFFFF) - self.font.set_shadow((0xFF000000, 2, 1, 1, 3.0)) - self.tr = text_region.TextRegion(self.decorator.left_width()+5,self.decorator.top_height()+5,self.base_width-10,40,font=self.font) - self.tr.set_alignment(2) - self.tr.set_one_line() - self.tr.set_text(self.path) - - self.error = False - - self.hover_widget = None - self.down_button = None - - def update(self): - self.path = self.wallpapers[self.index] - self.tr.set_text(self.path) - self.load_wallpaper() - self.draw() - - def load_directory(self, path): - if not os.path.exists(path): - return [] - - if toaru_webp.exists(): - return [os.path.join(path,x) for x in os.listdir(path) if x.endswith('.png') or x.endswith('.webp')] - else: - return [os.path.join(path,x) for x in os.listdir(path) if x.endswith('.png')] - - def find_wallpapers(self): - self.wallpapers = [] - - self.wallpapers.extend(self.load_directory('/usr/share/wallpapers')) - self.wallpapers.extend(self.load_directory('/tmp/wallpapers')) - - def read_wallpaper(self): - home = os.environ['HOME'] - conf = f'{home}/.desktop.conf' - if not os.path.exists(conf): - self.path = self.fallback - else: - with open(conf,'r') as f: - conf_str = '[desktop]\n' + f.read() - c = configparser.ConfigParser() - c.read_string(conf_str) - self.path = c['desktop'].get('wallpaper',self.fallback) - - def load_wallpaper(self): - if self.path.endswith('.webp') and toaru_webp.exists(): - self.wallpaper = toaru_webp.load_webp(self.path) - return - - self.wallpaper = cairo.ImageSurface.create_from_png(self.path) - - - def draw(self): - surface = self.get_cairo_surface() - - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() - - ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) - ctx.rectangle(0,0,WIDTH,HEIGHT) - ctx.set_source_rgb(204/255,204/255,204/255) - ctx.fill() - - ctx.rectangle(0,0,WIDTH,HEIGHT-50) - ctx.set_source_rgb(0,0,0) - ctx.fill() - - ctx.save() - x = WIDTH / self.wallpaper.get_width() - y = (HEIGHT-50) / self.wallpaper.get_height() - - nh = int(x * self.wallpaper.get_height()) - nw = int(y * self.wallpaper.get_width()) - - if (nw < WIDTH): - ctx.translate((WIDTH - nw) / 2, 0) - ctx.scale(y,y) - else: - ctx.translate(0,(HEIGHT - 50 - nh) / 2) - ctx.scale(x,x) - - ctx.set_source_surface(self.wallpaper,0,0) - ctx.paint() - ctx.restore() - - self.tr.resize(WIDTH,self.tr.height) - self.tr.draw(self) - - side_width = int(WIDTH/10) - self.previous_button.draw(self,ctx,0,0,side_width,HEIGHT-50) - self.next_button.draw(self,ctx,WIDTH-side_width,0,side_width,HEIGHT-50) - - offset_x = 20 - offset_y = HEIGHT-40 - button_height = 30 - button_width = 100 - button_pad = int((WIDTH - (button_width * len(self.buttons)) - (40))/(len(self.buttons)-1)) - - for button in self.buttons: - if button: - button.draw(self,ctx,offset_x,offset_y,button_width,button_height) - offset_x += button_width + button_pad - - self.decorator.render(self) - self.flip() - - def finish_resize(self, msg): - """Accept a resize.""" - _w = len(self.buttons) * 100 + 40 + self.decorator.width() - if msg.width < _w or msg.height < 120: - self.resize_offer(max(msg.width,_w),max(msg.height,120)) - return - self.resize_accept(msg.width, msg.height) - self.reinit() - self.draw() - self.resize_done() - self.flip() - - def mouse_event(self, msg): - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: - window.close() - sys.exit(0) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() - - redraw = False - if self.down_button: - if msg.command == yutani.MouseEvent.RAISE or msg.command == yutani.MouseEvent.CLICK: - if not (msg.buttons & yutani.MouseButton.BUTTON_LEFT): - if x >= self.down_button.x and \ - x < self.down_button.x + self.down_button.width and \ - y >= self.down_button.y and \ - y < self.down_button.y + self.down_button.height: - self.down_button.focus_enter() - self.down_button.callback(self.down_button) - self.down_button = None - redraw = True - else: - self.down_button.focus_leave() - self.down_button = None - redraw = True - - else: - button = None - for b in self.buttons + self.extra_buttons: - if x >= b.x and x < b.x + b.width and y >= b.y and y < b.y + b.height: - button = b - break - if button != self.hover_widget: - if button: - button.focus_enter() - redraw = True - if self.hover_widget: - self.hover_widget.focus_leave() - redraw = True - self.hover_widget = button - - if msg.command == yutani.MouseEvent.DOWN: - if button: - button.hilight = 2 - self.down_button = button - redraw = True - if not button: - if self.hover_widget: - self.hover_widget.focus_leave() - redraw = True - self.hover_widget = None - - if redraw: - self.draw() - - def keyboard_event(self, msg): - if msg.event.action != 0x01: - return # Ignore anything that isn't a key down. - if msg.event.key == b"q": - self.close() - sys.exit(0) - -if __name__ == '__main__': - yutani.Yutani() - d = yutani.Decor() - - window = WallpaperSelectorWindow(d) - window.draw() - - yutani_mainloop.mainloop() - - diff --git a/userspace/py/bin/toastd.py b/userspace/py/bin/toastd.py deleted file mode 100755 index bbd574e3..00000000 --- a/userspace/py/bin/toastd.py +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/python3 -""" -Python implementation of the toast daemon. -""" -import ctypes -import math -import os -import sys -import time - -import cairo - -import pex -import yutani -import text_region -import toaru_fonts -import fswait -import toast - -import yutani_mainloop - -notifications = [] -sliding = [] - -background = cairo.ImageSurface.create_from_png("/usr/share/ttk/toast/default.png") - -title_font = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF_BOLD, 13, 0xFFFFFFFF) -content_font = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF, 13, 0xFFFFFFFF) - -class Notification(yutani.Window): - - base_width = 310 - base_height = 110 - slide_time = 0.5 - - def __init__(self, raw): - self.ttl = time.time() + raw.ttl - strings = ctypes.addressof(raw) + toast.ToastMessage.strings.offset - self.title = ctypes.cast(strings, ctypes.c_char_p).value - self.content = ctypes.cast(strings+1+len(self.title), ctypes.c_char_p).value - flags = yutani.WindowFlag.FLAG_NO_STEAL_FOCUS | yutani.WindowFlag.FLAG_DISALLOW_DRAG | yutani.WindowFlag.FLAG_DISALLOW_RESIZE - super(Notification, self).__init__(self.base_width, self.base_height, flags=flags, doublebuffer=True) - self.update_location(len(notifications) * (self.base_height + 8)) - - self.title_tr = text_region.TextRegion(10,10,self.width-20,15,font=title_font) - self.title_tr.set_text(self.title.decode('utf-8')) - - self.content_tr = text_region.TextRegion(10,30,self.width-20,self.height-40-5,font=content_font) - self.content_tr.set_line_height(16) - self.content_tr.set_richtext(self.content.decode('utf-8')) - self.draw() - - def update_location(self, y): - self.y = int(y) - self.move(yutani.yutani_ctx._ptr.contents.display_width - self.base_width - 10, 35 + self.y) - - def slide_to(self, index, t): - self.start = self.y - self.start_time = t - self.destination = index * (self.base_height + 8) - if not self in sliding: - sliding.append(self) - - def slide(self, time): - if time - self.start_time > self.slide_time: - self.update_location(self.destination) - sliding.remove(self) - else: - self.update_location(self.start + min((time - self.start_time) / self.slide_time * (self.destination - self.start), 0)) - - def draw(self): - surface = self.get_cairo_surface() - ctx = cairo.Context(surface) - ctx.set_operator(cairo.OPERATOR_SOURCE) - ctx.set_source_surface(background, 0, 0) - ctx.paint() - - self.title_tr.draw(self) - self.content_tr.draw(self) - - self.flip() - - def close(self): - notifications.remove(self) - if self in sliding: - sliding.remove(self) - super(Notification,self).close() - - - def keyboard_event(self, msg): - pass - - def mouse_event(self, msg): - if msg.command == yutani.MouseEvent.CLICK or msg.command == yutani.MouseEvent.RAISE: - self.close() - return - -def check_close(): - kill = [] - t = time.time() - if sliding: - for note in sliding: - note.slide(t) - for note in notifications: - if note.ttl < t: - kill.append(note) - if kill: - for note in kill: - note.close() - i = 0 - for note in notifications: - note.slide_to(i, t) - i += 1 - - -if __name__ == '__main__': - yutani.Yutani() - - daemon = 'toastd' - if os.path.exists('/dev/pex/'+daemon): - print(f"Toast daemon already running or /dev/pex/{daemon} not closed properly.") - sys.exit(1) - - os.environ['TOASTD'] = daemon - pex_server = pex.PexServer(daemon) - - fds = [yutani.yutani_ctx,pex_server] - while 1: - # Poll for events. - fd = fswait.fswait(fds,20 if sliding else 500) - - if fd == 1: - size, packet = pex_server.listen() - if size and packet.size: - data = ctypes.addressof(packet) + pex.pex_packet.data.offset - notification = Notification(toast.ToastMessage.from_address(data)) - notifications.append(notification) - check_close() - while yutani.yutani_ctx.query(): - msg = yutani.yutani_ctx.poll() - if not yutani_mainloop.handle_event(msg): - os.unlink('/dev/pex/'+daemon) - sys.exit(0) - diff --git a/userspace/py/bin/toggle_vmware_mouse.py b/userspace/py/bin/toggle_vmware_mouse.py deleted file mode 100755 index b467bb2a..00000000 --- a/userspace/py/bin/toggle_vmware_mouse.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/python3 -import fcntl -import sys -import os - -if not 'absolute' in sys.argv and not 'relative' in sys.argv: - print("Expected 'absolute' or 'relative'") - sys.exit(1) - -if not os.path.exists('/dev/vmmouse'): - if not os.path.exists('/dev/absmouse'): - print("No absolute mouse pointer available.") - sys.exit(1) - else: - # VirtualBox - with open('/dev/absmouse','r') as f: - fcntl.ioctl(f, 1 if 'relative' in sys.argv else 2) -else: - # VMWare / QEMU - with open('/dev/vmmouse','r') as f: - fcntl.ioctl(f, 1 if 'relative' in sys.argv else 2) diff --git a/userspace/py/bin/tree.py b/userspace/py/bin/tree.py deleted file mode 100755 index 71681b00..00000000 --- a/userspace/py/bin/tree.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/python -""" -tree.py - List directories in a visual tree. -""" -import os - -def print_directory(path, prefix="", last=False): - if last: - extra = "└─" - else: - extra = "├─" - print(f"{prefix}{extra}{os.path.basename(path)}") - if not last: - prefix += "│ " - else: - prefix += " " - if os.path.isdir(path): - subs = os.listdir(path) - for i in range(len(subs)): - p = os.path.join(path,subs[i]) - if i == len(subs)-1: - print_directory(p,f"{prefix}",True) - else: - print_directory(p,f"{prefix}",False) - -print_directory(".",last=True) diff --git a/userspace/py/bin/wizard.py b/userspace/py/bin/wizard.py deleted file mode 100755 index e8d168e6..00000000 --- a/userspace/py/bin/wizard.py +++ /dev/null @@ -1,243 +0,0 @@ -#!/usr/bin/python3 -""" -Live CD wizard / tutorial -""" -import math -import os -import sys -import subprocess - -import cairo - -import yutani -import text_region -import toaru_fonts - -from button import Button - -import yutani_mainloop - -class HintHole(object): - """Draws a hole in the hints window.""" - - def __init__(self, x, y, radius): - self.x = x - self.y = y - self.radius = radius - - def draw(self, ctx): - ctx.save(); - ctx.set_operator(cairo.OPERATOR_SOURCE); - ctx.set_source_rgba(0.0, 0.0, 0.0, 0.0); - ctx.translate(self.x,self.y) - ctx.arc(0, 0, self.radius, 0, 2 * math.pi); - ctx.fill(); - ctx.restore(); - -_arrow = cairo.ImageSurface.create_from_png('/usr/share/wizard-arrow.png') - -class HintArrow(object): - - def __init__(self, x, y, angle, wizard_relative=False): - self.x = x - self.y = y - self.angle = angle - self.wizard_relative = wizard_relative - - def draw(self, ctx): - ctx.save() - w,h = _arrow.get_width(), _arrow.get_height() - - if self.wizard_relative: - ctx.translate((hints.width-window.width)/2+self.x,(hints.height-window.height)/2+self.y) - else: - ctx.translate(self.x,self.y) - ctx.rotate(self.angle * math.pi / 179.0) - ctx.translate(-w,-h/2) - ctx.set_source_surface(_arrow,0,0) - ctx.paint() - ctx.restore() - -class HintWindow(yutani.Window): - - def __init__(self): - flags = yutani.WindowFlag.FLAG_NO_STEAL_FOCUS | yutani.WindowFlag.FLAG_DISALLOW_DRAG | yutani.WindowFlag.FLAG_DISALLOW_RESIZE | yutani.WindowFlag.FLAG_ALT_ANIMATION - super(HintWindow, self).__init__(yutani.yutani_ctx._ptr.contents.display_width, yutani.yutani_ctx._ptr.contents.display_height, doublebuffer=True, flags=flags) - self.move(0,0) - self.page = 0 - self.update_shape(yutani.WindowShape.THRESHOLD_CLEAR) - - def draw(self): - surface = self.get_cairo_surface() - ctx = cairo.Context(surface) - ctx.rectangle(0,0,self.width,self.height) - ctx.set_operator(cairo.OPERATOR_SOURCE) - ctx.set_source_rgba(0,0,0,100/255) - ctx.fill() - - ctx.set_operator(cairo.OPERATOR_OVER) - - for widget in pages[self.page][1]: - widget.draw(ctx) - - self.flip() - - def finish_resize(self, msg): - self.resize_accept(msg.width, msg.height) - self.reinit() - self.draw() - self.resize_done() - self.flip() - - def focus_changed(self, msg): - if msg.focused: - yctx.focus_window(window.wid) - -logo = "/usr/share/logo_login.png" -pages = [ - (f"\n\n

Welcome to ToaruOS!

\n\nThis tutorial will guide you through the features of the operating system, as well as give you a feel for the UI and design principles.\n\n\nWhen you're ready to continue, press \"Next\".\n\nhttps://github.com/klange/toaruos - http://toaruos.org\n\nToaruOS is free software, released under the terms of the NCSA/University of Illinois license.",[]), - (f"\n\nIf you wish to exit the tutorial at any time, you can click the × in the upper right corner of the window.",[HintArrow(620,-5,90,True)]), - (f"\n\nAs a reminder, ToaruOS is a hobby project with few developers.\nAs such, do not expect things to work perfectly, or in some cases, at all, as the kernel and drivers are very much \"work-in-progress\".",[]), - (f"\n\nToaruOS aims to provide a Unix-like environment. You can find familiar command-line tools by opening a terminal. Application shortcuts on the desktop, as well as files in the file browser, are opened with a single click. You can also find more applications in the Applications menu.",[HintHole(70.5,80.5,50),HintArrow(110,120,-135)]), - (f"\n\nYou can explore the file system using the File Browser.",[HintHole(70.5,160.5,50),HintArrow(110,200,-135)]), - (f"\n\nMany third-party software packages have been ported to ToaruOS and are available from our website. You can use the package manager to automatically install programs like GCC, Bochs, Vim, Quake, and more.\n\nThe Package Manager will require you to authenticate. The default user is `local` with the password `local`. There is also a `root` user with password `toor`.",[HintHole(70.5,240.5,50),HintArrow(110,280,-135)]), - (f"\n\n\n\nWith ToaruOS's window manager, you can drag most windows by holding Alt, or by using the title bar. You can resize a window with Alt + Middle Click, and rotate with Alt + Right Click. To maximize a window, drag it to the top edge of the screen. To tile windows, use the Super (Windows or Command) key and the arrow keys. Holding shift or control will tile windows to quarter sizes up and down respectively.\n\nIf you are using VirtualBox, make sure the Host key does not conflict with these key bindings.",[]), - (f"\n\nYou've finished the tutorial.\n\nPress 'Exit' to close the tutorial and get started using the OS.",[]), -] - -class WizardWindow(yutani.Window): - - text_offset = 110 - - def __init__(self, decorator, title="Welcome to ToaruOS!", icon="star"): - flags = yutani.WindowFlag.FLAG_DISALLOW_DRAG | yutani.WindowFlag.FLAG_DISALLOW_RESIZE - super(WizardWindow, self).__init__(640,480, title=title, icon=icon, doublebuffer=True, flags=flags) - self.center() - self.decorator = decorator - hpad = 100 - self.page = 0 - self.button = Button("Next",self.button_click) - self.hover_widget = None - self.down_button = None - self.tr = text_region.TextRegion(hpad+self.decorator.left_width(),10+self.decorator.top_height(),self.width-self.decorator.width()-hpad*2,self.height-self.decorator.height()-20) - self.tr.line_height = 15 - self.tr.set_alignment(2) - self.load_page() - - def button_click(self, button): - self.page += 1 - if self.page >= len(pages): - sys.exit(0) - self.load_page() - - def load_page(self): - self.tr.set_richtext(pages[self.page][0]) - if self.page == len(pages)-1: - self.button.text = "Exit" - hints.page = self.page - hints.draw() - - def center(self): - self.move(int((yutani.yutani_ctx._ptr.contents.display_width-self.width)/2),int((yutani.yutani_ctx._ptr.contents.display_height-self.height)/2)) - - def draw(self): - surface = self.get_cairo_surface() - - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() - - ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) - ctx.rectangle(0,0,WIDTH,HEIGHT) - ctx.set_source_rgb(204/255,204/255,204/255) - ctx.fill() - - self.tr.draw(self) - self.button.draw(self,ctx,int((WIDTH-100)/2),380,100,38) - - self.decorator.render(self) - self.flip() - - def finish_resize(self, msg): - pass # Ignore resize requests - - def mouse_event(self, msg): - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: - window.close() - sys.exit(0) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() - - redraw = False - - if self.down_button: - if msg.command == yutani.MouseEvent.RAISE or msg.command == yutani.MouseEvent.CLICK: - if not (msg.buttons & yutani.MouseButton.BUTTON_LEFT): - if x >= self.down_button.x and \ - x < self.down_button.x + self.down_button.width and \ - y >= self.down_button.y and \ - y < self.down_button.y + self.down_button.height: - self.down_button.focus_enter() - self.down_button.callback(self.down_button) - self.down_button = None - redraw = True - else: - self.down_button.focus_leave() - self.down_button = None - redraw = True - else: - if x >= self.button.x and x < self.button.x + self.button.width and y >= self.button.y and y < self.button.y + self.button.height: - if self.button != self.hover_widget: - if self.hover_widget: - self.hover_widget.leave() - self.button.focus_enter() - self.hover_widget = self.button - redraw = True - if msg.command == yutani.MouseEvent.DOWN: - self.button.hilight = 2 - self.down_button = self.button - redraw = True - else: - if self.hover_widget == self.button: - self.button.focus_leave() - self.hover_widget = None - redraw = True - - if redraw: - self.draw() - - def keyboard_event(self, msg): - if msg.event.action != 0x01: - return # Ignore anything that isn't a key down. - if msg.event.key == b"q": - self.close() - sys.exit(0) - if msg.event.key == b' ': - self.page += 1 - if self.page >= len(pages): - self.close() - sys.exit(0) - self.load_page() - self.draw() - -if __name__ == '__main__': - yctx = yutani.Yutani() - d = yutani.Decor() - - hints = HintWindow() - hints.draw() - - window = WizardWindow(d) - window.draw() - - subprocess.Popen(['check-updates.py']) - - while 1: - # Poll for events. - msg = yutani.yutani_ctx.poll() - if msg.type == yutani.Message.MSG_WELCOME: - hints.resize(msg.display_width,msg.display_height) - window.center() - msg.free() - else: - if not yutani_mainloop.handle_event(msg): - break diff --git a/userspace/py/bin/yutani-cairo-demo.py b/userspace/py/bin/yutani-cairo-demo.py deleted file mode 100755 index f9ce4261..00000000 --- a/userspace/py/bin/yutani-cairo-demo.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/python3 -""" -Demo application that renders into a Yutani window with Cairo. -""" -import yutani -import cairo -import math - -if __name__ == '__main__': - # Connect to the server. - yutani.Yutani() - - # Initialize the decoration library. - d = yutani.Decor() - - # Create a new window. - w = yutani.Window(200+d.width(),200+d.height(),title="Python Cairo Demo") - - # Since this is Python, we can attach data to our window, such - # as its internal width (excluding the decorations). - w.int_width = 200 - w.int_height = 200 - - # We can set window shaping... - w.update_shape(yutani.WindowShape.THRESHOLD_HALF) - - # Move the window... - w.move(100, 100) - - def draw_decors(): - """Render decorations for the window.""" - d.render(w) - - def draw_window(): - """Draw the window.""" - surface = w.get_cairo_surface() - - WIDTH, HEIGHT = w.width, w.height - - ctx = cairo.Context(surface) - ctx.scale (WIDTH/1.0, HEIGHT/1.0) - - pat = cairo.LinearGradient (0.0, 0.0, 0.0, 1.0) - pat.add_color_stop_rgba (1, 0, 0, 0, 1) - pat.add_color_stop_rgba (0, 1, 1, 1, 1) - - ctx.rectangle (0,0,1,1) - ctx.set_source (pat) - ctx.fill () - - pat = cairo.RadialGradient (0.45, 0.4, 0.1, - 0.4, 0.4, 0.5) - pat.add_color_stop_rgba (0, 1, 1, 1, 1) - pat.add_color_stop_rgba (1, 0, 0, 0, 1) - - ctx.set_source (pat) - ctx.arc (0.5, 0.5, 0.3, 0, 2 * math.pi) - ctx.fill () - - draw_decors() - - def finish_resize(msg): - """Accept a resize.""" - - # Tell the server we accept. - w.resize_accept(msg.width, msg.height) - - # Reinitialize internal graphics context. - w.reinit() - - # Calculate new internal dimensions. - w.int_width = msg.width - d.width() - w.int_height = msg.height - d.height() - - # Redraw the window buffer. - draw_window() - - # Inform the server we are done. - w.resize_done() - - # And flip. - w.flip() - - # Do an initial draw. - draw_window() - - # Don't forget to flip. Our single-buffered window only needs - # the Yutani flip call, but the API will perform both if needed. - w.flip() - - while 1: - # Poll for events. - msg = yutani.yutani_ctx.poll() - if msg.type == yutani.Message.MSG_SESSION_END: - # All applications should attempt to exit on SESSION_END. - w.close() - break - elif msg.type == yutani.Message.MSG_KEY_EVENT: - # Print key events for debugging. - print(f'W({msg.wid}) key {msg.event.key} {msg.event.action}') - if msg.event.key == b'q': - # Convention says to close windows when 'q' is pressed, - # unless we're using keyboard input "normally". - w.close() - break - elif msg.type == yutani.Message.MSG_WINDOW_FOCUS_CHANGE: - # If the focus of our window changes, redraw the borders. - if msg.wid == w.wid: - # This attribute is stored in the underlying struct - # and used by the decoration library to pick which - # version of the decorations to draw for the window. - w.focused = msg.focused - draw_decors() - w.flip() - elif msg.type == yutani.Message.MSG_RESIZE_OFFER: - # Resize the window. - finish_resize(msg) - elif msg.type == yutani.Message.MSG_WINDOW_MOUSE_EVENT: - # Handle mouse events, first by passing them - # to the decorator library for processing. - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: - # Close the window when the 'X' button is clicked. - w.close() - break - else: - # For events that didn't get handled by the decorations, - # print a debug message with details. - print(f'W({msg.wid}) mouse {msg.new_x},{msg.new_y}') - msg.free() diff --git a/userspace/py/lib/color_picker.py b/userspace/py/lib/color_picker.py deleted file mode 100755 index 82a29367..00000000 --- a/userspace/py/lib/color_picker.py +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/python3 -""" -Color picker -""" -import colorsys -import math -import sys - -import cairo - -import yutani - -def s(p1,p2,p3): - return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]) - -def dist(a,b): - return math.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2) - -def closest_point(pt, v1, v2): - ap = (pt[0] - v1[0]),(pt[1] - v1[1]) - ab = (v2[0] - v1[0]),(v2[1] - v1[1]) - ab2 = ab[0]**2 + ab[1]**2 - ap_ab = ap[0]*ab[0] + ap[1]*ab[1] - t = ap_ab / ab2 - return (v1[0] + ab[0] * t, v1[1] + ab[1] * t) - -def point_inside(pt, v1, v2, v3): - a = s(pt,v1,v2) - b = s(pt,v2,v3) - c = s(pt,v3,v1) - return (a < 0) == (b < 0) == (c < 0) - -def dist3(a,b): - return math.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2+(a[2]-b[2])**2) - -def frange(x,y,jump): - while x < y: - yield x - x += jump - -class ColorPickerWindow(yutani.Window): - - base_width = 200 - - def __init__(self, decorator, close_callback): - super(ColorPickerWindow,self).__init__(self.base_width + decorator.width(), self.base_width + decorator.height(), title="Color Picker", doublebuffer=True) - self.move(100,100) - self.decorator = decorator - self.close_callback = close_callback - - self.hue = math.radians(240) - self.angle = -self.hue - self.pat = cairo.MeshGradient() - self.pat.begin_patch() - self.pat.move_to(-1.0,0.0) - self.pat.curve_to(-1.0,0.3886666666666667,-0.7746666666666667,0.742,-0.4226666666666667,0.906) - self.pat.curve_to(-0.12666666666666668,1.044,0.2173333333333333,1.0293333333333334,0.5,0.866) - self.pat.curve_to(0.8093333333333331,0.6873333333333332,1.0,0.3573333333333333,1.0,0.0) - self.pat.set_corner_color_rgb (0, 0, 1, 1) - self.pat.set_corner_color_rgb (1, 0, 0, 1) - self.pat.set_corner_color_rgb (2, 1, 0, 1) - self.pat.set_corner_color_rgb (3, 1, 0, 0) - self.pat.end_patch() - self.pat.begin_patch() - self.pat.move_to(-1.0,0.0) - self.pat.curve_to(-1.0,-0.3886666666666667,-0.7746666666666667,-0.742,-0.4226666666666667,-0.906) - self.pat.curve_to(-0.12666666666666668,-1.044,0.2173333333333333,-1.0293333333333334,0.5,-0.866) - self.pat.curve_to(0.8093333333333331,-0.6873333333333332,1.0,-0.3573333333333333,1.0,0.0) - self.pat.set_corner_color_rgb (0, 0, 1, 1) - self.pat.set_corner_color_rgb (1, 0, 1, 0) - self.pat.set_corner_color_rgb (2, 1, 1, 0) - self.pat.set_corner_color_rgb (3, 1, 0, 0) - self.pat.end_patch() - - self.dit_th = 0.0 - self.dit_r = 0.0 - self.color = (0,0,0) - - self.v1,self.v2,self.v3 = (0,0),(0,0),(0,0) - - self.down_in_circle = False - self.down_in_triangle = False - - def set_color(self,r,g,b): - return - """ - color = (r/255,g/255,b/255) - h,s,v = colorsys.rgb_to_hsv(*color) - self.hue = h * (2 * math.pi) - self.angle = -self.hue - - white_distance = dist3((1,1,1),color) - black_distance = dist3((0,0,0),color) - full_distance = dist3(colorsys.hsv_to_rgb(self.hue/(2*math.pi),1.0,1.0),color) - - print(white_distance,black_distance,full_distance) - - self.draw() - """ - - def calculate_color(self): - dit_x,dit_y = math.cos(math.radians(self.dit_th)+self.angle)*self.dit_r,math.sin(math.radians(self.dit_th)+self.angle)*self.dit_r - - dit = dit_x,dit_y - sat_p = closest_point(dit,self.v1,self.v2) - exp_p = closest_point(dit,self.v1,self.v3) - m_exp = closest_point(self.v2,self.v1,self.v3) - m_sat = closest_point(self.v3,self.v1,self.v2) - white_amount = dist(sat_p,dit)/dist(m_sat,self.v3) - mix_amount = dist(exp_p,dit)/dist(m_exp,self.v2) - r,g,b = colorsys.hsv_to_rgb(self.hue/(2*math.pi),1.0,1.0) - _r = white_amount * 1.0 + mix_amount * r - _g = white_amount * 1.0 + mix_amount * g - _b = white_amount * 1.0 + mix_amount * b - - return (_r,_g,_b), dit - - def draw(self): - surface = self.get_cairo_surface() - - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() - - ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(),self.decorator.top_height()) - ctx.rectangle(0,0,WIDTH,HEIGHT) - ctx.set_source_rgb(204/255,204/255,204/255) - ctx.fill() - ctx.scale (WIDTH/2.0, HEIGHT/2.0) - ctx.translate(1,1) - - # Draw the concentric circles for the hue selection. - ctx.arc(0.0,0.0,1.0,0,2*math.pi) - ctx.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) - ctx.arc(0.0,0.0,0.8,0,2*math.pi) - ctx.set_source (self.pat) - ctx.fill() - - self.v1 = math.cos(self.angle+4*math.pi/3)*0.8,math.sin(self.angle+4*math.pi/3)*0.8 - self.v2 = math.cos(self.angle+6*math.pi/3)*0.8,math.sin(self.angle+6*math.pi/3)*0.8 - self.v3 = math.cos(self.angle+8*math.pi/3)*0.8,math.sin(self.angle+8*math.pi/3)*0.8 - - # Temporary pattern for inner triangle. - pat2 = cairo.MeshGradient() - pat2.begin_patch() - pat2.move_to(*self.v3) - pat2.line_to(*self.v1) - pat2.line_to(*self.v2) - pat2.line_to(*self.v3) - pat2.set_corner_color_rgb (0, 1, 1, 1) - pat2.set_corner_color_rgb (1, 0, 0, 0) - pat2.set_corner_color_rgb (2, *colorsys.hsv_to_rgb(self.hue/(2*math.pi),1.0,1.0)) - pat2.set_corner_color_rgb (3, 1, 1, 1) - pat2.end_patch() - - ctx.move_to(*self.v3) - ctx.line_to(*self.v1) - ctx.line_to(*self.v2) - ctx.line_to(*self.v3) - ctx.set_source (pat2) - ctx.fill() - - ctx.set_line_width(0.04) - ctx.move_to(*self.v2) - ctx.line_to(self.v2[0]/0.8,self.v2[1]/0.8) - ctx.set_source_rgb(0,0,0) - ctx.stroke() - - - - self.color, dit = self.calculate_color() - - ctx.arc(-0.85,-0.85,0.1,0,2*math.pi) - ctx.set_source_rgb(*self.color) - ctx.fill() - ctx.set_line_width(0.02) - ctx.arc(*dit,0.05,0,2*math.pi) - ctx.set_source_rgb(0,0,0) - ctx.stroke() - - - self.decorator.render(self) - self.flip() - - def finish_resize(self,msg): - """Accept a resize.""" - WIDTH, HEIGHT = msg.width - self.decorator.width(), msg.height - self.decorator.height() - if WIDTH != HEIGHT: - self.resize_offer(WIDTH+self.decorator.width(),WIDTH+self.decorator.height()) - return - self.resize_accept(msg.width, msg.height) - self.reinit() - self.draw() - self.resize_done() - self.flip() - - def mouse_event(self,msg): - if self.decorator.handle_event(msg) == yutani.Decor.EVENT_CLOSE: - # Close the window when the 'X' button is clicked. - self.close() - self.close_callback() - if msg.buttons & yutani.MouseButton.BUTTON_LEFT: - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() - x = msg.new_x - self.decorator.left_width() - WIDTH/2 - y = msg.new_y - self.decorator.top_height() - HEIGHT/2 - r = math.sqrt(x*x + y*y)/(WIDTH/2) - a = 0 - if x > 0 and y > 0: - a = math.degrees(math.atan(y/x)) - if y == 0 and x < 0: - a = 180 - if x == 0 and y > 0: - a = 90 - if x == 0 and y < 0: - a = 90*3 - if x < 0 and y > 0: - a = 180 + math.degrees(math.atan(y/x)) - if x < 0 and y < 0: - a = 180 + math.degrees(math.atan(y/x)) - if x > 0 and y < 0: - a = 360 + math.degrees(math.atan(y/x)) - if msg.command == yutani.MouseEvent.DOWN: - self.down_in_circle = False - self.down_in_triangle = False - if r < 0.8: - self.down_in_triangle = True - elif r <= 1.0: - self.down_in_circle = True - if self.down_in_triangle: - _x,_y = x/WIDTH*2, y/HEIGHT*2 - if point_inside((_x,_y),self.v1,self.v2,self.v3): - self.dit_th = a - math.degrees(self.angle) - self.dit_r = r - self.draw() - if self.down_in_circle: - self.hue = math.radians(360-a) - self.angle = -self.hue - self.draw() - if msg.command == yutani.MouseEvent.RAISE or msg.command == yutani.MouseEvent.CLICK: - self.down_in_circle = False - self.down_in_triangel = False - - def keyboard_event(self, msg): - if __name__ == '__main__': - if msg.event.action != 0x01: - return # Ignore anything that isn't a key down. - if msg.event.key == b'q': - self.close() - sys.exit(0) - -if __name__ == '__main__': - # Connect to the server. - import yutani_mainloop - - yutani.Yutani() - d = yutani.Decor() - - def on_close(): - sys.exit(0) - - w = ColorPickerWindow(d,on_close) - w.draw() - - yutani_mainloop.mainloop() diff --git a/userspace/py/lib/pex.py b/userspace/py/lib/pex.py deleted file mode 100644 index f63d0e4c..00000000 --- a/userspace/py/lib/pex.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/python3 -"""Toaru Packet EXchange bindings.""" - -import ctypes -import os - -pex_lib = None -_libc = None - -class pex_packet(ctypes.Structure): - _fields_ = [ - ("source", ctypes.c_uint32), - ("size", ctypes.c_size_t), - ("data", ctypes.c_char*0), - ] - -class PexServer(object): - - def __init__(self, name): - global pex_lib - global _libc - if not pex_lib: - pex_lib = ctypes.CDLL("libtoaru-pex.so") - _libc = ctypes.CDLL("libc.so") - # FILE * pex_bind(int,char *) - pex_lib.pex_bind.restype = ctypes.c_void_p - pex_lib.pex_bind.argtypes = [ctypes.c_char_p] - # size_t pex_listen(FILE *,pex_packet_t *) - pex_lib.pex_listen.restype = ctypes.c_size_t - pex_lib.pex_listen.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - - self.server = pex_lib.pex_bind(name.encode('utf-8')) - self._fileno = _libc.fileno(self.server) - - def fileno(self): - return self._fileno - - def listen(self): - p = ctypes.create_string_buffer(1024+ctypes.sizeof(pex_packet)) - size = pex_lib.pex_listen(self.server, ctypes.byref(p)) - if not size: - return (0, None) - else: - np = ctypes.cast(ctypes.addressof(p), ctypes.POINTER(pex_packet)).contents - return (size, np) - diff --git a/userspace/py/lib/toaru_webp.py b/userspace/py/lib/toaru_webp.py deleted file mode 100644 index 9ae5e984..00000000 --- a/userspace/py/lib/toaru_webp.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Small WebP library -""" -import os -import cairo -import ctypes - -_webp_lib = None - -WebPGetInfo = None -WebPDecodeBGRAInto = None - -def exists(): - return os.path.exists('/usr/lib/libwebp.so') - -def load_webp(path): - global _webp_lib - global WebPGetInfo - global WebPDecodeBGRAInto - - if not exists(): - return None - - if not _webp_lib: - _webp_lib = ctypes.CDLL('libwebp.so') - WebPGetInfo = _webp_lib.WebPGetInfo - WebPGetInfo.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)] - WebPGetInfo.restype = ctypes.c_int - - WebPDecodeBGRAInto = _webp_lib.WebPDecodeBGRAInto - WebPDecodeBGRAInto.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.c_int] - WebPDecodeBGRAInto.restype = ctypes.c_int - - with open(path, 'rb') as f: - data = f.read() - - _width = ctypes.c_int() - _height = ctypes.c_int() - WebPGetInfo(data, len(data), ctypes.byref(_width), ctypes.byref(_height)) - width, height = _width.value, _height.value - - buf = ctypes.create_string_buffer(b'\000' * width * height * 4) - WebPDecodeBGRAInto(data, len(data), buf, width * height * 4, width * 4) - - return cairo.ImageSurface.create_for_data(buf, cairo.FORMAT_ARGB32, width, height, width * 4) diff --git a/userspace/py/lib/toast.py b/userspace/py/lib/toast.py deleted file mode 100644 index 067facd7..00000000 --- a/userspace/py/lib/toast.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/python3 -"""ToaruOS toast library. - -Sends messages to the notification daemon for display.""" - -import os -from ctypes import * - -pex_lib = CDLL("libtoaru-pex.so") -pex_conn = None - -class ToastMessage(Structure): - _fields_ = [ - ("ttl", c_uint), - ("strings", c_char * 0), - ] - -def init_toast(): - """Initialize the connection to the toast daemon. This should happen automatically.""" - global pex_conn - server = os.environ.get("TOASTD","toastd").encode('utf-8') - pex_conn = pex_lib.pex_connect(server) - -def send_toast(title, message, ttl=5): - """Send a toast message to the daemon.""" - - # If not yet connected, connect. - if not pex_conn: - init_toast() - - # Title and message need to be C strings. - title = title.encode('utf-8') - message = message.encode('utf-8') - - # Build message struct. - s = len(title) + len(message) + 2 - b = create_string_buffer(s + sizeof(ToastMessage)) - m = ToastMessage(ttl=ttl) - memmove(addressof(b), addressof(m), sizeof(m)) - memmove(addressof(b)+sizeof(m),title,len(title)+1) - memmove(addressof(b)+sizeof(m)+len(title)+1,message,len(message)+1) - - # Send it off. - pex_lib.pex_reply(pex_conn, s + sizeof(ToastMessage), b) - - diff --git a/userspace/py/lib/ttk.py b/userspace/py/lib/ttk.py deleted file mode 100644 index f6b5b454..00000000 --- a/userspace/py/lib/ttk.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/python3 - -import yutani - -decorations = None -_windows = {} - -def rgb(r,g,b): - return yutani.yutani_gfx_lib.rgb(r,g,b) - -class Button(object): # TODO widget base class? - pass - -class Window(object): # TODO container base class? - - def __init__(self): - global decorations - - if not yutani.yutani_lib: - yutani.Yutani() - - if not decorations: - decorations = yutani.Decor() - - self.decorated = True - self._win = None - self.title = "TTK Window" - - def _create_window(self): - w,h = self._calculate_bounds() - self._win = yutani.Window(w,h, flags=0, title=self.title) - self._win.move(100, 100) - _windows[self._win.wid] = self - - def _calculate_bounds(self): - return (decorations.width() + 200, decorations.height() + 200) - - def show(self): - if not self._win: - self._create_window() - self._win.fill(rgb(214,214,214)) - if self.decorated: - decorations.render(self._win, self.title) - self._win.flip() - - def close(self): - # TODO callback - self._win.close() - -def main(): - """TTK main""" - while 1: - # Poll for events. - msg = yutani.yutani_ctx.poll() - if msg.type == yutani.Message.MSG_SESSION_END: - # All applications should attempt to exit on SESSION_END. - for w in _windows.values(): - w.close() - break - elif msg.type == yutani.Message.MSG_KEY_EVENT: - # Print key events for debugging. - if msg.event.key == b'q': - # Convention says to close windows when 'q' is pressed, - # unless we're using keyboard input "normally". - w = _windows.get(msg.wid) - if w: - w.close() - break - elif msg.type == yutani.Message.MSG_WINDOW_FOCUS_CHANGE: - # If the focus of our window changes, redraw the borders. - w = _windows.get(msg.wid) - if w: - w._win.focused = msg.focused - w.show() - elif msg.type == yutani.Message.MSG_RESIZE_OFFER: - # Resize request for window. - pass - elif msg.type == yutani.Message.MSG_WINDOW_MOUSE_EVENT: - w = _windows.get(msg.wid) - if w: - r = None - if w.decorated: - r = decorations.handle_event(msg) - if r == yutani.Decor.EVENT_CLOSE: - w.close - break - else: - pass - -if __name__ == '__main__': - w = Window() - w.show() - main() diff --git a/userspace/tests/core-tests.c b/userspace/tests/core-tests.c deleted file mode 100644 index 01c718d1..00000000 --- a/userspace/tests/core-tests.c +++ /dev/null @@ -1,12 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -#include -#include "lib/testing.h" - -int main(int argc, char * argv[]) { - INFO("Hello world!"); - - DONE("Finished tests!"); -} diff --git a/userspace/tests/test-argv.c b/userspace/tests/test-argv.c deleted file mode 100644 index 08109704..00000000 --- a/userspace/tests/test-argv.c +++ /dev/null @@ -1,30 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * Argument processing test tool. - * - * Usage: - * Run as ./argv-tester herp derp etc. - * Evaluate the arguments as they are printed to verify - * they match the input that you provided. - */ -#include - -int main(int argc, char * argv[]) { - printf("argc = %d\n", argc); - for (int i = 0; i < argc; ++i) { - printf("%p argv[%d]= %s\n", argv[i], i, argv[i]); - } - printf("continuing until I hit a 0\n"); - int i = argc; - while (1) { - printf("argv[%d] = 0x%x\n", i, argv[i]); - if (argv[i] == 0) { - break; - } - i++; - } - return 0; -} diff --git a/userspace/tests/test-big-alloc.c b/userspace/tests/test-big-alloc.c deleted file mode 100644 index 7fb0098a..00000000 --- a/userspace/tests/test-big-alloc.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include - -#include - -#include "lib/pthread.h" - -char * x; -int i; - -void *print_pid(void * garbage) { - printf("x[%d] = %d\n", i, x[i]); - pthread_exit(NULL); -} - -int main(int argc, char * argv[]) { - printf("Making a big allocation!\n"); - x = malloc(0x400000); - x[0x355555] = 'a'; - i = atoi(argv[1]); - pthread_t thread; - pthread_create(&thread, NULL, print_pid, NULL); - - waitpid(thread.id, NULL, 0); - return x[i]; -} diff --git a/userspace/tests/test-boxchars.c b/userspace/tests/test-boxchars.c deleted file mode 100644 index 655e98e8..00000000 --- a/userspace/tests/test-boxchars.c +++ /dev/null @@ -1,17 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include -#include - -int main(int argc, char * argv[]) { - wchar_t * c = L"▒␉␌␍␊°±␤␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥"; - char d = 'a'; - while (*c) { - printf("%d - %c \033(0%c\033(B\n", *c, d, d); - c++; - d++; - } - return 0; -} diff --git a/userspace/tests/test-c++.c++ b/userspace/tests/test-c++.c++ deleted file mode 100644 index c33defe4..00000000 --- a/userspace/tests/test-c++.c++ +++ /dev/null @@ -1,11 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -using namespace std; - -int main() { - cout << "hello world!\n"; - return 0; -} diff --git a/userspace/tests/test-chmod.c b/userspace/tests/test-chmod.c deleted file mode 100644 index 90a5cb4e..00000000 --- a/userspace/tests/test-chmod.c +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include -#include - -int main(int argc, char * argv[]) { - struct stat s; - stat(argv[1], &s); - chmod(argv[1], s.st_mode | S_IXUSR | S_IXGRP | S_IXOTH); - return 0; -} diff --git a/userspace/tests/test-clock.c b/userspace/tests/test-clock.c deleted file mode 100644 index 8c246c0b..00000000 --- a/userspace/tests/test-clock.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include -#include - -int main(int argc, char * argv[]) { - struct timeval now, later; - struct tm * timeinfo; - int up, upa, upb, upc; - FILE * uptime; - gettimeofday(&now, NULL); - uptime = fopen("/proc/uptime","r"); - fscanf(uptime, "%d.%2d", &up, &upa); - fclose(uptime); - - sleep(5); - gettimeofday(&later, NULL); - uptime = fopen("/proc/uptime","r"); - fscanf(uptime, "%d.%2d", &upb, &upc); - fclose(uptime); - - fprintf(stderr, "Before: %d, %d.%2d\n", now.tv_sec, up, upa); - fprintf(stderr, "After: %d, %d.%2d\n", later.tv_sec, upb, upc); - return 0; -} diff --git a/userspace/tests/test-confreader.c b/userspace/tests/test-confreader.c deleted file mode 100644 index f914309e..00000000 --- a/userspace/tests/test-confreader.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#include "lib/confreader.h" - -int main(int argc, char * argv[]) { - confreader_t * conf = confreader_load("/etc/test.conf"); - - assert(!strcmp(confreader_get(conf, "", "hey"), "yeah")); - assert(confreader_get(conf, "", "foo") == NULL); - - assert(!strcmp(confreader_get(conf, "sectiona", "foo"), "bar")); - assert(!strcmp(confreader_get(conf, "sectiona", "baz"), "qix")); - assert(confreader_get(conf, "sectiona", "herp") == NULL); - - assert(!strcmp(confreader_get(conf, "sectionb", "lol"), "butts")); - assert(confreader_get(conf, "sectionb", "foo") == NULL); - - confreader_free(conf); - - return 0; -} diff --git a/userspace/tests/test-dl.c b/userspace/tests/test-dl.c deleted file mode 100644 index a8f1c7d1..00000000 --- a/userspace/tests/test-dl.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Based on a demo in the Linux manpages. - */ -#include -#include - -#include "lib/dlfcn.h" - -int main(int argc, char * argv[]) { - - void * handle; - double (*cosine)(double); - char * error; - - handle = dlopen("libm.so", 0); /* TODO constants */ - if (!handle) { - fprintf(stderr, "%s\n", dlerror()); - return 1; - } - - /* Clear error */ - dlerror(); - - cosine = (double (*)(double))dlsym(handle, "cos"); - - error = dlerror(); - if (error != NULL) { - fprintf(stderr, "%s\n", error); - return 1; - } - - printf("%f\n", (*cosine)(2.0)); - dlclose(handle); - - return 0; -} diff --git a/userspace/tests/test-dsr.c b/userspace/tests/test-dsr.c deleted file mode 100644 index a30e9810..00000000 --- a/userspace/tests/test-dsr.c +++ /dev/null @@ -1,22 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include - -int main (int argc, char * argv) { - printf("I'm going to move the cursor here >"); - fflush(stdout); - printf("\033[6n"); - fflush(stdout); - int x, y; - scanf("\033[%d;%dR", &y, &x); - printf("\n\nThe cursor was at %d, %d\n", x, y); - printf("I will now put ◯ where the cursor was.\n"); - char derp[1]; - gets(derp); - printf("\033[%d;%dH◯\n\n\n\n", y, x); - - printf("Done!\n"); - return 0; -} diff --git a/userspace/tests/test-echo.c b/userspace/tests/test-echo.c deleted file mode 100644 index 62691562..00000000 --- a/userspace/tests/test-echo.c +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* - * echo-test - * - * Prints a test string to standard out - * that includes various bits of ANSI - * escape sequences. - */ -#include - -int main(int argc, char ** argv) { - - printf("\n\033[1mBold \033[0m\033[3mItalic \033[1mBold+Italic\033[0m\033[0m \033[4mUnderline\033[0m \033[9mX-Out\033[0m \033[1;3;4;9mEverything\033[0m\n"); - - printf("\033[38;2;178;213;238mHello World\033[0m\n"); - - for (int i = 0; i < 256; i += 3) { - printf("\033[48;6;255;0;0;%dmX\033[0m", i); - } - printf("\n"); - - for (int i = 0; i < 256; i += 3) { - printf("\033[48;6;255;0;0;0;m\033[38;6;255;0;0;%dmX\033[0m", i); - } - printf("\n"); - - return 0; -} - -/* - * vim:tabstop=4 - * vim:noexpandtab - * vim:shiftwidth=4 - */ diff --git a/userspace/tests/test-env.c b/userspace/tests/test-env.c deleted file mode 100644 index 7f624238..00000000 --- a/userspace/tests/test-env.c +++ /dev/null @@ -1,17 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include -#include - -int main(int argc, char * argv) { - printf("hello world\n"); - char * term = getenv("TERM"); - if (term) { - printf("TERM=%s\n", term); - } else { - printf("TERM is not set.\n"); - } - return 0; -} diff --git a/userspace/tests/test-fs.c b/userspace/tests/test-fs.c deleted file mode 100644 index 9aab376d..00000000 --- a/userspace/tests/test-fs.c +++ /dev/null @@ -1,22 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* vim:tabstop=4 shiftwidth=4 noexpandtab - * - * File System Test Suite - * (incomplete) - */ -#include -#include -#include - -int main(int argc, char ** argv) { - printf("= Begin File System Testing =\n"); - - int fd = creat("/test.log", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - printf("File descriptor generator: %d\n", fd); - - return 0; -} diff --git a/userspace/tests/test-lots-of-files.c b/userspace/tests/test-lots-of-files.c deleted file mode 100644 index df5b3dad..00000000 --- a/userspace/tests/test-lots-of-files.c +++ /dev/null @@ -1,32 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include -#include -#include - -#define CHUNK_SIZE 4096 - -void doit(int fd) { - while (1) { - char buf[CHUNK_SIZE]; - memset(buf, 0, CHUNK_SIZE); - ssize_t r = read(fd, buf, CHUNK_SIZE); - if (!r) return; - write(STDOUT_FILENO, buf, r); - } -} - -int main(int argc, char * argv[]) { - - for (int i = 0; i < 500; ++i) { - int fd = open("/proc/meminfo", O_RDONLY); - doit(fd); - close(fd); - } - - return 0; -} diff --git a/userspace/tests/test-lots-of-procs.c b/userspace/tests/test-lots-of-procs.c deleted file mode 100644 index c1a88f13..00000000 --- a/userspace/tests/test-lots-of-procs.c +++ /dev/null @@ -1,41 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include -#include -#include - -#define CHUNK_SIZE 4096 - -void doit(int fd) { - lseek(fd, 0, SEEK_SET); - while (1) { - char buf[CHUNK_SIZE]; - memset(buf, 0, CHUNK_SIZE); - ssize_t r = read(fd, buf, CHUNK_SIZE); - if (!r) return; - write(STDOUT_FILENO, buf, r); - } -} - - -int main(int argc, char * argv[]) { - int fd = open("/proc/meminfo", O_RDONLY); - - for (int i = 0; i < 500; ++i) { - - if (!fork()) { - doit(fd); - return 0; - } - - waitpid(-1, NULL, 0); - } - - close(fd); - - return 0; -} diff --git a/userspace/tests/test-multitasking.c b/userspace/tests/test-multitasking.c deleted file mode 100644 index 0b25d7fa..00000000 --- a/userspace/tests/test-multitasking.c +++ /dev/null @@ -1,57 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* vim: tabstop=4 noexpandtab shiftwidth=4 - * - * Multitasking Thrasher - * - * Useful for testing that multitasking still works. - * Starts up a bunch of threads, lets them do stuff, - * cleans them up, etc. - * - */ - -#include -#include -#include -#include -#include -#include - -int main(int argc, char ** argv) { - int nthreads = 2, base_pid = getpid(), npid = -1; - - if (argc > 1) { - /* Read some arguments */ - int c; - while ((c = getopt(argc, argv, "n:")) != -1) { - switch (c) { - case 'n': - nthreads = atoi(optarg); - break; - default: - break; - } - } - } - - printf("I am pid %d\n", base_pid); - printf("Starting %d threads.\n", nthreads); - - for (int i = 0; i < nthreads; ++i) { - int pid = fork(); - if (!pid) { - while (1) { - printf("%c", i + 'A'); - fflush(stdout); - } - } else { - npid = pid; - } - } - - printf("Done.\n"); - - return 0; -} diff --git a/userspace/tests/test-open-flags.c b/userspace/tests/test-open-flags.c deleted file mode 100644 index ea8157f8..00000000 --- a/userspace/tests/test-open-flags.c +++ /dev/null @@ -1,16 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include -#include -int main(int argc, char * argv) { - printf("O_RDONLY 0x%x\n", O_RDONLY); - printf("O_WRONLY 0x%x\n", O_WRONLY); - printf("O_RDWR 0x%x\n", O_RDWR); - printf("O_APPEND 0x%x\n", O_APPEND); - printf("O_CREAT 0x%x\n", O_CREAT); - printf("O_EXCL 0x%x\n", O_EXCL); - printf("O_TRUNC 0x%x\n", O_TRUNC); - return 0; -} diff --git a/userspace/tests/test-pex.c b/userspace/tests/test-pex.c deleted file mode 100644 index 5367cc05..00000000 --- a/userspace/tests/test-pex.c +++ /dev/null @@ -1,90 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include -#include -#include -#include - -#include "lib/testing.h" -#include "lib/pex.h" - -int main(int argc, char * argv[]) { - FILE * server = pex_bind("testex"); - FILE * client = pex_connect("testex"); - - char * foo = "Hello World!"; - pex_reply(client, strlen(foo)+1, foo); - - size_t query_result; - - query_result = pex_query(server); - if (query_result < 1) { - FAIL("Expected pex_query to return something > 0, got %d", query_result); - } else { - PASS("."); - } - - pex_packet_t * p = calloc(PACKET_SIZE, 1); - pex_listen(server, p); - - unsigned int client_id = p->source; - - if (!strcmp("Hello World!", p->data)) { - PASS("Client-server message received."); - } else { - FAIL("Expected message of 'Hello World!', got %s", p->data); - } - - free(p); - - query_result = pex_query(server); - if (query_result != 0) { - FAIL("Expected pex_query to return 0, got %d", query_result); - } else { - PASS("."); - } - - query_result = pex_query(client); - if (query_result != 0) { - FAIL("Expected pex_query to return 0, got %d", query_result); - } else { - PASS("."); - } - - char * foo2 = "Hello everyone!\n"; - pex_broadcast(server, strlen(foo2)+1, foo2); - - query_result = pex_query(client); - if (query_result < 1) { - FAIL("Expected pex_query to return something > 0, got %d", query_result); - } else { - PASS("."); - } - - char out[MAX_PACKET_SIZE]; - size_t size = pex_recv(client, out); - if (!strcmp("Hello everyone!\n", out)) { - PASS("Server broadcast received."); - } else { - FAIL("Expected message of 'Hello everyone\\n!', got %s", out); - } - - char * foo3 = malloc(MAX_PACKET_SIZE); - memset(foo3, 0x42, MAX_PACKET_SIZE); - for (int i = 0; i < 3; ++i) { - size_t size = pex_send(server, client_id, MAX_PACKET_SIZE, foo3); - if (size != MAX_PACKET_SIZE) FAIL("Bad packet size (%d)", size); - else PASS("."); - } - - size_t tmp_size = pex_send(server, client_id, MAX_PACKET_SIZE, foo3); - if (tmp_size != -1) FAIL("Bad packet size (%d)", tmp_size); - else PASS("Packet dropped successfully."); - - fclose(client); - fclose(server); - return 0; -} diff --git a/userspace/tests/test-pipe.c b/userspace/tests/test-pipe.c deleted file mode 100644 index 33680543..00000000 --- a/userspace/tests/test-pipe.c +++ /dev/null @@ -1,35 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * pipe test - * - * Makes a pipe. Pipes stuff to it. Yeah. - */ - -#include -#include -#include -#include -#include -#include - -int main(int argc, char ** argv) { - int fd = syscall_mkpipe(); - printf("%d <- pipe\n", fd); - int pid = getpid(); - uint32_t f = fork(); - if (getpid() != pid) { - char buf[512]; - int r = read(fd, buf, 13); - printf("[%d] %s\n", r, buf); - return 0; - } else { - char * buf = "Hello world!"; - write(fd, buf, strlen(buf) + 1); - return 0; - } - - return 0; -} diff --git a/userspace/tests/test-signal.c b/userspace/tests/test-signal.c deleted file mode 100644 index 00f5c615..00000000 --- a/userspace/tests/test-signal.c +++ /dev/null @@ -1,28 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include -#include -#include -#include - -void sig_winch(int signum) { - struct winsize w; - int width, height; - ioctl(0, TIOCGWINSZ, &w); - width = w.ws_col; - height = w.ws_row; - printf("Terminal is %dx%d\n", width, height); -} - -int main(int argc, char * argv[]) { - signal(SIGWINCH, sig_winch); - while (1) { - int c = fgetc(stdin); - if (c == 'q') { - break; - } - } - return 0; -} diff --git a/userspace/tests/test-symlink.c b/userspace/tests/test-symlink.c deleted file mode 100644 index 7a605aec..00000000 --- a/userspace/tests/test-symlink.c +++ /dev/null @@ -1,74 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Mike Gerow - */ -#include -#include -#include -#include - -#include "lib/testing.h" - -static char test58[] = - "0000000000000000000000000000000000000000000000000000000000"; -static char test59[] = - "00000000000000000000000000000000000000000000000000000000000"; -static char test60[] = - "000000000000000000000000000000000000000000000000000000000000"; -static char test61[] = - "0000000000000000000000000000000000000000000000000000000000000"; - -int main(int argc, char * argv[]) { - INFO("Starting symlink test"); - if (symlink(test58, "/home/root/test58") < 0) { - perror("symlink(/home/root/test58)"); - } - if (symlink(test59, "/home/root/test59") < 0) { - perror("symlink(/home/root/test59)"); - } - if (symlink(test60, "/home/root/test60") < 0) { - perror("symlink(/home/root/test60)"); - } - if (symlink(test61, "/home/root/test61") < 0) { - perror("symlink(/home/root/test61)"); - } - - char buf[128]; - int failed = 0; - - if (readlink("/home/root/test58", buf, sizeof(buf)) < 0) { - perror("readlink(/home/root/test58)"); - } - if (strcmp(buf, test58) != 0) { - FAIL("Link sized 58 is wrong"); - failed = 1; - } - if (readlink("/home/root/test59", buf, sizeof(buf)) < 0) { - perror("readlink(/home/root/test59)"); - } - if (strcmp(buf, test59) != 0) { - FAIL("Link sized 59 is wrong"); - failed = 1; - } - if (readlink("/home/root/test60", buf, sizeof(buf)) < 0) { - perror("readlink(/home/root/test60)"); - } - if (strcmp(buf, test60) != 0) { - FAIL("Link sized 60 is wrong"); - failed = 1; - } - if (readlink("/home/root/test61", buf, sizeof(buf)) < 0) { - perror("readlink(/home/root/test61)"); - } - if (strcmp(buf, test61) != 0) { - FAIL("Link sized 61 is wrong"); - failed = 1; - } - - if (failed) { - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); -} diff --git a/userspace/tests/test-system.c b/userspace/tests/test-system.c deleted file mode 100644 index f8e16c5f..00000000 --- a/userspace/tests/test-system.c +++ /dev/null @@ -1,12 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include -#include - -int main(int arch, char * argv[]) { - fprintf(stderr, "Calling system(\"echo hello world\")\n"); - int ret = system("echo hello world"); - fprintf(stderr, "Done. Returned %d.\n", ret); -} diff --git a/userspace/tests/test-threads.c b/userspace/tests/test-threads.c deleted file mode 100644 index 761fb2ed..00000000 --- a/userspace/tests/test-threads.c +++ /dev/null @@ -1,77 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* - * threadtest - * - * A class concurreny failure demonstration. - * Append -l to use locks. - */ -#include -#include -#include -#include -#include -#include -#include -#include "lib/pthread.h" -#include "lib/spinlock.h" - -#define NUM_THREADS 5 -#define VALUE 0x1000000 -#define CHECKPOINT 0x03FFFFF - -volatile uint32_t result = 0; -int8_t use_locks = 0; - -volatile int the_lock = 0; - -void *print_pid(void * garbage) { - int i; - printf("I am a thread and my pid is %d but my tid is %d and my stack is at %p\n", getpid(), gettid(), &i); - - for (uint32_t i = 0; i < VALUE; ++i) { - if (use_locks) { - spin_lock(&the_lock); - } - if (!(result & CHECKPOINT)) { - printf("[%d] Checkpoint: %x\n", gettid(), result); - } - result++; - if (use_locks) { - spin_unlock(&the_lock); - } - } - - pthread_exit(garbage); -} - -int main(int argc, char * argv[]) { - if (argc > 1) { - if (!strcmp(argv[1], "-l")) { - use_locks = 1; - } - } - pthread_t thread[NUM_THREADS]; - printf("I am the main process and my pid is %d and my tid is also %d\n", getpid(), gettid()); - - printf("Attempting to %s calculate %d!\n", - (use_locks) ? "(safely)" : "(unsafely)", - NUM_THREADS * VALUE); - - for (int i = 0; i < NUM_THREADS; ++i) { - pthread_create(&thread[i], NULL, print_pid, NULL); - } - - for (int i = 0; i < NUM_THREADS; ++i) { - waitpid(thread[i].id, NULL, 0); - } - - printf("Done. Result of %scomputation was %d %s!!\n", - (use_locks) ? "" : "(definitely unsafe) ", - result, - (result == NUM_THREADS * VALUE) ? "(yay, that's right!)" : "(boo, that's wrong!)"); - - return 0; -} diff --git a/userspace/tests/test-utf8.c b/userspace/tests/test-utf8.c deleted file mode 100644 index fa83f4ec..00000000 --- a/userspace/tests/test-utf8.c +++ /dev/null @@ -1,47 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -#include -#include - -#include "lib/utf8decode.h" - -static char * c = "🍕"; -static char * t = "😎"; -static char * z = "😸"; -static char * y = "😹"; - -static uint32_t codepoint; -static uint32_t state = 0; - -void decodestring(char * s) { - uint32_t o = 0; - char * c = s; - - while (*s) { - if (!decode(&state, &codepoint, (uint8_t)*s)) { - o = (uint32_t)codepoint; - s++; - goto decoded; - } else if (state == UTF8_REJECT) { - state = 0; - } - s++; - } -decoded: - fprintf(stdout, "Decoded %s to 0x%x (%d)\n", c, codepoint, codepoint); -} - -int main(int argc, char * argv[]) { - fprintf(stdout, "Length(:pizza:) = %d\n", strlen(c)); - - for (int i = 0; i < 5; ++i) { - decodestring(c); - decodestring(t); - decodestring(z); - decodestring(y); - } - - return 0; -} diff --git a/userspace/tests/test-write.c b/userspace/tests/test-write.c deleted file mode 100644 index 9f1bf773..00000000 --- a/userspace/tests/test-write.c +++ /dev/null @@ -1,30 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014 Kevin Lange - */ -/* - * Testing tool to write a file with the given contents. - */ -#include -#include - -int main(int argc, char * argv[]) { - if (argc < 3) { - fprintf(stderr, "usage: %s name \"content...\"\n", argv[0]); - return 1; - } - FILE * f = fopen(argv[1], "w"); - - if (!f) { - fprintf(stderr, "%s: fopen: failed to open file\n", argv[0]); - return 2; - } - - size_t r = fwrite(argv[2], 1, strlen(argv[2]), f); - - fclose(f); - - fprintf(stderr, "%s: wrote %d bytes\n", argv[0], r); - - return 0; -} diff --git a/userspace/util/stack-overflow.c b/userspace/util/stack-overflow.c deleted file mode 100644 index 1e4664c4..00000000 --- a/userspace/util/stack-overflow.c +++ /dev/null @@ -1,23 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * Sample application which triggers a stack overflow - * by means of a simple infinitely recursive function. - */ -#include -#include - -void overflow() { - int i[1024] = {0xff}; - printf("Stack is at 0x%x\n", &i); - overflow(); -} - -int main(int argc, char ** argv) { - overflow(); - - return 0; -} diff --git a/userspace/util/stack-reaper.c b/userspace/util/stack-reaper.c deleted file mode 100644 index e6b2ed74..00000000 --- a/userspace/util/stack-reaper.c +++ /dev/null @@ -1,23 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include - -int main(int argc, char ** argv) { - printf("Exploring the stack...\n"); - unsigned int x = 0; - unsigned int nulls = 0; - while (1) { - if (!argv[x]) { ++nulls; } - printf("argv[%.2d] = [%p] %s\n", x, argv[x], argv[x]); - ++x; - if (nulls == 2) { break; } - } - printf("[ELF AuxV]\n"); - while (1) { - printf("auxv[%.2d] = %.2d -> 0x%x\n", x, (unsigned int)argv[x], (unsigned int)argv[x+1]); - if (argv[x] == 0) { break; } /* AT_NULL, technically, but that's 0 */ - x += 2; - } -} diff --git a/userspace/util/term-size.c b/userspace/util/term-size.c deleted file mode 100644 index c5f4c3d9..00000000 --- a/userspace/util/term-size.c +++ /dev/null @@ -1,14 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013 Kevin Lange - */ -#include -#include -#include - -int main(int argc, char * argv[]) { - struct winsize w; - ioctl(0, TIOCGWINSZ, &w); - printf("Terminal is %dx%d (%d px x %d px)\n", w.ws_col, w.ws_row, w.ws_xpixel, w.ws_ypixel); - return 0; -} diff --git a/userspace/util/thrash-process.c b/userspace/util/thrash-process.c deleted file mode 100644 index 94d771dd..00000000 --- a/userspace/util/thrash-process.c +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2014 Kevin Lange - */ -/* - * thrash-process - * Creates a lot of processes. - */ -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char ** argv) { - int quiet = 0; - if (argc > 1) { - if (!strcmp(argv[1],"-q")) { - printf("I'll be quiet...\n"); - quiet = 1; - } - } - for (int j = 0; j < 1024; ++j) { - volatile int k = fork(); - if (!quiet) - printf("I am %d, I got %d\n", getpid(), k); - if (k == 0) { - if (!quiet || !(j % 10)) - printf("I am %d\n", getpid()); - return 0; - } else { - if (!quiet) - printf("Waiting on %d\n", k); - waitpid(k, NULL, 0); - } - } - return 0; -} diff --git a/util/256colres.pl b/util/256colres.pl deleted file mode 100755 index 99e0d08d..00000000 --- a/util/256colres.pl +++ /dev/null @@ -1,74 +0,0 @@ -#! /usr/bin/perl -# $XTermId: 256colres.pl,v 1.16 2007/06/08 23:58:37 tom Exp $ -# ----------------------------------------------------------------------------- -# this file is part of xterm -# -# Copyright 1999-2002,2007 by Thomas E. Dickey -# -# All Rights Reserved -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name(s) of the above copyright -# holders shall not be used in advertising or otherwise to promote the -# sale, use or other dealings in this Software without prior written -# authorization. -# ----------------------------------------------------------------------------- - -# Construct a header file defining default resources for the 256-color model -# of xterm. This is modeled after the 256colors2.pl script. - -# use the resources for colors 0-15 - usually more-or-less a -# reproduction of the standard ANSI colors, but possibly more -# pleasing shades - -# Modified by Kevin Lange for use in the ToAruOS Kernel video -# terminal drivers (for compatibility with the xterm 256 color palette) - -use strict; - -our ( $line1, $line2, $line3 ); -our ( $red, $green, $blue, $gray ); -our ( $level, $code, @steps ); - -$line3="\t\t\t\t 0x%2.2x%2.2x%2.2x,\n"; - -# colors 16-231 are a 6x6x6 color cube -for ($red = 0; $red < 6; $red++) { - for ($green = 0; $green < 6; $green++) { - for ($blue = 0; $blue < 6; $blue++) { - $code = 16 + ($red * 36) + ($green * 6) + $blue; - printf($line3, - ($red ? ($red * 40 + 55) : 0), - ($green ? ($green * 40 + 55) : 0), - ($blue ? ($blue * 40 + 55) : 0)); - } - } -} - -# colors 232-255 are a grayscale ramp, intentionally leaving out -# black and white -$code=232; -for ($gray = 0; $gray < 24; $gray++) { - $level = ($gray * 10) + 8; - $code = 232 + $gray; - printf($line3, - $level, $level, $level); -} diff --git a/util/Vagrantfile b/util/Vagrantfile deleted file mode 100644 index fffa4437..00000000 --- a/util/Vagrantfile +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure(2) do |config| - config.vm.box = "ubuntu/xenial64" - - config.vm.provider "virtualbox" do |vb| - vb.memory = "1024" - end -end diff --git a/util/activate.sh b/util/activate.sh new file mode 100755 index 00000000..0236be1f --- /dev/null +++ b/util/activate.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +export PATH="$DIR/local/bin:$PATH" +export TOOLCHAIN="$DIR" +echo "$PATH" diff --git a/util/auto-dep.py b/util/auto-dep.py index 7daf8b24..d8f0afe5 100755 --- a/util/auto-dep.py +++ b/util/auto-dep.py @@ -10,49 +10,36 @@ except KeyError: # This is not good, but we need to let it happen for the make file TOOLCHAIN_PATH = "" -force_static = ["GLU"] - class Classifier(object): dependency_hints = { - # Core libraries - '': (None, '-lm', []), - '': ('cairo', '-lcairo', ['', '', '']), - '': ('freetype2', '-lfreetype', ['']), - '': ('pixman-1', '-lpixman-1', ['']), - '': (None, '-lOSMesa', []), - '': (None, '-lGLU', ['']), - '': ('ncurses', '-lncurses', []), - '': (None, '-lpanel', ['']), - '': (None, '-lmenu', ['']), - '': (None, '-lz', ['']), - '': (None, '-lpng15', ['']), - '': ('python/include/python3.6m', '-lpython3.6m', ['']), # Toaru Standard Library - '': (None, '-ltoaru', ['','','']), - '"lib/toaru_auth.h"': (None, '-ltoaru-toaru_auth', ['"lib/sha2.h"']), - '"lib/kbd.h"': (None, '-ltoaru-kbd', []), - '"lib/list.h"': (None, '-ltoaru-list', []), - '"lib/hashmap.h"': (None, '-ltoaru-hashmap', ['"lib/list.h"']), - '"lib/tree.h"': (None, '-ltoaru-tree', ['"lib/list.h"']), - '"lib/testing.h"': (None, '-ltoaru-testing', []), - '"lib/pthread.h"': (None, '-ltoaru-pthread', []), - '"lib/sha2.h"': (None, '-ltoaru-sha2', []), - '"lib/pex.h"': (None, '-ltoaru-pex', []), - '"lib/graphics.h"': (None, '-ltoaru-graphics', ['']), - '"lib/shmemfonts.h"': (None, '-ltoaru-shmemfonts', ['"lib/graphics.h"', '']), - '"lib/rline.h"': (None, '-ltoaru-rline', ['"lib/kbd.h"']), - '"lib/confreader.h"': (None, '-ltoaru-confreader', ['"lib/hashmap.h"']), - '"lib/network.h"': (None, '-ltoaru-network', []), - '"lib/http_parser.h"': (None, '-ltoaru-http_parser', []), - '"lib/dlfcn.h"': (None, '-ltoaru-dlfcn', []), - # Yutani Libraries - '"lib/yutani.h"': (None, '-ltoaru-yutani', ['"lib/kbd.h"', '"lib/list.h"', '"lib/pex.h"', '"lib/graphics.h"', '"lib/hashmap.h"']), - '"lib/decorations.h"': (None, '-ltoaru-decorations', ['"lib/shmemfonts.h"', '"lib/graphics.h"', '"lib/yutani.h"','"lib/dlfcn.h"']), - '"gui/terminal/lib/termemu.h"': (None, '-ltoaru-termemu', ['"lib/graphics.h"']), + '': (None, '-ltoaru_kbd', []), + '': (None, '-ltoaru_list', []), + '': (None, '-ltoaru_hashmap', ['']), + '': (None, '-ltoaru_tree', ['']), + '': (None, '-ltoaru_pex', []), + '': (None, '-ltoaru_auth', []), + '': (None, '-ltoaru_graphics', []), + '': (None, '-ltoaru_drawstring', ['']), + '': (None, '-ltoaru_rline', ['']), + '': (None, '-ltoaru_rline_exp', ['']), + '': (None, '-ltoaru_confreader', ['']), + '': (None, '-ltoaru_yutani', ['', '', '', '', '']), + '': (None, '-ltoaru_decorations', ['', '', '', '']), + '': (None, '-ltoaru_termemu', ['']), + '': (None, '-ltoaru_sdf', ['', '']), + '': (None, '-ltoaru_icon_cache', ['', '']), + '': (None, '-ltoaru_menu', ['', '', '', '', '']), + '': (None, '-ltoaru_textregion', ['', '','', '']), + # OPTIONAL third-party libraries, for extensions / ports + '': ('freetype2', '-lfreetype', []), + '': ('pixman-1', '-lpixman-1', []), + '': ('cairo', '-lcairo', ['', '']), } def __init__(self, filename): + self.export_dynamic_hint = False self.filename = filename self.includes, self.libs = self._depends() @@ -89,6 +76,8 @@ class Classifier(object): for l in lines: if l.startswith('#include'): depends.extend([k for k in list(self.dependency_hints.keys()) if l.startswith('#include ' + k)]) + elif l.startswith('/* auto-dep: export-dynamic */'): + self.export_dynamic_hint = True depends = self._calculate([], depends) depends = self._sort(depends) includes = [] @@ -96,7 +85,7 @@ class Classifier(object): for k in depends: dep = self.dependency_hints[k] if dep[0]: - includes.append('-I' + TOOLCHAIN_PATH + '/include/' + dep[0]) + includes.append('-I' + 'base/usr/include/' + dep[0]) if dep[1]: libraries.append(dep[1]) return includes, libraries @@ -106,13 +95,19 @@ def todep(name): """Convert a library name to an archive path or object file name.""" if name.startswith("-l"): name = name.replace("-l","",1) - if name in force_static: - return (False, "%s/lib%s.a" % (TOOLCHAIN_PATH + '/lib', name)) + if name.startswith('toaru'): + return (True, "%s/lib%s.so" % ('base/lib', name)) else: - return (True, "%s/lib%s.so" % ('hdd/usr/lib', name)) + return (True, "%s/lib%s.so" % ('base/usr/lib', name)) else: return (False, name) +def toheader(name): + if name.startswith('-ltoaru_'): + return name.replace('-ltoaru_','base/usr/include/toaru/') + '.h' + else: + return '' + if __name__ == "__main__": if len(sys.argv) < 3: print("usage: util/auto-dep.py command filename") @@ -131,3 +126,25 @@ if __name__ == "__main__": normal = [x[1] for x in results if not x[0]] order_only = [x[1] for x in results if x[0]] print(" ".join(normal) + " | " + " ".join(order_only)) + elif command == "--make": + print("base/bin/{app}: {source} {headers} util/auto-dep.py | {libraryfiles} $(LC)\n\t$(CC) $(CFLAGS) {extra} {includes} -o $@ $< {libraries}".format( + app=os.path.basename(filename).replace(".c",""), + source=filename, + headers=" ".join([toheader(x) for x in c.libs]), + libraryfiles=" ".join([todep(x)[1] for x in c.libs]), + libraries=" ".join([x for x in c.libs]), + includes=" ".join([x for x in c.includes if x is not None]), + extra="-Wl,--export-dynamic" if c.export_dynamic_hint else "", + )) + elif command == "--makelib": + libname = os.path.basename(filename).replace(".c","") + _libs = [x for x in c.libs if not x.startswith('-ltoaru_') or x.replace("-ltoaru_","") != libname] + print("base/lib/libtoaru_{lib}.so: {source} {headers} util/auto-dep.py | {libraryfiles} $(LC)\n\t$(CC) $(CFLAGS) {includes} -shared -fPIC -o $@ $< {libraries}".format( + lib=libname, + source=filename, + headers=" ".join([toheader(x) for x in c.libs]), + libraryfiles=" ".join([todep(x)[1] for x in _libs]), + libraries=" ".join([x for x in _libs]), + includes=" ".join([x for x in c.includes if x is not None]) + )) + diff --git a/util/bin/.git-marker b/util/bin/.git-marker deleted file mode 100644 index e69de29b..00000000 diff --git a/util/boot/grub/grub.cfg b/util/boot/grub/grub.cfg deleted file mode 100644 index 77b28544..00000000 --- a/util/boot/grub/grub.cfg +++ /dev/null @@ -1,43 +0,0 @@ -insmod vbe -insmod vga -insmod video_bochs -insmod video_cirrus -set root='(hd0,msdos1)' - -menuentry 'Normal Boot' { - multiboot /boot/toaruos-kernel vid=preset,1024,768 root=/dev/hda0 - module /mod/zero.ko - module /mod/random.ko - module /mod/serial.ko - module /mod/procfs.ko - module /mod/tmpfs.ko - module /mod/ata.ko - module /mod/dospart.ko - module /mod/ext2.ko - module /mod/ps2kbd.ko - module /mod/ps2mouse.ko - module /mod/lfbvideo.ko - module /mod/packetfs.ko - set gfxpayload=1024x768x32 - boot -} - -menuentry 'Debug Mode' { - multiboot /boot/toaruos-kernel start=--vga root=/dev/hda0 - - module /mod/zero.ko - module /mod/random.ko - module /mod/serial.ko - module /mod/procfs.ko - module /mod/tmpfs.ko - module /mod/ata.ko - module /mod/dospart.ko - module /mod/ext2.ko - module /mod/ps2kbd.ko - module /mod/ps2mouse.ko - module /mod/debug_shell.ko - module /mod/packetfs.ko - - set gfxpayload=text - boot -} diff --git a/util/build-gcc.sh b/util/build-gcc.sh new file mode 100644 index 00000000..e8253796 --- /dev/null +++ b/util/build-gcc.sh @@ -0,0 +1,61 @@ +#!/bin/bash +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +$DIR/check-reqs.sh + +TARGET=i686-pc-toaru +PREFIX="$DIR/local" +TOARU_SYSROOT="$DIR/../base" + +cd "$DIR" + +mkdir -p tarballs + +pushd tarballs + if [ ! -e "binutils-2.27.tar.gz" ]; then + wget "http://ftp.gnu.org/gnu/binutils/binutils-2.27.tar.gz" + fi + if [ ! -e "gcc-6.4.0.tar.gz" ]; then + wget "http://www.netgull.com/gcc/releases/gcc-6.4.0/gcc-6.4.0.tar.gz" + fi + + if [ ! -d "binutils-2.27" ]; then + tar -xf "binutils-2.27.tar.gz" + pushd "binutils-2.27" + patch -p1 < $DIR/patches/binutils.patch > /dev/null + popd + fi + + if [ ! -d "gcc-6.4.0" ]; then + tar -xf "gcc-6.4.0.tar.gz" + pushd "gcc-6.4.0" + patch -p1 < $DIR/patches/gcc.patch > /dev/null + popd + fi +popd + +mkdir -p local +mkdir -p build +mkdir -p build/binutils +mkdir -p build/gcc + +pushd build + + unset PKG_CONFIG_LIBDIR # Just in case + + pushd binutils + $DIR/tarballs/binutils-2.27/configure --target=$TARGET --prefix=$PREFIX --with-sysroot=$TOARU_SYSROOT --disable-werror || exit 1 + make -j4 + make install + popd + + pushd gcc + $DIR/tarballs/gcc-6.4.0/configure --target=i686-pc-toaru --prefix=$PREFIX --with-sysroot=$TOARU_SYSROOT --disable-nls --enable-languages=c --disable-libssp --with-newlib || exit 1 + make all-gcc all-target-libgcc + make install-gcc install-target-libgcc + popd + +popd + + + diff --git a/util/build-travis.sh b/util/build-travis.sh deleted file mode 100755 index 81bdd4e1..00000000 --- a/util/build-travis.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -# Locale stuff -. /opt/build/base.sh - -# Build toolchain -. /opt/toaruos/toolchain/activate.sh - -# Print environment for reference -env - -# Print cross GCC version for reference -i686-pc-toaru-gcc --version - -# Cheating and copying /usr/python from toolchain -if [ -d hdd/usr/python ]; then - rm -r hdd/usr/python -fi -cp -r /opt/toaruos/hdd/usr/python hdd/usr/python - -pushd hdd/usr - if [ ! -d bin ]; then - mkdir bin - fi - - if [ ! -d lib ]; then - mkdir lib - fi - - pushd bin - - # Can never be too careful. - ln -s ../python/bin/python3.6 python3.6 - ln -s ../python/bin/python3.6 python3 - ln -s ../python/bin/python3.6 python - - popd - - pushd lib - - ln -s ../python/lib/libpython3.6m.so - - popd -popd - -# Build the CD -make cdrom - -# We're done! diff --git a/util/cache-toolchain.sh b/util/cache-toolchain.sh deleted file mode 100755 index 92cb7711..00000000 --- a/util/cache-toolchain.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo $TOOLCHAIN > .toolchain diff --git a/util/calc-size.sh b/util/calc-size.sh new file mode 100755 index 00000000..e7a7f8e3 --- /dev/null +++ b/util/calc-size.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +SPACE_REQ=$(du -sb "$DIR/../base" | cut -f 1) + +let "SIZE = ($SPACE_REQ / 3500)" +echo $SIZE + diff --git a/util/cdrom/boot/grub/grub.cfg b/util/cdrom/boot/grub/grub.cfg deleted file mode 100644 index 89c530f7..00000000 --- a/util/cdrom/boot/grub/grub.cfg +++ /dev/null @@ -1,107 +0,0 @@ -insmod vbe -insmod vga -insmod video_bochs -insmod video_cirrus -insmod iso9660 -insmod png - -#set root='(cd)' -set gfxmode=1024x768 -set t_driver=auto -set t_resolution=1024,768 -set g_resolution=1024x768 -set t_root="root=/dev/ram0,nocache" -set t_migrate="start=--migrate" -set t_start="_start" - -export gfxmode -export t_driver -export t_resolution -export g_resolution -export t_root -export t_migrate -export t_start - -set mod_deb_enabled="yes" -set mod_ata_enabled="yes" -set mod_vid_enabled="yes" -set mod_snd_enabled="yes" -set mod_net_enabled="yes" -set mod_ataold_enabled="no" -set mod_vmware_enabled="yes" -set mod_vbox_enabled="yes" - -export mod_deb_enabled -export mod_ata_enabled -export mod_vid_enabled -export mod_snd_enabled -export mod_net_enabled -export mod_ataold_enabled -export mod_vmware_enabled -export mod_vbox_enabled - -insmod gfxterm -terminal_output gfxterm - -loadfont /boot/grub/fonts/unicode.pf2 - -function set_theme { - set theme=/boot/grub/theme.txt -} - -function load_modules { - echo "Loading modules..." - module /mod/zero.ko - module /mod/random.ko - module /mod/serial.ko - if [ "${mod_deb_enabled}" = "yes" ]; then - module /mod/debug_shell.ko - fi - module /mod/procfs.ko - module /mod/tmpfs.ko - if [ "${mod_ata_enabled}" = "yes" ]; then - module /mod/ata.ko - fi - if [ "${mod_ataold_enabled}" = "yes" ]; then - module /mod/ataold.ko - fi - module /mod/ext2.ko - module /mod/iso9660.ko - module /mod/ps2kbd.ko - module /mod/ps2mouse.ko - if [ "${mod_vid_enabled}" = "yes" ]; then - module /mod/lfbvideo.ko - if [ "${mod_vbox_enabled}" = "yes" ]; then - module /mod/vboxguest.ko - fi - if [ "${mod_vmware_enabled}" = "yes" ]; then - module /mod/vmware.ko - fi - if [ "${mod_deb_enabled}" = "yes" ]; then - module /mod/vidset.ko - fi - fi - module /mod/packetfs.ko - if [ "${mod_snd_enabled}" = "yes" ]; then - module /mod/snd.ko - module /mod/ac97.ko - fi - if [ "${mod_net_enabled}" = "yes" ]; then - module /mod/net.ko - module /mod/pcnet.ko - module /mod/rtl.ko - module /mod/e1000.ko - fi -} - -function load_ramdisk { - echo "Loading ramdisk..." - module /ramdisk.img.gz -} - -function set_vidmode { - echo "Switching to video mode..." - set gfxpayload=${g_resolution}x32 -} - -configfile /boot/grub/menus.cfg diff --git a/util/cdrom/boot/grub/menus.cfg b/util/cdrom/boot/grub/menus.cfg deleted file mode 100644 index aed691d0..00000000 --- a/util/cdrom/boot/grub/menus.cfg +++ /dev/null @@ -1,103 +0,0 @@ -set_theme - -if [ ! "${seen_menu}" = "yes" ]; then - set timeout=5 - set seen_menu="yes" - export seen_menu -fi - -submenu 'Live CD' { - multiboot /kernel vid=${t_driver},${t_resolution} ${t_migrate} ${t_start}=live-welcome ${t_root} - load_modules - load_ramdisk - set_vidmode - boot -} -submenu 'Normal graphical boot - boots to a graphical login screen' { - multiboot /kernel vid=${t_driver},${t_resolution} ${t_migrate} ${t_root} - load_modules - load_ramdisk - set_vidmode - boot -} -submenu 'Graphical terminal - boots to a terminal with a traditional login prompt ' { - multiboot /kernel vid=${t_driver},${t_resolution} ${t_migrate} ${t_start}=--single ${t_root} - load_modules - load_ramdisk - set_vidmode - boot -} -submenu 'VGA text-mode console' { - multiboot /kernel logtoserial=1 ${t_migrate} ${t_start}=--vga ${t_root} - load_modules - load_ramdisk - set gfxpayload=text - boot -} -submenu '> Advanced graphics configuration options...' { - set_theme - menuentry '800x600' { - set t_resolution=800,600 - set g_resolution=800x600 - export t_resolution - export g_resolution - configfile /boot/grub/menus.cfg - } - menuentry '1024x768 (default)' { - set t_resolution=1024,768 - set g_resolution=1024x768 - export t_resolution - export g_resolution - configfile /boot/grub/menus.cfg - } - menuentry '1280x720' { - set t_resolution=1280,720 - set g_resolution=1280x720 - export t_resolution - export g_resolution - configfile /boot/grub/menus.cfg - } - menuentry '1920x1080' { - set t_resolution=1920,1080 - set g_resolution=1920x1080 - export t_resolution - export g_resolution - configfile /boot/grub/menus.cfg - } - menuentry 'Custom...' { - echo -n "Width: " - read _w - echo - echo -n "Height: " - read _h - set t_resolution=${_w},${_h} - set g_resolution=${_w}x${_h} - export t_resolution - export g_resolution - configfile /boot/grub/menus.cfg - } - menuentry 'Automatically detect video adapter (Default)' { - set t_driver=auto - export t_driver - configfile /boot/grub/menus.cfg - } - menuentry 'Use QEMU/Bochs/VirtualBox Driver' { - set t_driver=qemu - export t_driver - configfile /boot/grub/menus.cfg - } - menuentry 'Use VMWare driver' { - set t_driver=vmware - export t_driver - configfile /boot/grub/menus.cfg - } - menuentry 'Use Preset LFB Driver' { - set t_driver=preset - export t_driver - configfile /boot/grub/menus.cfg - } -} - -submenu '> Configure optional modules...' { - configfile /boot/grub/modules.cfg -} diff --git a/util/cdrom/boot/grub/modules.cfg b/util/cdrom/boot/grub/modules.cfg deleted file mode 100644 index d4ae1e5c..00000000 --- a/util/cdrom/boot/grub/modules.cfg +++ /dev/null @@ -1,128 +0,0 @@ -set_theme - -submenu 'Back' { - configfile /boot/grub/menus.cfg -} - -if [ "${mod_deb_enabled}" = "yes" ]; then - submenu '[on] Debug modules' { - set mod_deb_enabled="no" - export mod_deb_enabled - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] debug modules' { - set mod_deb_enabled="yes" - export mod_deb_enabled - configfile /boot/grub/modules.cfg - } -fi -if [ "${mod_ata_enabled}" = "yes" ]; then - submenu '[on] ATA/ATAPI DMA module' { - set mod_ata_enabled="no" - export mod_ata_enabled - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] ATA/ATAPI DMA module' { - set mod_ata_enabled="yes" - export mod_ata_enabled - configfile /boot/grub/modules.cfg - } -fi -if [ "${mod_ataold_enabled}" = "yes" ]; then - submenu '[on] Legacy ATA module' { - set mod_ataold_enabled="no" - export mod_ataold_enabled - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] Legacy ATA module' { - set mod_ataold_enabled="yes" - export mod_ataold_enabled - configfile /boot/grub/modules.cfg - } -fi -if [ "${mod_vid_enabled}" = "yes" ]; then - submenu '[on] Video modules' { - set mod_vid_enabled="no" - export mod_vid_enabled - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] Video modules' { - set mod_vid_enabled="yes" - export mod_vid_enabled - configfile /boot/grub/modules.cfg - } -fi -if [ "${mod_snd_enabled}" = "yes" ]; then - submenu '[on] Sound modules (AC97, subsystem)' { - set mod_snd_enabled="no" - export mod_snd_enabled - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] Sound modules (AC97, subsystem)' { - set mod_snd_enabled="yes" - export mod_snd_enabled - configfile /boot/grub/modules.cfg - } -fi -if [ "${mod_net_enabled}" = "yes" ]; then - submenu '[on] Network modules (PCNet, RTL8139, subsystem)' { - set mod_net_enabled="no" - export mod_net_enabled - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] Network modules (PCNet, RTL8139, subsystem)' { - set mod_net_enabled="yes" - export mod_net_enabled - configfile /boot/grub/modules.cfg - } -fi -if [ "${mod_vmware_enabled}" = "yes" ]; then - submenu '[on] VMWare/QEMU absolute mouse' { - set mod_vmware_enabled="no" - export mod_vmware_enabled - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] VMWare/QEMU absolute mouse' { - set mod_vmware_enabled="yes" - export mod_vmware_enabled - configfile /boot/grub/modules.cfg - } -fi -if [ "${mod_vbox_enabled}" = "yes" ]; then - submenu '[on] VirtualBox guest extensions' { - set mod_vbox_enabled="no" - export mod_vbox_enabled - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] VirtualBox guest extensions' { - set mod_vbox_enabled="yes" - export mod_vbox_enabled - configfile /boot/grub/modules.cfg - } -fi - -if [ "${t_migrate}" = "start=--migrate" ]; then - submenu '[on] Migrate to in-RAM filesystem on boot' { - set t_migrate="" - set t_start="start" - export t_migrate - export t_start - configfile /boot/grub/modules.cfg - } -else - submenu '[ ] Migrate to in-RAM filesystem on boot' { - set t_migrate="start=--migrate" - set t_start="_start" - export t_migrate - export t_start - configfile /boot/grub/modules.cfg - } -fi diff --git a/util/cdrom/boot/grub/theme.txt b/util/cdrom/boot/grub/theme.txt deleted file mode 100644 index 5c20d8a7..00000000 --- a/util/cdrom/boot/grub/theme.txt +++ /dev/null @@ -1,61 +0,0 @@ -title-text: "ToaruOS Bootable CD" -title-color: "white" -message-color: "white" -message-bg-color: "black" -desktop-image: "/wallpaper.png" -desktop-color: "#000000" - -+ label { - text="Select a boot option or wait for the timeout." - width = 100% - top = 10% - align = center - color = #fff -} - -+ label { - top = 66% - width = 100% - align = center - color = #fff - text = "The default user is 'local' with password 'local'." -} -+ label { - top = 77% - width = 100% - align = center - color = #fff - text = "ToaruOS is free software, released under the NCSA/University of Illinois License" -} -+ label { - top = 80% - width = 100% - align = center - color = #fff - text = "http://toaruos.org | https://github.com/klange/toaruos" -} - -+ boot_menu { - left = 10% - width = 85% - height = 55% - top = 15% - item_color = "white" - selected_item_color = "#77b7ff" - item_height = 17 - item_padding = 10 - item_spacing = 6 -} - -+ progress_bar { - id = "__timeout__" - left = 15% - width = 70% - top = 90% - height = 12 - show_text = true - text_color = "255, 255, 255" - text = "@TIMEOUT_NOTIFICATION_LONG@" - fg_color = "119, 183, 255" -} - diff --git a/util/cdrom/wallpaper.png b/util/cdrom/wallpaper.png deleted file mode 100644 index 107b1857..00000000 Binary files a/util/cdrom/wallpaper.png and /dev/null differ diff --git a/util/check-reqs.sh b/util/check-reqs.sh new file mode 100755 index 00000000..428f032f --- /dev/null +++ b/util/check-reqs.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +RET=0 + +if ! which python3 >/dev/null; then + echo "python3 is required to run build tools - 3.6 is recommended as it is needed to cross-compile itself" + RET=1 +fi + +if ! which genext2fs >/dev/null; then + echo "genext2fs is needed to build ramdisk images" + RET=1 +else + if [ -z "$(genext2fs --help 2>&1 | grep -- "block-size")" ]; then + echo "genext2fs must support the -B (--block-size) argument; try building with Debian patches" + RET=1 + fi +fi + +if ! which mkfs.fat >/dev/null; then + echo "mkfs.fat is required (and should be in your PATH) to build EFI file systems" + RET=1 +fi + +if ! which mcopy >/dev/null; then + echo "mtools is required to build FAT images for EFI / hybrid ISOs" + RET=1 +fi + +if ! which xorriso >/dev/null; then + echo "xorriso is required to build ISO CD images" + RET=1 +fi + +if ! which yasm >/dev/null; then + echo "yasm is required to build some assembly sources" + RET=1 +fi + +if ! which autoconf >/dev/null; then + echo "autoconf is required to build GCC cross-compiler" + RET=1 +fi + +if ! which automake >/dev/null; then + echo "automake is required to build GCC cross-compiler" + RET=1 +fi + +if ! which wget >/dev/null; then + echo "wget is required to build GCC cross-compiler" + RET=1 +fi + +if [ ! -e /usr/lib32/crt0-efi-ia32.o ]; then + echo "gnu-efi is required to build EFI loaders" + RET=1 +fi + +if ! cpp <(echo "#include \"gmp.h\"") >/dev/null 2>/dev/null; then + echo "GMP headers are required to build GCC cross-compiler" + RET=1 +fi + +if ! cpp <(echo "#include \"mpfr.h\"") >/dev/null 2>/dev/null; then + echo "MPFR headers are required to build GCC cross-compiler" + RET=1 +fi + +if ! cpp <(echo "#include \"mpfr.h\"") >/dev/null 2>/dev/null; then + echo "MPFR headers are required to build GCC cross-compiler" + RET=1 +fi + +if ! cpp <(echo "#include \"mpc.h\"") >/dev/null 2>/dev/null; then + echo "MPC headers are required to build GCC cross-compiler" + RET=1 +fi + +exit $RET + diff --git a/util/check.sh b/util/check.sh new file mode 100755 index 00000000..d50a729d --- /dev/null +++ b/util/check.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +if [ ! -e "$DIR/local/bin/i686-pc-toaru-gcc" ]; then + echo -n "n"; + exit 1; +else + echo -n "y"; + exit 0; +fi diff --git a/util/cpad.sh b/util/cpad.sh deleted file mode 100755 index 93888a37..00000000 --- a/util/cpad.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -function cpad { - word="$1" - while [ ${#word} -lt $2 ]; do - word="$word$3"; - if [ ${#word} -lt $2 ]; then - word="$3$word" - fi; - done; - echo "$word"; -} - diff --git a/util/create-image.sh b/util/create-image.sh deleted file mode 100755 index 7d0db61a..00000000 --- a/util/create-image.sh +++ /dev/null @@ -1,95 +0,0 @@ -#!/bin/bash - -if [[ $EUID -ne 0 ]]; then - echo -e "\033[1;31mYou're going to need to run this as root\033[0m" 1>&2 - echo "Additionally, verify that /dev/loop4 is available and that" 1>&2 - echo "/mnt is available for mounting; otherwise, modify the script" 1>&2 - echo "to use alternative loop devices or mount points as needed." 1>&2 - exit 1 -fi - -if [[ $# -lt 1 ]]; then - echo "I need a path to a compiled とあるOS source directory as an argument, try again." 1>&2 - exit 1 -fi - -DISK=toaru-disk.img -SRCDIR=$1 -BOOT=./boot -SIZE=1G - -echo "Please select a disk size." -read -p "l for 1GB, s for 256MB: " -if [ "$REPLY" == "small" ] ; then - SIZE=256M -fi - -echo "I will create partitioned, ext2 disk image of size $SIZE x 4KB at $DISK from files in $SRCDIR as well as boot scripts in $BOOT" -read -p "Is this correct? (Y/n)" -if [ "$REPLY" == "n" ] ; then - echo "Oh, okay, never mind then." - exit -fi - -type kpartx >/dev/null 2>&1 || { echo "Trying to install kpartx..."; apt-get install kpartx; } - -# Create a 1GiB blank disk image. -dd if=/dev/zero of=$DISK bs=$SIZE count=1 - -echo "Partitioning..." - -cat parted.conf | parted $DISK - -echo "Done partition." - - -# Here's where we need to be root. -LOOPRAW=`losetup -f` -losetup $LOOPRAW $DISK -TMP=`kpartx -av $DISK` -TMP2=${TMP/add map /} -LOOP=${TMP2%%p1 *} -LOOPDEV=/dev/${LOOP} -LOOPMAP=/dev/mapper/${LOOP}p1 - -if [ ! -e $LOOPDEV ] ; then - echo "Bailing! $LOOPDEV is not valid" - exit -fi - -if [ ! -e $LOOPMAP ] ; then - echo "Bailing! $LOOPMAP is not valid" - exit -fi - -mkfs.ext2 ${LOOPMAP} - -mount ${LOOPMAP} /mnt - -echo "Installing main files." -cp -r $SRCDIR/hdd/* /mnt/ - -echo "Installing boot files." -mkdir -p /mnt/boot -cp -r $BOOT/* /mnt/boot/ - -echo "Installing kernel." -cp -r $SRCDIR/toaruos-kernel /mnt/boot/ - -echo "Installing grub." -grub-install --target=i386-pc --boot-directory=/mnt/boot $LOOPRAW - -echo "Cleaning up" -umount /mnt -kpartx -d ${LOOPMAP} -dmsetup remove ${LOOPMAP} -losetup -d ${LOOPDEV} -losetup -d ${LOOPRAW} - -if [ -n "$SUDO_USER" ] ; then - echo "Reassigning permissions on disk image to $SUDO_USER" - chown $SUDO_USER:$SUDO_USER $DISK -fi - - -echo "Done. You can boot the disk image with qemu now." diff --git a/util/detect-make-all.sh b/util/detect-make-all.sh deleted file mode 100755 index b99a3890..00000000 --- a/util/detect-make-all.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -if [ -f toaruos.iso ]; then - echo "cdrom tags" -else - echo "system tags userspace" -fi diff --git a/util/devtable b/util/devtable deleted file mode 100644 index 2183f969..00000000 --- a/util/devtable +++ /dev/null @@ -1,6 +0,0 @@ -/bin/sudo f 4555 0 0 - - - - - -/bin/gsudo f 4555 0 0 - - - - - -/home/local d 775 1000 1000 - - - - - -/home/local/.desktop.conf f 664 1000 1000 - - - - - -/home/local/.menu.desktop f 664 1000 1000 - - - - - -/home/local/.weather.json f 664 1000 1000 - - - - - diff --git a/util/disk_size.sh b/util/disk_size.sh deleted file mode 100755 index 65eb8074..00000000 --- a/util/disk_size.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -f "$DIR/../.disk_size" ]; then - cat "$DIR/../.disk_size" -else - echo "131072" -fi diff --git a/util/downsample-icons.sh b/util/downsample-icons.sh deleted file mode 100755 index a48d152f..00000000 --- a/util/downsample-icons.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -pushd hdd/usr/share/icons/48 - for i in *.png; do - echo "Downsampling $i..." - convert "$i" -filter box -resize 24x24 -define png:color-type=6 ../24/$i - done -popd diff --git a/util/dump-colors.py b/util/dump-colors.py deleted file mode 100755 index ce7a0adb..00000000 --- a/util/dump-colors.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python3 - -for i in range(256): - print(str(i) + "\t\x1b[48;5;" + str(i) + "m \x1b[0m") diff --git a/hdd/usr/share/help/0_index.trt b/util/extra-help/0_index.trt similarity index 100% rename from hdd/usr/share/help/0_index.trt rename to util/extra-help/0_index.trt diff --git a/hdd/usr/share/help/calculator.trt b/util/extra-help/calculator.trt similarity index 100% rename from hdd/usr/share/help/calculator.trt rename to util/extra-help/calculator.trt diff --git a/hdd/usr/share/help/file_browser.trt b/util/extra-help/file_browser.trt similarity index 100% rename from hdd/usr/share/help/file_browser.trt rename to util/extra-help/file_browser.trt diff --git a/hdd/usr/share/help/help_browser.trt b/util/extra-help/help_browser.trt similarity index 100% rename from hdd/usr/share/help/help_browser.trt rename to util/extra-help/help_browser.trt diff --git a/hdd/usr/share/help/licenses/0_toaruos.trt b/util/extra-help/licenses/0_toaruos.trt similarity index 95% rename from hdd/usr/share/help/licenses/0_toaruos.trt rename to util/extra-help/licenses/0_toaruos.trt index 8dbeea8a..6122a40f 100644 --- a/hdd/usr/share/help/licenses/0_toaruos.trt +++ b/util/extra-help/licenses/0_toaruos.trt @@ -1,7 +1,7 @@

ToaruOS

-Copyright (c) 2011-2017 Kevin Lange. All rights reserved. +Copyright (c) 2011-2018 K. Lange. All rights reserved. Dedicated to the memory of Dennis Ritchie @@ -21,7 +21,7 @@ furnished to do so, subject to the following conditions: 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. - 3. Neither the names of the ToAruOS Kernel Development Team, Kevin Lange, + 3. Neither the names of the ToAruOS Kernel Development Team, K. Lange, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. @@ -36,7 +36,7 @@ WITH THE SOFTWARE.

Authors

-- Kevin Lange +- K. Lange - Markus Schober - Tianyi Wang - Josh Kilmer diff --git a/hdd/usr/share/help/licenses/cairo.trt b/util/extra-help/licenses/cairo.trt similarity index 100% rename from hdd/usr/share/help/licenses/cairo.trt rename to util/extra-help/licenses/cairo.trt diff --git a/hdd/usr/share/help/licenses/font_dejavu.trt b/util/extra-help/licenses/font_dejavu.trt similarity index 100% rename from hdd/usr/share/help/licenses/font_dejavu.trt rename to util/extra-help/licenses/font_dejavu.trt diff --git a/hdd/usr/share/help/licenses/font_symbola.trt b/util/extra-help/licenses/font_symbola.trt similarity index 100% rename from hdd/usr/share/help/licenses/font_symbola.trt rename to util/extra-help/licenses/font_symbola.trt diff --git a/hdd/usr/share/help/licenses/font_vlgothic.trt b/util/extra-help/licenses/font_vlgothic.trt similarity index 100% rename from hdd/usr/share/help/licenses/font_vlgothic.trt rename to util/extra-help/licenses/font_vlgothic.trt diff --git a/hdd/usr/share/help/licenses/freetype.trt b/util/extra-help/licenses/freetype.trt similarity index 100% rename from hdd/usr/share/help/licenses/freetype.trt rename to util/extra-help/licenses/freetype.trt diff --git a/hdd/usr/share/help/licenses/lgpl-2.1.trt b/util/extra-help/licenses/lgpl-2.1.trt similarity index 100% rename from hdd/usr/share/help/licenses/lgpl-2.1.trt rename to util/extra-help/licenses/lgpl-2.1.trt diff --git a/hdd/usr/share/help/licenses/lgpl-3.0.trt b/util/extra-help/licenses/lgpl-3.0.trt similarity index 100% rename from hdd/usr/share/help/licenses/lgpl-3.0.trt rename to util/extra-help/licenses/lgpl-3.0.trt diff --git a/hdd/usr/share/help/licenses/pycairo.trt b/util/extra-help/licenses/pycairo.trt similarity index 100% rename from hdd/usr/share/help/licenses/pycairo.trt rename to util/extra-help/licenses/pycairo.trt diff --git a/hdd/usr/share/help/licenses/python.trt b/util/extra-help/licenses/python.trt similarity index 100% rename from hdd/usr/share/help/licenses/python.trt rename to util/extra-help/licenses/python.trt diff --git a/hdd/usr/share/help/mines.trt b/util/extra-help/mines.trt similarity index 100% rename from hdd/usr/share/help/mines.trt rename to util/extra-help/mines.trt diff --git a/hdd/usr/share/help/packages.trt b/util/extra-help/packages.trt similarity index 100% rename from hdd/usr/share/help/packages.trt rename to util/extra-help/packages.trt diff --git a/hdd/usr/share/help/painting.trt b/util/extra-help/painting.trt similarity index 100% rename from hdd/usr/share/help/painting.trt rename to util/extra-help/painting.trt diff --git a/util/fdisk.conf b/util/fdisk.conf deleted file mode 100644 index 3b6715f3..00000000 --- a/util/fdisk.conf +++ /dev/null @@ -1,12 +0,0 @@ -o -n -p -1 - - -a -1 -w -q - - diff --git a/util/fix-python.sh b/util/fix-python.sh new file mode 100755 index 00000000..ac22257c --- /dev/null +++ b/util/fix-python.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# needed for strip +source util/activate.sh + +HDD_PATH=base + +pushd $HDD_PATH/usr/python/lib || exit 1 + + echo "Stripping shared library..." + chmod +w libpython3.6m.so + i686-pc-toaru-strip libpython3.6m.so + chmod -w libpython3.6m.so + + echo "Killing __pycache__ directories..." + find . -name __pycache__ -exec rm -r "{}" \; + + # Let's kill some other shit while we're in here + pushd python3.6 || exit 1 + echo "Cleaning up unused modules..." + rm -r test distutils tkinter multiprocessing ensurepip config-3.6m/libpython3.6m.a + popd + +popd + +pushd $HDD_PATH/usr + if [ ! -d bin ]; then + mkdir bin + fi + + pushd bin + + # Can never be too careful. + ln -s ../python/bin/python3.6 python3.6 + ln -s ../python/bin/python3.6 python3 + ln -s ../python/bin/python3.6 python + + popd + + pushd lib + + ln -s ../python/lib/libpython3.6m.so + + popd + +popd + +echo "Installing readline hook..." +cp util/readline._py $HDD_PATH/usr/python/lib/python3.6/ + +echo "Installing demos..." +mkdir -p base/usr/share/python-demos +cp util/python-demos/*.py base/usr/share/python-demos/ + +echo "Installing Help Browser files..." +mkdir -p base/usr/share/help +mkdir -p base/usr/share/help/licenses +cp util/extra-help/*.trt base/usr/share/help/ +cp util/extra-help/licenses/*.trt base/usr/share/help/licenses/ diff --git a/util/generate-vga-palette.c b/util/generate-vga-palette.c deleted file mode 100644 index 9dd38006..00000000 --- a/util/generate-vga-palette.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include - -#include "../userspace/gui/terminal/terminal-palette.h" - -static int abs(int a) { - return a > 0 ? a : -a; -} - -static int color_distance(uint32_t a, uint32_t b) { - int a_r = (a & 0xFF0000) >> 16; - int a_g = (a & 0xFF00) >> 8; - int a_b = (a & 0xFF); - - int b_r = (b & 0xFF0000) >> 16; - int b_g = (b & 0xFF00) >> 8; - int b_b = (b & 0xFF); - - int distance = 0; - distance += abs(a_r - b_r) * 3; - distance += abs(a_g - b_g) * 6; - distance += abs(a_b - b_b) * 10; - - return distance; -} - -static uint32_t vga_base_colors[] = { - 0x000000, - 0xAA0000, - 0x00AA00, - 0xAA5500, - 0x0000AA, - 0xAA00AA, - 0x00AAAA, - 0xAAAAAA, - 0x555555, - 0xFF5555, - 0x55AA55, - 0xFFFF55, - 0x5555FF, - 0xFF55FF, - 0x55FFFF, - 0xFFFFFF, -}; - -static int is_gray(uint32_t a) { - int a_r = (a & 0xFF0000) >> 16; - int a_g = (a & 0xFF00) >> 8; - int a_b = (a & 0xFF); - - return (a_r == a_g && a_g == a_b); -} - -int main(int argc, char * argv[]) { - printf("#define PALETTE_COLORS 256\n"); - printf("uint32_t vga_colors[PALETTE_COLORS] = {\n"); - for (int i = 0; i < 16; ++i) { - printf("\t0x%x,\n", i); - } - for (int i = 16; i < 256; ++i) { - int best_distance = INT32_MAX; - int best_index = 0; - for (int j = 0; j < 16; ++j) { - if (is_gray(term_colors[i]) && !is_gray(vga_base_colors[j])); - int distance = color_distance(term_colors[i], vga_base_colors[j]); - if (distance < best_distance) { - best_index = j; - best_distance = distance; - } - } - printf("\t0x%x, /* #%06x -> #%06x */\n", best_index, term_colors[i], vga_base_colors[best_index]); - } - printf("};\n"); - return 0; -} - diff --git a/util/helpful-toolchain-error.sh b/util/helpful-toolchain-error.sh deleted file mode 100755 index 643e4289..00000000 --- a/util/helpful-toolchain-error.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -if [ -d toolchain/local/bin ]; then - echo 'You have not activated your toolchain (. toolchain/activate.sh)' -elif [ -e .toolchain ]; then - echo "You have not activated your toolchain (. `cat .toolchain | sed 's%hdd/usr%toolchain/activate.sh%'`)" -else - echo 'No toolchain found. Did you mean to run `make toolchain` or source an existing toolchain?' -fi diff --git a/util/install-efi.sh b/util/install-efi.sh new file mode 100755 index 00000000..35115e8d --- /dev/null +++ b/util/install-efi.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +cp fatbase/efi/boot/bootx64.efi /boot/efi/EFI/toaru/toarux64.efi +cp fatbase/{ramdisk.img,kernel} /boot/efi/ +mkdir -p /boot/efi/mod +cp fatbase/mod/* /boot/efi/mod/ diff --git a/util/license-tool.sh b/util/license-tool.sh deleted file mode 100755 index bce9ca54..00000000 --- a/util/license-tool.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -for f in $(find kernel userspace modules | fgrep '.c'); do - echo -n "Looking at '$f'... " - - if ! grep -q "Copyright" $f; then - echo "needs headers... " - - authors=$(mktemp) - - echo "/* This file is part of ToaruOS and is released under the terms" >> $authors - echo " * of the NCSA / University of Illinois License - see LICENSE.md" >> $authors - - last_user="X" - last_sdate="X" - last_edate="X" - while read -r line; do - auth_user=$(echo "$line" | cut -d" " -f1) - auth_date=$(echo "$line" | cut -d" " -f2) - - if [ "$last_user" != "$auth_user" ]; then - if [ "$last_user" != "X" ]; then - if [ "$last_edate" == $last_sdate ]; then - echo " * Copyright (C) $last_sdate $last_user" >> $authors - else - echo " * Copyright (C) $last_sdate-$last_edate $last_user" >> $authors - fi - fi - last_sdate=$auth_date - last_user=$auth_user - fi - - last_edate=$auth_date - last_user=$auth_user - done < <(git log --date=short --pretty=format:"%an %ad" "$f" | sed 's/-..-..//' | sort | uniq; echo "-") - - echo " */" >> $authors - - tmpfile=$(mktemp) - cat "$authors" "$f" > "$tmpfile" - mv "$tmpfile" "$f" - - rm $authors - else - echo "-- already has license headers" - fi -done diff --git a/util/lm.c b/util/lm.c new file mode 100644 index 00000000..a131395d --- /dev/null +++ b/util/lm.c @@ -0,0 +1,3 @@ +int __libm_dummy(void) { + return 42; +} diff --git a/util/make-grub-wallpaper.sh b/util/make-grub-wallpaper.sh deleted file mode 100755 index 2b599427..00000000 --- a/util/make-grub-wallpaper.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -# Make a wallpaper for grub from the input. - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -convert $1 \ - -resize 1024x768^ \ - -gravity center \ - -extent 1024x768 \ - -level 0,200% \ - ${DIR}/cdrom/wallpaper.png diff --git a/util/mergecomments.sh b/util/mergecomments.sh deleted file mode 100755 index 83059e56..00000000 --- a/util/mergecomments.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -for f in $(find kernel modules | fgrep '.c'); do - echo -n "Looking at '$f'... " - - outfile=$(mktemp) - sed -e 'N;s#\*/\n*/\*# *#g;P;D' $f > $outfile - mv $outfile $f - - echo "done" -done diff --git a/util/mk-beg b/util/mk-beg deleted file mode 100755 index 96b97d32..00000000 --- a/util/mk-beg +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -. "$DIR/cpad.sh" - -echo -n > /tmp/.`whoami`-build-errors - -CMD=`cpad "$1" 8 " "` -echo -e -n "\033[32m${CMD}${2}\033[0m" diff --git a/util/mk-beg-rm b/util/mk-beg-rm deleted file mode 100755 index ce289d94..00000000 --- a/util/mk-beg-rm +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -. "$DIR/cpad.sh" - -echo -n > /tmp/.`whoami`-build-errors - -CMD=`cpad "$1" 8 " "` -echo -e -n "\033[31m${CMD}${2}\033[0m" diff --git a/util/mk-end b/util/mk-end deleted file mode 100755 index 861b14b5..00000000 --- a/util/mk-end +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -. "$DIR/cpad.sh" - -CMD=`cpad "$1" 8 " "` -if [[ -s /tmp/.`whoami`-build-errors ]] ; then - echo -e -n "\r\033[1;33m${CMD}${2}\033[0m\033[K\n" - cat /tmp/.`whoami`-build-errors -else - echo -e -n "\r\033[1;32m${CMD}${2}\033[0m\033[K\n" -fi diff --git a/util/mk-end-rm b/util/mk-end-rm deleted file mode 100755 index 0f1fa8a4..00000000 --- a/util/mk-end-rm +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -. "$DIR/cpad.sh" - -CMD=`cpad "$1" 8 " "` -echo -e -n "\r\033[1;31m${CMD}${2}\033[0m\033[K\n" diff --git a/util/mk-error b/util/mk-error deleted file mode 100755 index 76fcc5da..00000000 --- a/util/mk-error +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -echo -e "\033[1;31m! Fatal error encountered.\033[0m" -cat /tmp/.`whoami`-build-errors - -exit 1 diff --git a/util/mk-info b/util/mk-info deleted file mode 100755 index 639face9..00000000 --- a/util/mk-info +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -. "$DIR/cpad.sh" - - -CMD=`cpad "$1" 8 " "` -echo -e -n "\r\033[1;34m${CMD}${2}\033[0m\n" diff --git a/util/mkdisk.sh b/util/mkdisk.sh new file mode 100755 index 00000000..56cda9ab --- /dev/null +++ b/util/mkdisk.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +OUT=$1 +IN=$2 + +OUTDIR=`dirname $1` + +if [ -e "$DIR/../base/usr/share/fonts" ]; then + SIZE=128 +else + SIZE=64 +fi + +rm -f $OUT +mkdir -p cdrom +fallocate -l ${SIZE}M $OUT || dd if=/dev/zero bs=1M count=${SIZE} of=$OUT +mkfs.fat -s 1 -S 2048 $OUT + +#echo "Turning $IN into $OUT" + +for i in $(find $IN) +do + if [[ $i == $IN ]]; then + continue + fi + OUT_FILE=`echo $i | sed s"/^$IN/$OUTDIR/"` + IN_FILE=`echo $i | sed s"/^$IN//"` + #echo $IN_FILE $OUT_FILE + if [ -d "$i" ]; then + mmd -i $OUT $IN_FILE + mkdir -p $OUT_FILE + else + mcopy -i $OUT $i '::'$IN_FILE + touch $OUT_FILE + fi +done + +rm -f cdrom/efi/boot/bootia32.efi # Otherwise virtualbox may erroneously try to load from this +rm -f cdrom/efi/boot/bootx64.efi # Same + diff --git a/util/mod_deps.py b/util/mod_deps.py deleted file mode 100755 index 681ea0d0..00000000 --- a/util/mod_deps.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python3 -# coding: utf-8 -""" -Extract dependencies from kernel modules. -""" - -import os -import sys -import subprocess - -if os.uname().sysname == "toaru": - prefix = "" - link_ld = '/tmp/link.ld' - mod_dir = '/mod' - o_file = '/tmp/test' -else: - prefix = "i686-elf-" - link_ld = 'kernel/link.ld' - mod_dir = 'hdd/mod' - o_file = '/dev/null' - - -def processModule(path): - p = subprocess.Popen([prefix+"nm",path,"-p"], stdout=subprocess.PIPE,bufsize=1) - symbols, _ = p.communicate() - symbols = symbols.decode('utf-8') - name = [ x[2].replace("module_info_","") for x in [x.strip().split(" ") for x in symbols.split("\n") if len(x.strip().split(" ")) > 2] if x[1] == "D" and x[2].startswith("module_info_") ][0] - dependencies = [ x[2].replace("_mod_dependency_","") for x in [x.strip().split(" ") for x in symbols.split("\n") if len(x.strip().split(" ")) > 2] if x[1] == "d" and x[2].startswith("_mod_dependency_") ] - return path, name, dependencies - -modules = {} -files = {} - -# Read the symbols from the file. -for module in os.listdir(mod_dir): - if module.endswith(".ko"): - path,name,deps = processModule(mod_dir + "/" + module) - modules[name] = (path,deps) - files[path] = name - -# Okay, now let's spit out the dependencies for our module. -if len(sys.argv) < 2: - print("Expected a path to a module (from the root of the build tree), eg. %s/test.ko" % mod_dir, file=sys.stderr) - sys.exit(1) - -me = sys.argv[-1] -name = files[me] -deps = modules[name][1] - -def calculate(depends, new): - for k in new: - if not k in depends: - depends.append(k) - _, other = modules[k] - depends = calculate(depends, other) - return depends - -depends = calculate([], deps) - -satisfied = [] -a = depends[:] - -while set(satisfied) != set(depends): - b = [] - for k in a: - if all([x in satisfied for x in modules[k][1]]): - satisfied.append(k) - else: - b.append(k) - a = b[:] - -if len(sys.argv) > 2: - for i in sys.argv[1:-1]: - if i == '--print-deps': - print(name, "→", " ".join(["\033[31m{mod}\033[m".format(mod=x) if not x in deps else x for x in satisfied])) - - if i == '--print-files': - for i in satisfied: - print(modules[i][0], "(dep-of-dep)" if i not in deps else "") - - -if os.path.exists(link_ld) and os.path.exists('toaruos-kernel'): - p = subprocess.Popen([prefix+"ld","-T",link_ld,"-o",o_file,"toaruos-kernel",]+[modules[x][0] for x in satisfied]+[me]) - sys.exit(p.wait()) - - diff --git a/util/netinit.c b/util/netinit.c new file mode 100644 index 00000000..cd3c1987 --- /dev/null +++ b/util/netinit.c @@ -0,0 +1,717 @@ +/* vim: ts=4 sw=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015-2017 K. Lange + * + * netinit + * + * Download, decompress, and mount a root filesystem from the + * network and run the `/bin/init` contained therein. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NETBOOT_URL "http://10.0.2.1:8080/netboot.img" + +#include +#include +#include "../lib/list.c" +#include "../lib/hashmap.c" +#include "terminal-font.h" + +extern int mount(char* src,char* tgt,char* typ,unsigned long,void*); + +#define SIZE 512 + +struct http_req { + char domain[SIZE]; + char path[SIZE]; + int port; + int ssl; +}; + +struct { + int show_headers; + const char * output_file; + const char * cookie; + FILE * out; +} fetch_options = {0}; + +#define TRACE(msg,...) do { \ + char tmp[512]; \ + sprintf(tmp, msg, ##__VA_ARGS__); \ + fprintf(stderr, "%s", tmp); \ + fflush(stderr); \ + print_string(tmp); \ +} while(0) + +static int has_video = 1; +static int width, height, depth; +static char * framebuffer; +static struct timeval start; +static int framebuffer_fd; + +#define char_height 20 +#define char_width 9 + +#define BG_COLOR 0xFF050505 +#define FG_COLOR 0xFFCCCCCC +#define EX_COLOR 0xFF999999 + +static void set_point(int x, int y, uint32_t value) { + uint32_t * disp = (uint32_t *)framebuffer; + uint32_t * cell = &disp[y * width + x]; + *cell = value; +} + +static void write_char(int x, int y, int val, uint32_t color) { + if (val > 128) { + val = 4; + } +#ifdef number_font + uint8_t * c = number_font[val]; + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + if (c[i] & (1 << (8-j))) { + set_point(x+j,y+i,color); + } else { + set_point(x+j,y+i,BG_COLOR); + } + } + } +#else + uint16_t * c = large_font[val]; + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + if (c[i] & (1 << (15-j))) { + set_point(x+j,y+i,color); + } else { + set_point(x+j,y+i,BG_COLOR); + } + } + } + +#endif +} + +#define BUF_SIZE 255 +static void read_http_line(char * buf, FILE * f) { + memset(buf, 0x00, BUF_SIZE); + + fgets(buf, BUF_SIZE, f); + char * _r = strchr(buf, '\r'); + if (_r) { + *_r = '\0'; + } + if (!_r) { + _r = strchr(buf, '\n'); /* that's not right, but, whatever */ + if (_r) { + *_r = '\0'; + } + } +} + +static unsigned short * textmemptr = (unsigned short *)0xB8000; +static void placech(unsigned char c, int x, int y, int attr) { + unsigned short *where; + unsigned att = attr << 8; + where = textmemptr + (y * 80 + x); + *where = c | att; +} + + +#define LEFT_PAD 40 +static int x = LEFT_PAD; +static int y = 0; +static int vx = 0; +static int vy = 0; +static void print_string(char * msg) { + if (!has_video) { + while (*msg) { + placech(' ',vx,vy,0); + switch (*msg) { + case '\n': + vx = 0; + vy += 1; + if (vy == 25) { + /* scroll */ + memcpy(textmemptr,textmemptr + 80,sizeof(unsigned short) * 80 * 24); + memset(textmemptr + 80 * 24, 0, sizeof(unsigned short) * 80); + vy = 24; + } + break; + case '\033': + msg++; + if (*msg == '[') { + msg++; + if (*msg == 'G') { + vx = 0; + } + if (*msg == 'K') { + int last_x = vx; + while (vx < 80) { + placech(' ',vx,vy,0); + vx++; + } + vx = last_x; + } + } + break; + default: + placech(*msg,vx,vy,0xF); + vx++; + break; + } + placech('_',vx,vy,0xF); + msg++; + } + } else { + while (*msg) { + write_char(x,y,' ',BG_COLOR); + switch (*msg) { + case '\n': + x = LEFT_PAD; + y += char_height; + if (y > height - 30) { + y = 0; + } + break; + case '\033': + msg++; + if (*msg == '[') { + msg++; + if (*msg == 'G') { + x = LEFT_PAD; + } + if (*msg == 'K') { + int last_x = x; + while (x < width) { + write_char(x,y,' ',FG_COLOR); + x += char_width; + } + x = last_x; + } + } + break; + default: + write_char(x,y,*msg,FG_COLOR); + x += char_width; + break; + } + write_char(x,y,'_',EX_COLOR); + msg++; + } + } +} + +void parse_url(char * d, struct http_req * r) { + if (strstr(d, "http://") == d) { + + d += strlen("http://"); + + char * s = strstr(d, "/"); + if (!s) { + strcpy(r->domain, d); + strcpy(r->path, ""); + } else { + *s = 0; + s++; + strcpy(r->domain, d); + strcpy(r->path, s); + } + if (strstr(r->domain,":")) { + char * port = strstr(r->domain,":"); + *port = '\0'; + port++; + r->port = atoi(port); + } else { + r->port = 80; + } + r->ssl = 0; + } else if (strstr(d, "https://") == d) { + + d += strlen("https://"); + + char * s = strstr(d, "/"); + if (!s) { + strcpy(r->domain, d); + strcpy(r->path, ""); + } else { + *s = 0; + s++; + strcpy(r->domain, d); + strcpy(r->path, s); + } + if (strstr(r->domain,":")) { + char * port = strstr(r->domain,":"); + *port = '\0'; + port++; + r->port = atoi(port); + } else { + r->port = 443; + } + r->ssl = 1; + } else { + TRACE("sorry, can't parse %s\n", d); + exit(1); + } +} + + +static void bad_response(void) { + TRACE("Bad response.\n"); + exit(1); +} + +static char * img = "/tmp/netboot.img"; + +static void update_video(int sig) { + (void)sig; + ioctl(framebuffer_fd, IO_VID_WIDTH, &width); + ioctl(framebuffer_fd, IO_VID_HEIGHT, &height); + ioctl(framebuffer_fd, IO_VID_DEPTH, &depth); + ioctl(framebuffer_fd, IO_VID_ADDR, &framebuffer); + ioctl(framebuffer_fd, IO_VID_SIGNAL, NULL); + /* Clear the screen */ + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + set_point(x,y,BG_COLOR); + } + } + x = LEFT_PAD; + y = 0; + + if (sig) { + TRACE("(video display changed to %d x %d)\n", width, height); + } +} + +static volatile int watchdog_success = 0; + +static void network_error(int is_thread) { + TRACE("\n\n"); + TRACE("ERROR: Network does not seem to be available, or unable to reach host.\n"); + TRACE(" Please check your VM configuration.\n"); + if (is_thread) { + pthread_exit(0); + } else { + exit(1); + } +} + +static void * watchdog_func(void * garbage) { + (void)garbage; + + int i = 0; + + while (i < 5) { + usleep(1000000); + if (watchdog_success) { + pthread_exit(0); + } + i++; + } + + network_error(1); + return NULL; +} + +#define BAR_WIDTH 20 +#define bar_perc "||||||||||||||||||||" +#define bar_spac " " +static void draw_progress(size_t content_length, size_t size) { + struct timeval now; + gettimeofday(&now, NULL); + + TRACE("\033[G%6dkB",(int)size/1024); + if (content_length) { + int percent = (size * BAR_WIDTH) / (content_length); + TRACE(" / %6dkB [%.*s%.*s]", (int)content_length/1024, percent,bar_perc,BAR_WIDTH-percent,bar_spac); + } + double timediff = (double)(now.tv_sec - start.tv_sec) + (double)(now.tv_usec - start.tv_usec)/1000000.0; + if (timediff > 0.0) { + double rate = (double)(size) / timediff; + double s = rate/(1024.0) * 8.0; + if (s > 1024.0) { + TRACE(" %.2f mbps", s/1024.0); + } else { + TRACE(" %.2f kbps", s); + } + + if (content_length) { + if (rate > 0.0) { + double remaining = (double)(content_length - size) / rate; + + TRACE(" (%.2f sec remaining)", remaining); + } + } + } + TRACE("\033[K"); +} + +static uint32_t crctab[256] = { + 0x00000000, 0x09073096, 0x120e612c, 0x1b0951ba, + 0xff6dc419, 0xf66af48f, 0xed63a535, 0xe46495a3, + 0xfedb8832, 0xf7dcb8a4, 0xecd5e91e, 0xe5d2d988, + 0x01b64c2b, 0x08b17cbd, 0x13b82d07, 0x1abf1d91, + 0xfdb71064, 0xf4b020f2, 0xefb97148, 0xe6be41de, + 0x02dad47d, 0x0bdde4eb, 0x10d4b551, 0x19d385c7, + 0x036c9856, 0x0a6ba8c0, 0x1162f97a, 0x1865c9ec, + 0xfc015c4f, 0xf5066cd9, 0xee0f3d63, 0xe7080df5, + 0xfb6e20c8, 0xf269105e, 0xe96041e4, 0xe0677172, + 0x0403e4d1, 0x0d04d447, 0x160d85fd, 0x1f0ab56b, + 0x05b5a8fa, 0x0cb2986c, 0x17bbc9d6, 0x1ebcf940, + 0xfad86ce3, 0xf3df5c75, 0xe8d60dcf, 0xe1d13d59, + 0x06d930ac, 0x0fde003a, 0x14d75180, 0x1dd06116, + 0xf9b4f4b5, 0xf0b3c423, 0xebba9599, 0xe2bda50f, + 0xf802b89e, 0xf1058808, 0xea0cd9b2, 0xe30be924, + 0x076f7c87, 0x0e684c11, 0x15611dab, 0x1c662d3d, + 0xf6dc4190, 0xffdb7106, 0xe4d220bc, 0xedd5102a, + 0x09b18589, 0x00b6b51f, 0x1bbfe4a5, 0x12b8d433, + 0x0807c9a2, 0x0100f934, 0x1a09a88e, 0x130e9818, + 0xf76a0dbb, 0xfe6d3d2d, 0xe5646c97, 0xec635c01, + 0x0b6b51f4, 0x026c6162, 0x196530d8, 0x1062004e, + 0xf40695ed, 0xfd01a57b, 0xe608f4c1, 0xef0fc457, + 0xf5b0d9c6, 0xfcb7e950, 0xe7beb8ea, 0xeeb9887c, + 0x0add1ddf, 0x03da2d49, 0x18d37cf3, 0x11d44c65, + 0x0db26158, 0x04b551ce, 0x1fbc0074, 0x16bb30e2, + 0xf2dfa541, 0xfbd895d7, 0xe0d1c46d, 0xe9d6f4fb, + 0xf369e96a, 0xfa6ed9fc, 0xe1678846, 0xe860b8d0, + 0x0c042d73, 0x05031de5, 0x1e0a4c5f, 0x170d7cc9, + 0xf005713c, 0xf90241aa, 0xe20b1010, 0xeb0c2086, + 0x0f68b525, 0x066f85b3, 0x1d66d409, 0x1461e49f, + 0x0edef90e, 0x07d9c998, 0x1cd09822, 0x15d7a8b4, + 0xf1b33d17, 0xf8b40d81, 0xe3bd5c3b, 0xeaba6cad, + 0xedb88320, 0xe4bfb3b6, 0xffb6e20c, 0xf6b1d29a, + 0x12d54739, 0x1bd277af, 0x00db2615, 0x09dc1683, + 0x13630b12, 0x1a643b84, 0x016d6a3e, 0x086a5aa8, + 0xec0ecf0b, 0xe509ff9d, 0xfe00ae27, 0xf7079eb1, + 0x100f9344, 0x1908a3d2, 0x0201f268, 0x0b06c2fe, + 0xef62575d, 0xe66567cb, 0xfd6c3671, 0xf46b06e7, + 0xeed41b76, 0xe7d32be0, 0xfcda7a5a, 0xf5dd4acc, + 0x11b9df6f, 0x18beeff9, 0x03b7be43, 0x0ab08ed5, + 0x16d6a3e8, 0x1fd1937e, 0x04d8c2c4, 0x0ddff252, + 0xe9bb67f1, 0xe0bc5767, 0xfbb506dd, 0xf2b2364b, + 0xe80d2bda, 0xe10a1b4c, 0xfa034af6, 0xf3047a60, + 0x1760efc3, 0x1e67df55, 0x056e8eef, 0x0c69be79, + 0xeb61b38c, 0xe266831a, 0xf96fd2a0, 0xf068e236, + 0x140c7795, 0x1d0b4703, 0x060216b9, 0x0f05262f, + 0x15ba3bbe, 0x1cbd0b28, 0x07b45a92, 0x0eb36a04, + 0xead7ffa7, 0xe3d0cf31, 0xf8d99e8b, 0xf1deae1d, + 0x1b64c2b0, 0x1263f226, 0x096aa39c, 0x006d930a, + 0xe40906a9, 0xed0e363f, 0xf6076785, 0xff005713, + 0xe5bf4a82, 0xecb87a14, 0xf7b12bae, 0xfeb61b38, + 0x1ad28e9b, 0x13d5be0d, 0x08dcefb7, 0x01dbdf21, + 0xe6d3d2d4, 0xefd4e242, 0xf4ddb3f8, 0xfdda836e, + 0x19be16cd, 0x10b9265b, 0x0bb077e1, 0x02b74777, + 0x18085ae6, 0x110f6a70, 0x0a063bca, 0x03010b5c, + 0xe7659eff, 0xee62ae69, 0xf56bffd3, 0xfc6ccf45, + 0xe00ae278, 0xe90dd2ee, 0xf2048354, 0xfb03b3c2, + 0x1f672661, 0x166016f7, 0x0d69474d, 0x046e77db, + 0x1ed16a4a, 0x17d65adc, 0x0cdf0b66, 0x05d83bf0, + 0xe1bcae53, 0xe8bb9ec5, 0xf3b2cf7f, 0xfab5ffe9, + 0x1dbdf21c, 0x14bac28a, 0x0fb39330, 0x06b4a3a6, + 0xe2d03605, 0xebd70693, 0xf0de5729, 0xf9d967bf, + 0xe3667a2e, 0xea614ab8, 0xf1681b02, 0xf86f2b94, + 0x1c0bbe37, 0x150c8ea1, 0x0e05df1b, 0x0702ef8d, + }; + +/* This is taken from the kernel/sys/version.c */ +#if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER)) +# define COMPILER_VERSION "gcc " __VERSION__ +#elif (defined(__clang__)) +# define COMPILER_VERSION "clang " __clang_version__ +#else +# define COMPILER_VERSION "unknown-compiler how-did-you-do-that" +#endif + +int main(int argc, char * argv[]) { + int _stdin = open("/dev/null", O_RDONLY); + int _stdout = open("/dev/ttyS0", O_WRONLY); + int _stderr = open("/dev/ttyS0", O_WRONLY); + + if (_stdout < 0) { + _stdout = open("/dev/null", O_WRONLY); + _stderr = open("/dev/null", O_WRONLY); + } + + (void)_stdin; + (void)_stdout; + (void)_stderr; + + framebuffer_fd = open("/dev/fb0", O_RDONLY); + if (framebuffer_fd < 0) { + has_video = 0; + memset(textmemptr, 0, sizeof(unsigned short) * 80 * 25); + } else { + update_video(0); + signal(SIGWINEVENT, update_video); + } + + TRACE("\n\nToaruOS-NIH Netinit Host\n\n"); + + TRACE("ToaruOS-NIH is free software under the NCSA / University of Illinois license.\n"); + TRACE(" https://toaruos.org/ https://git.toaruos.org/klange/toaru-nih\n\n"); + + struct utsname u; + uname(&u); + TRACE("%s %s %s %s\n", u.sysname, u.nodename, u.release, u.version); + + { + char kernel_version[512] = {0}; + int fd = open("/proc/compiler", O_RDONLY); + read(fd, kernel_version, 512); + if (kernel_version[strlen(kernel_version)-1] == '\n') { + kernel_version[strlen(kernel_version)-1] = '\0'; + } + TRACE(" Kernel was built with: %s\n", kernel_version); + } + + TRACE(" Netinit binary was built with: %s\n", COMPILER_VERSION); + + TRACE("\n"); + + if (has_video) { + TRACE("Display is %dx%d (%d bpp), framebuffer at 0x%x\n", width, height, depth, (unsigned int)framebuffer); + } + + TRACE("\n"); + TRACE("Sleeping for a moment to let network initialize...\n"); + sleep(2); + +#define LINE_LEN 100 + char line[LINE_LEN]; + + FILE * f = fopen("/proc/netif", "r"); + + while (fgets(line, LINE_LEN, f) != NULL) { + if (strstr(line, "ip:") == line) { + char * value = strchr(line,'\t')+1; + *strchr(value,'\n') = '\0'; + TRACE(" IP address: %s\n", value); + } else if (strstr(line, "device:") == line) { + char * value = strchr(line,'\t')+1; + *strchr(value,'\n') = '\0'; + TRACE(" Network Driver: %s\n", value); + } else if (strstr(line, "mac:") == line) { + char * value = strchr(line,'\t')+1; + *strchr(value,'\n') = '\0'; + TRACE(" MAC address: %s\n", value); + } else if (strstr(line, "dns:") == line) { + char * value = strchr(line,'\t')+1; + *strchr(value,'\n') = '\0'; + TRACE(" DNS server: %s\n", value); + } else if (strstr(line, "gateway:") == line) { + char * value = strchr(line,'\t')+1; + *strchr(value,'\n') = '\0'; + TRACE(" Gateway: %s\n", value); + } else if (strstr(line,"no network") == line){ + network_error(0); + } + memset(line, 0, LINE_LEN); + } + + fclose(f); + + + struct http_req my_req; + /* TODO: Extract URL from kcmdline */ + parse_url(NETBOOT_URL, &my_req); + + char file[100]; + sprintf(file, "/dev/net/%s:%d", my_req.domain, my_req.port); + + TRACE("Fetching from %s... ", my_req.domain); + + fetch_options.out = fopen(img,"w+"); + + pthread_t watchdog; + + pthread_create(&watchdog, NULL, watchdog_func, NULL); + + f = fopen(file,"r+"); + if (!f) { + network_error(0); + } + +#if 0 + char * vbuf = malloc(10240); + setvbuf(f,vbuf,_IOLBF,10240); +#endif + + watchdog_success = 1; + + TRACE("Connection established.\n"); + + fprintf(f, + "GET /%s HTTP/1.0\r\n" + "User-Agent: curl/7.35.0\r\n" + "Host: %s\r\n" + "Accept: */*\r\n" + "\r\n", my_req.path, my_req.domain); + + gettimeofday(&start, NULL); + + hashmap_t * headers = hashmap_create(10); + + /* Parse response */ + { + char buf[BUF_SIZE]; + read_http_line(buf, f); + TRACE("[%s]\n", buf); + + char * elements[3]; + + elements[0] = buf; + elements[1] = strchr(elements[0], ' '); + if (!elements[1]) bad_response(); + *elements[1] = '\0'; + elements[1]++; + + elements[2] = strchr(elements[1], ' '); + if (!elements[2]) bad_response(); + *elements[2] = '\0'; + elements[2]++; + + if (strcmp(elements[1], "200")) { + TRACE("Bad response code: %s\n", elements[1]); + return 1; + } + } + + while (1) { + char buf[BUF_SIZE]; + read_http_line(buf, f); + + if (!*buf) { + TRACE("(done with headers)\n"); + break; + } + + /* Split */ + char * name = buf; + char * value = strstr(buf, ": "); + if (!value) bad_response(); + *value = '\0'; + value += 2; + + hashmap_set(headers, name, strdup(value)); + } + +#if 1 + TRACE("Dumping headers.\n"); + list_t * hash_keys = hashmap_keys(headers); + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + TRACE("[%s] = %s\n", key, (char*)hashmap_get(headers, key)); + } + list_free(hash_keys); + free(hash_keys); +#endif + + /* determine how many bytes we should read now */ + if (!hashmap_has(headers, "Content-Length")) { + TRACE("Don't know how much to read.\n"); + return 1; + } + + int bytes_to_read = atoi(hashmap_get(headers, "Content-Length")); + size_t bytes_total = (size_t)bytes_to_read; + size_t bytes_read = 0; + +#define RBUF_SIZE 10240 + char * buf = malloc(RBUF_SIZE); + uint32_t crc32 = 0xffffffff; + while (bytes_to_read > 0) { + size_t r = fread(buf, 1, bytes_to_read < RBUF_SIZE ? bytes_to_read : RBUF_SIZE, f); + fwrite(buf, 1, r, fetch_options.out); + for (size_t i = 0; i < r; ++i) { + int ind = (crc32 ^ buf[i]) & 0xFF; + crc32 = (crc32 >> 8) ^ (crctab[ind]); + } + bytes_to_read -= r; + bytes_read += r; + draw_progress(bytes_total, bytes_read); + } + crc32 ^= 0xffffffff; + free(buf); + + TRACE("\nDone: 0x%x\n", (unsigned int)crc32); + + fflush(fetch_options.out); + fclose(fetch_options.out); + +#if 0 + FILE * xtmp = fopen(img, "r"); + crc32 = 0xffffffff; + int tab = 0; + size_t bytesread = 0; + while (!feof(xtmp)) { + uint8_t buf[1024]; + size_t r = fread(buf, 1, 1024, xtmp); + for (size_t i = 0; i < r; ++i) { + if (tab & 0x01) { + TRACE("%2x ", (unsigned char)buf[i]); + } else { + TRACE("%2x", (unsigned char)buf[i]); + } + tab++; + if (tab == 32){ + tab = 0; + TRACE("\n"); + } + int ind = (crc32 ^ buf[i]) & 0xFF; + crc32 = (crc32 >> 8) ^ (crctab[ind]); + } + bytesread += r; + } + crc32 ^= 0xffffffff; + TRACE("\nDisk crc32: 0x%x (%d)\n", (unsigned int)crc32, bytesread); +#endif + + TRACE("Mounting filesystem... "); + int err = 0; + if ((err = mount(img, "/", "ext2", 0, NULL))) { + TRACE("Mount error: %d; errno=%d\n", err, errno); + return 0; + } else { + TRACE("Done.\n"); + } + + FILE * tmp = fopen("/bin/init","r"); + if (!tmp) { + TRACE("/bin/init missing?\n"); + } else { + TRACE("/bin/init exists, filesystem successfully mounted\n"); + fclose(tmp); + } + + TRACE("Executing init...\n"); + char * const _argv[] = { + "/bin/init", + argv[1], + NULL, + }; + execve("/bin/init",_argv,NULL); + + TRACE("ERROR: If you are seeing this, there was a problem\n"); + TRACE(" executing the init binary from the downloaded\n"); + TRACE(" filesystem. This may indicate a corrupted\n"); + TRACE(" download. Please try again.\n"); + + return 0; +} diff --git a/util/package-mods.py b/util/package-mods.py deleted file mode 100755 index 17aa7258..00000000 --- a/util/package-mods.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -import os -import struct - -# This is ORDERED, so don't screw it up. -mods_to_pack = [ - 'zero', - 'random', - 'serial', - 'procfs', - 'tmpfs', - 'ext2', - 'ps2kbd', - 'ps2mouse', - 'lfbvideo', - 'packetfs', -] - - -with open('modpack.kop','wb') as pack: - for mod in mods_to_pack: - with open('hdd/mod/{mod}.ko'.format(mod=mod),'rb') as m: - pack.write(b"PACK") - size = os.stat(m.name).st_size - extra = 0 - while (size + extra) % 4096 != 0: - extra += 1 - pack.write(struct.pack("I", size+extra)) - pack.write(b'\0' * (4096-8)) - pack.write(m.read(size)) - pack.write(b'\0' * extra) - pack.write(b"PACK") - pack.write(b'\0\0\0\0') - - diff --git a/util/parted.conf b/util/parted.conf deleted file mode 100644 index e5ac79f7..00000000 --- a/util/parted.conf +++ /dev/null @@ -1,4 +0,0 @@ -mklabel msdos -mkpart primary ext2 0% 100% -set 1 boot on -quit diff --git a/toolchain/patches/binutils-2.27.patch b/util/patches/binutils.patch similarity index 100% rename from toolchain/patches/binutils-2.27.patch rename to util/patches/binutils.patch diff --git a/toolchain/patches/gcc-6.4.0.patch b/util/patches/gcc.patch similarity index 100% rename from toolchain/patches/gcc-6.4.0.patch rename to util/patches/gcc.patch diff --git a/util/prompt.sh b/util/prompt.sh new file mode 100755 index 00000000..7cd50aab --- /dev/null +++ b/util/prompt.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +if ! $DIR/check-reqs.sh >&2; then + echo "A toolchain is not available and the above issues were found." >&2 + echo "Resolve the problems above and run \`make\` again." >&2 + echo -n "n" && exit 1 +fi + +echo -n "Toolchain has not been built. Would you like to build it now? (y/n) " >&2 +read response +case $response in + [yY]) bash $DIR/build-gcc.sh >&2 ;; + [nN]) echo -n "n" && exit 1 ;; + *) +esac + diff --git a/userspace/py/lib/about_applet.py b/util/python-demos/about_applet.py similarity index 72% rename from userspace/py/lib/about_applet.py rename to util/python-demos/about_applet.py index 2a9278bd..84bcd528 100644 --- a/userspace/py/lib/about_applet.py +++ b/util/python-demos/about_applet.py @@ -21,10 +21,12 @@ class AboutAppletWindow(yutani.Window): text_offset = 110 def __init__(self, decorator, title, logo, text, icon="star",on_close=None): - super(AboutAppletWindow, self).__init__(self.base_width + decorator.width(), self.base_height + decorator.height(), title=title, icon=icon, doublebuffer=True) + super(AboutAppletWindow, self).__init__(self.base_width + decorator.width(), self.base_height + decorator.height(), title=title, flags=yutani.WindowFlag.FLAG_DISALLOW_RESIZE, icon=icon, doublebuffer=True) self.move(int((yutani.yutani_ctx._ptr.contents.display_width-self.width)/2),int((yutani.yutani_ctx._ptr.contents.display_height-self.height)/2)) self.decorator = decorator - self.logo = cairo.ImageSurface.create_from_png(logo) + if logo.endswith('.png'): + logo = logo.replace('.png','.bmp') # Hope that works + self.logo = yutani.Sprite.from_file(logo).get_cairo_surface() self.font = toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF, 13, 0xFF000000) self.tr = text_region.TextRegion(0,0,self.base_width-30,self.base_height-self.text_offset,font=self.font) self.tr.set_alignment(2) @@ -35,10 +37,10 @@ class AboutAppletWindow(yutani.Window): def draw(self): surface = self.get_cairo_surface() - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() + WIDTH, HEIGHT = self.width - self.decorator.width(self), self.height - self.decorator.height(self) ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) + ctx.translate(self.decorator.left_width(self), self.decorator.top_height(self)) ctx.rectangle(0,0,WIDTH,HEIGHT) ctx.set_source_rgb(204/255,204/255,204/255) ctx.fill() @@ -47,7 +49,7 @@ class AboutAppletWindow(yutani.Window): ctx.paint() self.tr.resize(WIDTH-30,HEIGHT-self.text_offset) - self.tr.move(self.decorator.left_width() + 15,self.decorator.top_height()+self.text_offset) + self.tr.move(self.decorator.left_width(self) + 15,self.decorator.top_height(self)+self.text_offset) self.tr.draw(self) self.decorator.render(self) @@ -70,10 +72,11 @@ class AboutAppletWindow(yutani.Window): if self.decorator.handle_event(msg) == yutani.Decor.EVENT_CLOSE: self.close_window() return - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + x,y = msg.new_x - self.decorator.left_width(self), msg.new_y - self.decorator.top_height(self) + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) def keyboard_event(self, msg): if msg.event.key == b"q": self.close_window() + diff --git a/userspace/py/lib/button.py b/util/python-demos/button.py similarity index 100% rename from userspace/py/lib/button.py rename to util/python-demos/button.py diff --git a/userspace/py/bin/calculator.py b/util/python-demos/calculator.py similarity index 90% rename from userspace/py/bin/calculator.py rename to util/python-demos/calculator.py index 5c187bbb..90d17425 100755 --- a/userspace/py/bin/calculator.py +++ b/util/python-demos/calculator.py @@ -26,7 +26,7 @@ operators = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, app_name = "Calculator" version = "1.0.0" -_description = f"{app_name} {version}\n© 2017 Kevin Lange\n\nSimple four-function calculator using Python.\n\nhttp://github.com/klange/toaruos" +_description = f"{app_name} {version}\n© 2017-2018 K. Lange\n\nSimple four-function calculator using Python.\n\nhttp://github.com/klange/toaruos" def eval_expr(expr): """ @@ -100,7 +100,7 @@ class CalculatorWindow(yutani.Window): self.menubar = MenuBarWidget(self,menus) - self.tr = text_region.TextRegion(self.decorator.left_width()+5,self.decorator.top_height()+self.menubar.height,self.base_width-10,40) + self.tr = text_region.TextRegion(self.decorator.left_width(self)+5,self.decorator.top_height(self)+self.menubar.height,self.base_width-10,40) self.tr.set_font(toaru_fonts.Font(toaru_fonts.FONT_MONOSPACE,18)) self.tr.set_text("") self.tr.set_alignment(1) @@ -158,10 +158,10 @@ class CalculatorWindow(yutani.Window): def draw(self): surface = self.get_cairo_surface() - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() + WIDTH, HEIGHT = self.width - self.decorator.width(self), self.height - self.decorator.height(self) ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) + ctx.translate(self.decorator.left_width(self), self.decorator.top_height(self)) ctx.rectangle(0,0,WIDTH,HEIGHT) ctx.set_source_rgb(204/255,204/255,204/255) ctx.fill() @@ -169,6 +169,7 @@ class CalculatorWindow(yutani.Window): ctx.rectangle(0,5+self.menubar.height,WIDTH,self.tr.height-10) ctx.set_source_rgb(1,1,1) ctx.fill() + self.tr.move(self.decorator.left_width(self)+5,self.decorator.top_height(self)+self.menubar.height) self.tr.resize(WIDTH-10, self.tr.height) self.tr.draw(self) @@ -200,11 +201,14 @@ class CalculatorWindow(yutani.Window): self.flip() def mouse_event(self, msg): - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: + decor_event = d.handle_event(msg) + if decor_event == yutani.Decor.EVENT_CLOSE: window.close() sys.exit(0) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + elif decor_event == yutani.Decor.EVENT_RIGHT: + d.show_menu(self, msg) + x,y = msg.new_x - self.decorator.left_width(self), msg.new_y - self.decorator.top_height(self) + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) if x >= 0 and x < w and y >= 0 and y < self.menubar.height: self.menubar.mouse_event(msg, x, y) @@ -230,7 +234,7 @@ class CalculatorWindow(yutani.Window): else: if y > self.tr.height + self.menubar.height and y < h and x >= 0 and x < w: row = int((y - self.tr.height - self.menubar.height) / (self.height - self.decorator.height() - self.tr.height - self.menubar.height) * len(self.buttons)) - col = int(x / (self.width - self.decorator.width()) * len(self.buttons[row])) + col = int(x / (self.width - self.decorator.width(self)) * len(self.buttons[row])) button = self.buttons[row][col] if button != self.hover_widget: if button: diff --git a/userspace/py/bin/clock.py b/util/python-demos/clock.py similarity index 96% rename from userspace/py/bin/clock.py rename to util/python-demos/clock.py index 6518554e..e1c741c8 100755 --- a/userspace/py/bin/clock.py +++ b/util/python-demos/clock.py @@ -10,7 +10,6 @@ import time import cairo import yutani -import text_region import toaru_fonts import fswait @@ -21,7 +20,7 @@ import yutani_mainloop app_name = "Clock" version = "1.0.0" -_description = f"{app_name} {version}\n© 2017 Kevin Lange\n\nAnalog clock widget.\n\nhttp://github.com/klange/toaruos" +_description = f"{app_name} {version}\n© 2017-2018 K. Lange\n\nAnalog clock widget.\n\nhttp://github.com/klange/toaruos" class BasicWatchFace(object): @@ -259,9 +258,8 @@ class ClockWindow(yutani.Window): def exit(self, data): sys.exit(0) - def about(self, data): - AboutAppletWindow(d,f"About {app_name}","/usr/share/icons/48/clock.png",_description,"clock") - + def about(self, data=None): + AboutAppletWindow(d,f"About {app_name}","/usr/share/icons/48/clock.bmp",_description,"clock") def mouse_event(self, msg): # drag start @@ -301,7 +299,9 @@ if __name__ == '__main__': fd = fswait.fswait(fds,20) if fd == 0: msg = yutani.yutani_ctx.poll() - yutani_mainloop.handle_event(msg) + while msg: + yutani_mainloop.handle_event(msg) + msg = yutani.yutani_ctx.poll(False) window.draw() elif fd == 1: # Tick diff --git a/userspace/py/lib/dialog.py b/util/python-demos/dialog.py similarity index 91% rename from userspace/py/lib/dialog.py rename to util/python-demos/dialog.py index a7a4786c..43da8779 100644 --- a/userspace/py/lib/dialog.py +++ b/util/python-demos/dialog.py @@ -90,10 +90,10 @@ class DialogWindow(yutani.Window): def draw(self): surface = self.get_cairo_surface() - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() + WIDTH, HEIGHT = self.width - self.decorator.width(self), self.height - self.decorator.height(self) ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) + ctx.translate(self.decorator.left_width(self), self.decorator.top_height(self)) ctx.rectangle(0,0,WIDTH,HEIGHT) ctx.set_source_rgb(204/255,204/255,204/255) ctx.fill() @@ -102,7 +102,7 @@ class DialogWindow(yutani.Window): ctx.paint() self.tr.resize(WIDTH-90,HEIGHT-self.text_offset) - self.tr.move(self.decorator.left_width() + 90,self.decorator.top_height()+self.text_offset) + self.tr.move(self.decorator.left_width(self) + 90,self.decorator.top_height(self)+self.text_offset) self.tr.draw(self) self.button_ok.draw(self,ctx,WIDTH-130,HEIGHT-60,100,30) @@ -121,14 +121,17 @@ class DialogWindow(yutani.Window): self.flip() def mouse_event(self, msg): - if self.decorator.handle_event(msg) == yutani.Decor.EVENT_CLOSE: + decor_event = self.decorator.handle_event(msg) + if decor_event == yutani.Decor.EVENT_CLOSE: if self.close_is_cancel: self.cancel_click(None) else: self.ok_click(None) return - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + elif decor_event == yutani.Decor.EVENT_RIGHT: + self.decorator.show_menu(self, msg) + x,y = msg.new_x - self.decorator.left_width(self), msg.new_y - self.decorator.top_height(self) + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) redraw = False if self.down_button: @@ -332,10 +335,10 @@ class OpenFileDialog(DialogWindow): def draw(self): surface = self.get_cairo_surface() - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() + WIDTH, HEIGHT = self.width - self.decorator.width(self), self.height - self.decorator.height(self) ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) + ctx.translate(self.decorator.left_width(self), self.decorator.top_height(self)) ctx.rectangle(0,0,WIDTH,HEIGHT) ctx.set_source_rgb(204/255,204/255,204/255) ctx.fill() @@ -344,7 +347,7 @@ class OpenFileDialog(DialogWindow): #ctx.paint() self.tr.resize(WIDTH,30) - self.tr.move(self.decorator.left_width(),self.decorator.top_height()+10) + self.tr.move(self.decorator.left_width(self),self.decorator.top_height(self)+10) self.tr.set_alignment(2) self.tr.draw(self) @@ -370,7 +373,7 @@ class OpenFileDialog(DialogWindow): self.flip() def scroll(self, amount): - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) self.scroll_y += amount if self.scroll_y > 0: self.scroll_y = 0 @@ -382,8 +385,8 @@ class OpenFileDialog(DialogWindow): def mouse_event(self, msg): super(OpenFileDialog,self).mouse_event(msg) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + x,y = msg.new_x - self.decorator.left_width(self), msg.new_y - self.decorator.top_height(self) + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) if y < 0: return if x < 0 or x >= w: return diff --git a/userspace/py/bin/file_browser.py b/util/python-demos/file_browser.py similarity index 92% rename from userspace/py/bin/file_browser.py rename to util/python-demos/file_browser.py index fac65ff3..832fe892 100755 --- a/userspace/py/bin/file_browser.py +++ b/util/python-demos/file_browser.py @@ -24,7 +24,7 @@ import yutani_mainloop app_name = "File Browser" version = "1.0.0" -_description = f"{app_name} {version}\n© 2017 Kevin Lange\n\nFile system navigator.\n\nhttp://github.com/klange/toaruos" +_description = f"{app_name} {version}\n© 2017-2018 K. Lange\n\nFile system navigator.\n\nhttp://github.com/klange/toaruos" class File(object): @@ -83,8 +83,6 @@ class FileBrowserWindow(yutani.Window): def __init__(self, decorator, path): super(FileBrowserWindow, self).__init__(self.base_width + decorator.width(), self.base_height + decorator.height(), title=app_name, icon="folder", doublebuffer=True) self.move(100,100) - self.x = 100 - self.y = 100 self.decorator = decorator def exit_app(action): @@ -159,7 +157,7 @@ class FileBrowserWindow(yutani.Window): def redraw_buf(self,icons=None): if self.buf: self.buf.destroy() - w = self.width - self.decorator.width() + w = self.width - self.decorator.width(self) files_per_row = int(w / 100) self.buf = yutani.GraphicsBuffer(w,math.ceil(len(self.files)/files_per_row)*100) @@ -196,10 +194,10 @@ class FileBrowserWindow(yutani.Window): def draw(self): surface = self.get_cairo_surface() - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() + WIDTH, HEIGHT = self.width - self.decorator.width(self), self.height - self.decorator.height(self) ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) + ctx.translate(self.decorator.left_width(self), self.decorator.top_height(self)) ctx.rectangle(0,0,WIDTH,HEIGHT) ctx.set_source_rgb(1,1,1) ctx.fill() @@ -229,7 +227,7 @@ class FileBrowserWindow(yutani.Window): self.flip() def scroll(self, amount): - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) files_per_row = int(w / 100) rows_total = math.ceil(len(self.files) / files_per_row) rows_visible = int((h - 24) / 100) @@ -242,11 +240,14 @@ class FileBrowserWindow(yutani.Window): self.scroll_y = -100 * rows def mouse_event(self, msg): - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: + decor_event = d.handle_event(msg) + if decor_event == yutani.Decor.EVENT_CLOSE: window.close() sys.exit(0) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + elif decor_event == yutani.Decor.EVENT_RIGHT: + d.show_menu(self, msg) + x,y = msg.new_x - self.decorator.left_width(self), msg.new_y - self.decorator.top_height(self) + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) if x >= 0 and x < w and y >= 0 and y < self.menubar.height: self.menubar.mouse_event(msg, x, y) diff --git a/userspace/py/lib/fswait.py b/util/python-demos/fswait.py similarity index 100% rename from userspace/py/lib/fswait.py rename to util/python-demos/fswait.py diff --git a/userspace/py/bin/help-browser.py b/util/python-demos/help-browser.py similarity index 99% rename from userspace/py/bin/help-browser.py rename to util/python-demos/help-browser.py index 5ceda1e1..d0244283 100755 --- a/userspace/py/bin/help-browser.py +++ b/util/python-demos/help-browser.py @@ -22,7 +22,6 @@ app_name = "Help Browser" version = "1.0.0" _description = f"{app_name} {version}\n© 2017 Kevin Lange\n\nRich text help document viewer.\n\nhttp://github.com/klange/toaruos" - class ScrollableText(object): def __init__(self): @@ -94,8 +93,6 @@ class HelpBrowserWindow(yutani.Window): def __init__(self, decorator): super(HelpBrowserWindow, self).__init__(self.base_width + decorator.width(), self.base_height + decorator.height(), title=app_name, icon="help", doublebuffer=True) self.move(100,100) - self.x = 100 - self.y = 100 self.decorator = decorator self.current_topic = "0_index.trt" self.text_buffer = None diff --git a/userspace/py/lib/icon_cache.py b/util/python-demos/icon_cache.py similarity index 85% rename from userspace/py/lib/icon_cache.py rename to util/python-demos/icon_cache.py index 7c2fe5a9..9c42ceef 100644 --- a/userspace/py/lib/icon_cache.py +++ b/util/python-demos/icon_cache.py @@ -3,6 +3,7 @@ Library for caching Cairo surfaces for icons by name and size. """ import os import cairo +import yutani icon_directories = { 16: [ @@ -41,9 +42,10 @@ def get_icon(name,size=24,fallback='applications-generic'): if not name in icon_cache[size]: for directory in icon_directories[size]: - path = f"{directory}/{name}.png" + path = f"{directory}/{name}.bmp" if os.access(path,os.R_OK): - icon = cairo.ImageSurface.create_from_png(f"{directory}/{name}.png") + #icon = cairo.ImageSurface.create_from_png(f"{directory}/{name}.png") + icon = yutani.Sprite.from_file(f"{directory}/{name}.bmp").get_cairo_surface() icon_cache[size][name] = icon return icon return get_icon(fallback,size) diff --git a/userspace/py/lib/input_box.py b/util/python-demos/input_box.py similarity index 96% rename from userspace/py/lib/input_box.py rename to util/python-demos/input_box.py index 8aecfed9..2d84b31e 100755 --- a/userspace/py/lib/input_box.py +++ b/util/python-demos/input_box.py @@ -321,10 +321,10 @@ class TextInputWindow(yutani.Window): surface = self.get_cairo_surface() - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() + WIDTH, HEIGHT = self.width - self.decorator.width(self), self.height - self.decorator.height(self) ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) + ctx.translate(self.decorator.left_width(self), self.decorator.top_height(self)) ctx.rectangle(0,0,WIDTH,HEIGHT) ctx.set_source_rgb(204/255,204/255,204/255) ctx.fill() @@ -346,8 +346,8 @@ class TextInputWindow(yutani.Window): """Accept a resize.""" self.resize_accept(msg.width, msg.height) self.reinit() - self.int_width = msg.width - self.decorator.width() - self.int_height = msg.height - self.decorator.height() + self.int_width = msg.width - self.decorator.width(self) + self.int_height = msg.height - self.decorator.height(self) self.draw() self.resize_done() self.flip() @@ -356,8 +356,8 @@ class TextInputWindow(yutani.Window): if self.closed: return if self.decorator.handle_event(msg) == yutani.Decor.EVENT_CLOSE: self.cancel_click(None) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + x,y = msg.new_x - self.decorator.left_width(self), msg.new_y - self.decorator.top_height(self) + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) redraw = False if self.down_button: diff --git a/userspace/py/lib/menu_bar.py b/util/python-demos/menu_bar.py similarity index 93% rename from userspace/py/lib/menu_bar.py rename to util/python-demos/menu_bar.py index 71776403..40eb2bb7 100644 --- a/userspace/py/lib/menu_bar.py +++ b/util/python-demos/menu_bar.py @@ -67,12 +67,12 @@ class MenuBarWidget(object): w = self.font.width(title) + 10 if x >= offset and x < offset + w: if msg.command == yutani.MouseEvent.CLICK or close_enough(msg): - menu = MenuWindow(menu,(self.window.x+self.window.decorator.left_width()+offset,self.window.y+self.window.decorator.top_height()+self.height),root=self.window) + menu = MenuWindow(menu,(self.window.x+self.window.decorator.left_width(self.window)+offset,self.window.y+self.window.decorator.top_height(self.window)+self.height),root=self.window) self.active_menu = menu self.active_entry = e elif self.active_menu and self.active_menu in self.window.menus.values() and e != self.active_entry: self.active_menu.definitely_close() - menu = MenuWindow(menu,(self.window.x+self.window.decorator.left_width()+offset,self.window.y+self.window.decorator.top_height()+self.height),root=self.window) + menu = MenuWindow(menu,(self.window.x+self.window.decorator.left_width(self.window)+offset,self.window.y+self.window.decorator.top_height(self.window)+self.height),root=self.window) self.active_menu = menu self.active_entry = e self.window.draw() @@ -193,6 +193,23 @@ class MenuEntrySubmenu(MenuEntryAction): def __init__(self, title, entries, icon="folder"): super(MenuEntrySubmenu,self).__init__(title,icon,None,None) self.entries = entries + self.tick = get_icon('menu-tick', 16) + self.tick_hilight = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.tick.get_width(), self.tick.get_height()) + tmp = cairo.Context(self.tick_hilight) + tmp.set_operator(cairo.OPERATOR_SOURCE) + tmp.set_source_surface(self.tick,0,0) + tmp.paint() + tmp.set_operator(cairo.OPERATOR_ATOP) + tmp.rectangle(0,0,16,16) + tmp.set_source_rgb(1,1,1) + tmp.paint() + + def draw(self, window, offset, ctx): + super(MenuEntrySubmenu,self).draw(window, offset, ctx) + ctx.save() + ctx.set_source_surface(self.tick if not self.hilight else self.tick_hilight,window.width-16, self.offset + 2) + ctx.paint() + ctx.restore() def focus_enter(self,keyboard=False): self.tr.set_font(self.font_hilight) @@ -256,7 +273,6 @@ class MenuWindow(yutani.Window): self.move(*origin) self.focused_widget = None self.child = None - self.x, self.y = origin self.closed = False self.root = root self.root.menus[self.wid] = self diff --git a/userspace/py/bin/mines.py b/util/python-demos/mines.py similarity index 94% rename from userspace/py/bin/mines.py rename to util/python-demos/mines.py index 5c357cce..7fa1a8b2 100755 --- a/userspace/py/bin/mines.py +++ b/util/python-demos/mines.py @@ -22,7 +22,7 @@ import yutani_mainloop version = "1.0.0" app_name = "Mines" -_description = f"{app_name} {version}\n© 2017 Kevin Lange\n\nClassic logic game.\n\nhttp://github.com/klange/toaruos" +_description = f"{app_name} {version}\n© 2017-2018 K. Lange\n\nClassic logic game.\n\nhttp://github.com/klange/toaruos" class MineButton(Button): @@ -129,7 +129,7 @@ class MinesWindow(yutani.Window): self.menubar = MenuBarWidget(self,menus) - self.tr = text_region.TextRegion(self.decorator.left_width()+5,self.decorator.top_height()+self.menubar.height,self.base_width-10,40) + self.tr = text_region.TextRegion(self.decorator.left_width(self)+5,self.decorator.top_height(self)+self.menubar.height,self.base_width-10,40) self.tr.set_font(toaru_fonts.Font(toaru_fonts.FONT_SANS_SERIF,18)) self.tr.set_alignment(2) self.tr.set_valignment(2) @@ -253,10 +253,10 @@ class MinesWindow(yutani.Window): def draw(self): surface = self.get_cairo_surface() - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() + WIDTH, HEIGHT = self.width - self.decorator.width(self), self.height - self.decorator.height(self) ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) + ctx.translate(self.decorator.left_width(self), self.decorator.top_height(self)) ctx.rectangle(0,0,WIDTH,HEIGHT) ctx.set_source_rgb(204/255,204/255,204/255) ctx.fill() @@ -294,11 +294,14 @@ class MinesWindow(yutani.Window): self.flip() def mouse_event(self, msg): - if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: + decor_event = d.handle_event(msg) + if decor_event == yutani.Decor.EVENT_CLOSE: window.close() sys.exit(0) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + elif decor_event == yutani.Decor.EVENT_RIGHT: + d.show_menu(self, msg) + x,y = msg.new_x - self.decorator.left_width(self), msg.new_y - self.decorator.top_height(self) + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) if x >= 0 and x < w and y >= 0 and y < self.menubar.height: self.menubar.mouse_event(msg, x, y) diff --git a/userspace/py/bin/panel.py b/util/python-demos/panel.py similarity index 97% rename from userspace/py/bin/panel.py rename to util/python-demos/panel.py index 16dbb430..bc41695b 100755 --- a/userspace/py/bin/panel.py +++ b/util/python-demos/panel.py @@ -26,7 +26,7 @@ import yutani import text_region import toaru_fonts import fswait -import toaru_webp +#import toaru_webp from menu_bar import MenuEntryAction, MenuEntrySubmenu, MenuEntryDivider, MenuWindow from icon_cache import get_icon @@ -35,6 +35,9 @@ import toaru_theme PANEL_HEIGHT=28 +def create_from_bmp(path): + return yutani.Sprite.from_file(path).get_cairo_surface() + def close_enough(msg): return msg.command == yutani.MouseEvent.RAISE and \ math.sqrt((msg.new_x - msg.old_x) ** 2 + (msg.new_y - msg.old_y) ** 2) < 10 @@ -138,11 +141,11 @@ class LogOutWidget(BaseWidget): width = 28 - path = '/usr/share/icons/panel-shutdown.png' + path = '/usr/share/icons/panel-shutdown.bmp' def __init__(self): - self.icon = cairo.ImageSurface.create_from_png(self.path) - self.icon_hilight = cairo.ImageSurface.create_from_png(self.path) + self.icon = create_from_bmp(self.path) + self.icon_hilight = create_from_bmp(self.path) tmp = cairo.Context(self.icon_hilight) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) @@ -235,13 +238,13 @@ class MouseModeWidget(BaseWidget): self.icons = {} self.icons_hilight = {} for name in self.icon_names: - self.icons[name] = cairo.ImageSurface.create_from_png(f'/usr/share/icons/24/{name}.png') + self.icons[name] = create_from_bmp(f'/usr/share/icons/24/{name}.bmp') tmp = cairo.Context(self.icons[name]) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) tmp.set_source_rgb(*self.color) tmp.paint() - self.icons_hilight[name] = cairo.ImageSurface.create_from_png(f'/usr/share/icons/24/{name}.png') + self.icons_hilight[name] = create_from_bmp(f'/usr/share/icons/24/{name}.bmp') tmp = cairo.Context(self.icons_hilight[name]) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) @@ -336,7 +339,7 @@ class WeatherWidget(BaseWidget): if current_time - self.last_check > self.check_time: # Every so often, try to colect new weather data. self.last_check = current_time - subprocess.Popen(['/bin/weather_tool.py']) + subprocess.Popen(['/usr/share/python-demos/weather_tool.py']) self.update_time = 1 # Try to collect data every seconds. if current_time - self.last_update > self.update_time: @@ -362,14 +365,14 @@ class WeatherWidget(BaseWidget): self.tr.set_richtext(f"{weather['temp_r']}°") self.width = self.icon_width + self.tr.get_offset_at_index(-1)[1][1] - if weather['conditions'] and os.path.exists(f"{self.icons_path}{weather['icon']}.png"): - self.icon = cairo.ImageSurface.create_from_png(f"{self.icons_path}{weather['icon']}.png") + if weather['conditions'] and os.path.exists(f"{self.icons_path}{weather['icon']}.bmp"): + self.icon = create_from_bmp(f"{self.icons_path}{weather['icon']}.bmp") tmp = cairo.Context(self.icon) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) tmp.set_source_rgb(*self.icon_color) tmp.paint() - self.icon_hilight = cairo.ImageSurface.create_from_png(f"{self.icons_path}{weather['icon']}.png") + self.icon_hilight = create_from_bmp(f"{self.icons_path}{weather['icon']}.bmp") tmp = cairo.Context(self.icon_hilight) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) @@ -419,13 +422,13 @@ class VolumeWidget(BaseWidget): self.icons = {} self.icons_hilight = {} for name in self.icon_names: - self.icons[name] = cairo.ImageSurface.create_from_png(f'/usr/share/icons/24/{name}.png') + self.icons[name] = create_from_bmp(f'/usr/share/icons/24/{name}.bmp') tmp = cairo.Context(self.icons[name]) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) tmp.set_source_rgb(*self.color) tmp.paint() - self.icons_hilight[name] = cairo.ImageSurface.create_from_png(f'/usr/share/icons/24/{name}.png') + self.icons_hilight[name] = create_from_bmp(f'/usr/share/icons/24/{name}.bmp') tmp = cairo.Context(self.icons_hilight[name]) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) @@ -535,13 +538,13 @@ class NetworkWidget(BaseWidget): self.icons = {} self.icons_hilight = {} for name in self.icon_names: - self.icons[name] = cairo.ImageSurface.create_from_png(f'/usr/share/icons/24/{name}.png') + self.icons[name] = create_from_bmp(f'/usr/share/icons/24/{name}.bmp') tmp = cairo.Context(self.icons[name]) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) tmp.set_source_rgb(*self.color) tmp.paint() - self.icons_hilight[name] = cairo.ImageSurface.create_from_png(f'/usr/share/icons/24/{name}.png') + self.icons_hilight[name] = create_from_bmp(f'/usr/share/icons/24/{name}.bmp') tmp = cairo.Context(self.icons_hilight[name]) tmp.set_operator(cairo.OPERATOR_ATOP) tmp.rectangle(0,0,24,24) @@ -827,7 +830,7 @@ class PanelWindow(yutani.Window): self.hovered_menu = None # Panel background - self.background = cairo.ImageSurface.create_from_png('/usr/share/panel.png') + self.background = create_from_bmp('/usr/share/panel.bmp') self.background_pattern = cairo.SurfacePattern(self.background) self.background_pattern.set_extend(cairo.EXTEND_REPEAT) @@ -1000,7 +1003,7 @@ class WallpaperIcon(object): class WallpaperWindow(yutani.Window): """Manages the desktop wallpaper window.""" - fallback = '/usr/share/wallpapers/default' + fallback = '/usr/share/wallpaper.bmp' def __init__(self): w = yutani.yutani_ctx._ptr.contents.display_width @@ -1015,8 +1018,6 @@ class WallpaperWindow(yutani.Window): self.icons = self.load_icons() self.focused_icon = None self.animations = {} - self.x = 0 # For clipping - self.y = 0 def animate_new(self): self.new_background = self.load_wallpaper() @@ -1072,9 +1073,9 @@ class WallpaperWindow(yutani.Window): c.read_string(conf_str) path = c['desktop'].get('wallpaper',self.fallback) - if path.endswith('.webp') and toaru_webp.exists(): - return toaru_webp.load_webp(path) - return cairo.ImageSurface.create_from_png(path) + #if path.endswith('.webp') and toaru_webp.exists(): + # return toaru_webp.load_webp(path) + return create_from_bmp(path) def finish_resize(self, msg): self.resize_accept(msg.width, msg.height) @@ -1391,10 +1392,13 @@ def rounded_rectangle(ctx,x,y,w,h,r): def launch_app(item,terminal=False): """Launch an application in the background.""" - if terminal: - subprocess.Popen(['/bin/terminal',item]) - else: - subprocess.Popen(shlex.split(item)) + try: + if terminal: + subprocess.Popen(['/bin/terminal',item]) + else: + subprocess.Popen(shlex.split(item)) + except: + pass def logout_callback(item): """Request the active session be stopped.""" diff --git a/userspace/py/bin/progress-bar.py b/util/python-demos/progress-bar.py similarity index 84% rename from userspace/py/bin/progress-bar.py rename to util/python-demos/progress-bar.py index 2582adfc..5b4c61b9 100755 --- a/userspace/py/bin/progress-bar.py +++ b/util/python-demos/progress-bar.py @@ -59,10 +59,10 @@ class ProgressBarWindow(yutani.Window): def draw(self): surface = self.get_cairo_surface() - WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height() + WIDTH, HEIGHT = self.width - self.decorator.width(self), self.height - self.decorator.height(self) ctx = cairo.Context(surface) - ctx.translate(self.decorator.left_width(), self.decorator.top_height()) + ctx.translate(self.decorator.left_width(self), self.decorator.top_height(self)) ctx.rectangle(0,0,WIDTH,HEIGHT) ctx.set_source_rgb(204/255,204/255,204/255) ctx.fill() @@ -72,7 +72,7 @@ class ProgressBarWindow(yutani.Window): percent = int(100 * self.progress / self.total) self.tr.set_text(f"{percent}%") self.tr.resize(WIDTH-30,HEIGHT-self.text_offset) - self.tr.move(self.decorator.left_width() + 15,self.decorator.top_height()+self.text_offset) + self.tr.move(self.decorator.left_width(self) + 15,self.decorator.top_height(self)+self.text_offset) self.tr.draw(self) self.decorator.render(self) @@ -82,8 +82,8 @@ class ProgressBarWindow(yutani.Window): """Accept a resize.""" self.resize_accept(msg.width, msg.height) self.reinit() - self.int_width = msg.width - self.decorator.width() - self.int_height = msg.height - self.decorator.height() + self.int_width = msg.width - self.decorator.width(self) + self.int_height = msg.height - self.decorator.height(self) self.draw() self.resize_done() self.flip() @@ -92,8 +92,8 @@ class ProgressBarWindow(yutani.Window): if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE: window.close() sys.exit(0) - x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height() - w,h = self.width - self.decorator.width(), self.height - self.decorator.height() + x,y = msg.new_x - self.decorator.left_width(self), msg.new_y - self.decorator.top_height(self) + w,h = self.width - self.decorator.width(self), self.height - self.decorator.height(self) def keyboard_event(self, msg): pass diff --git a/userspace/py/lib/text_region.py b/util/python-demos/text_region.py similarity index 98% rename from userspace/py/lib/text_region.py rename to util/python-demos/text_region.py index dd34ac34..34663695 100644 --- a/userspace/py/lib/text_region.py +++ b/util/python-demos/text_region.py @@ -8,6 +8,12 @@ import os import cairo import toaru_fonts +import yutani + +def create_from_bmp(path): + if os.path.exists(path) and path.endswith('.bmp'): + return yutani.Sprite.from_file(path).get_cairo_surface() + return None _emoji_available = os.path.exists('/usr/share/emoji') @@ -417,7 +423,9 @@ class TextRegion(object): img = self.img_from_path(target) except: print(f"Failed to load image {target}, going to show backup image.") - img = self.img_from_path('/usr/share/icons/16/missing.png') + img = None + if not img: + img = self.img_from_path('/usr/share/icons/16/missing.bmp') chop = math.ceil(img.get_height() / tr.line_height) group = [] for i in range(chop): @@ -449,7 +457,7 @@ class TextRegion(object): def img_from_path(self, path): if not path in self.surface_cache: - s = cairo.ImageSurface.create_from_png(path) + s = create_from_bmp(path) self.surface_cache[path] = s return s else: diff --git a/userspace/py/lib/toaru_fonts.py b/util/python-demos/toaru_fonts.py similarity index 63% rename from userspace/py/lib/toaru_fonts.py rename to util/python-demos/toaru_fonts.py index 1b9adfa0..c44ee635 100644 --- a/userspace/py/lib/toaru_fonts.py +++ b/util/python-demos/toaru_fonts.py @@ -8,14 +8,14 @@ _cairo_module_lib = None _lib = None if not _lib: - _lib = ctypes.CDLL('libtoaru-shmemfonts.so') - _lib.init_shmemfonts() - _lib.draw_string_width.argtypes = [ctypes.c_char_p] - _lib.draw_string_width.restype = ctypes.c_uint32 - _lib.shmem_font_name.restype = ctypes.c_char_p - _lib.draw_string.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_uint32, ctypes.c_char_p] - _lib.draw_string_shadow.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_uint32, ctypes.c_char_p, ctypes.c_uint32, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_double] - _lib.get_active_font_face.restype = ctypes.c_void_p + _lib = ctypes.CDLL('libtoaru_ext_freetype_fonts.so') + #_lib.init_shmemfonts() # No init call in new library + _lib.freetype_draw_string_width.argtypes = [ctypes.c_char_p] + _lib.freetype_draw_string_width.restype = ctypes.c_uint32 + _lib.freetype_font_name.restype = ctypes.c_char_p + _lib.freetype_draw_string.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_uint32, ctypes.c_char_p] + _lib.freetype_draw_string_shadow.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_uint32, ctypes.c_char_p, ctypes.c_uint32, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_double] + _lib.freetype_get_active_font_face.restype = ctypes.c_void_p FONT_SANS_SERIF = 0 FONT_SANS_SERIF_BOLD = 1 @@ -29,7 +29,7 @@ FONT_JAPANESE = 8 FONT_SYMBOLA = 9 def get_active_font(): - return _lib.get_active_font_face() + return _lib.freetype_get_active_font_face() def get_cairo_face(): global _cairo_lib @@ -62,13 +62,13 @@ class Font(object): self.shadow = shadow def _use(self): - _lib.set_font_face(self.font_number) - _lib.set_font_size(self.font_size) + _lib.freetype_set_font_face(self.font_number) + _lib.freetype_set_font_size(self.font_size) def width(self, string): self._use() string = string.encode('utf-8') - return _lib.draw_string_width(string) + return _lib.freetype_draw_string_width(string) def write(self, ctx, x, y, string, shadow=None): if self.shadow: @@ -81,11 +81,12 @@ class Font(object): ctx = ctx._gfx if shadow: color, darkness, offset_x, offset_y, radius = shadow - _lib.draw_string_shadow(ctx,x,y,foreground,string,color,darkness,offset_x,offset_y,radius) + _lib.freetype_draw_string_shadow(ctx,x,y,foreground,string,color,darkness,offset_x,offset_y,radius) else: - _lib.draw_string(ctx,x,y,foreground,string) + _lib.freetype_draw_string(ctx,x,y,foreground,string) @property def name(self): - return _lib.shmem_font_name(self.font_number).decode('utf-8') + return _lib.freetype_font_name(self.font_number).decode('utf-8') + diff --git a/userspace/py/lib/toaru_theme.py b/util/python-demos/toaru_theme.py similarity index 100% rename from userspace/py/lib/toaru_theme.py rename to util/python-demos/toaru_theme.py diff --git a/userspace/py/bin/weather_tool.py b/util/python-demos/weather_tool.py similarity index 100% rename from userspace/py/bin/weather_tool.py rename to util/python-demos/weather_tool.py diff --git a/userspace/py/lib/yutani.py b/util/python-demos/yutani.py old mode 100644 new mode 100755 similarity index 85% rename from userspace/py/lib/yutani.py rename to util/python-demos/yutani.py index 560a3728..2f550fc2 --- a/userspace/py/lib/yutani.py +++ b/util/python-demos/yutani.py @@ -10,6 +10,7 @@ import importlib yutani_lib = None yutani_gfx_lib = None yutani_ctx = None +yutani_menu_lib = None yutani_windows = {} _cairo_lib = None @@ -329,12 +330,22 @@ class Yutani(object): global yutani_lib global yutani_ctx global yutani_gfx_lib - yutani_lib = CDLL("libtoaru-yutani.so") - yutani_gfx_lib = CDLL("libtoaru-graphics.so") + global yutani_menu_lib + if not yutani_lib: + yutani_lib = CDLL("libtoaru_yutani.so") + if not yutani_gfx_lib: + yutani_gfx_lib = CDLL("libtoaru_graphics.so") + if not yutani_menu_lib: + yutani_menu_lib = CDLL("libtoaru_menu.so") self._ptr = cast(yutani_lib.yutani_init(), POINTER(self._yutani_t)) + if not self._ptr: + raise ConnectionRefusedError("Could not connect to compositor.") yutani_ctx = self self._fileno = _libc.fileno(self._ptr.contents.sock) + def process_menus(self, event): + return yutani_menu_lib.menu_process_event(self._ptr, event._ptr) + def poll(self, sync=True): """Poll for an event message.""" if sync: @@ -445,6 +456,58 @@ class CursorType(object): RESIZE_UP_DOWN = 5 RESIZE_DOWN_UP = 6 +class Sprite(object): + class _sprite_t(Structure): + _fields_ = [ + ('width', c_uint16), + ('height', c_uint16), + ('bitmap', POINTER(c_char)), + ('masks', POINTER(c_char)), + ('blank', c_uint32), + ('alpha', c_uint8), + ] + + @property + def width(self): + return self._ptr.contents.width + + @property + def height(self): + return self._ptr.contents.height + + @property + def buffer(self): + return self._ptr.contents.bitmap + + def get_cairo_surface(self): + class Derp(object): + pass + self._gfx = Derp() + self._gfx.contents = Derp() + self._gfx.contents.backbuffer = self._ptr.contents.bitmap + self._cairo_surface = Window.get_cairo_surface(self) + return self._cairo_surface + + def from_file(path): + global yutani_gfx_lib + if not yutani_gfx_lib: + yutani_gfx_lib = CDLL("libtoaru_graphics.so") + s = Sprite() + s._contents = create_string_buffer(sizeof(Sprite._sprite_t)) + s._ptr = cast(addressof(s._contents), POINTER(Sprite._sprite_t)) + yutani_gfx_lib.load_sprite.argtypes = [c_void_p, c_char_p] + yutani_gfx_lib.load_sprite(s._ptr, path.encode('utf-8')) + return s + + def create(width, height): + s = Sprite() + s._ptr = yutani_gfx_lib.create_sprite(width, height) + return s + + def free(self): + yutani_gfx_lib.sprite_free(self._ptr) + + class GraphicsBuffer(object): """Generic buffer for rendering.""" @@ -477,6 +540,11 @@ class Window(object): ("bufid", c_uint32), ("focused", c_uint8), ("oldbufid", c_uint32), + ("userdata", c_void_p), + ("x", c_int32), + ("y", c_int32), + ("decorator_flags", c_uint32), + ("ctx", c_void_p), ] class _gfx_context_t(Structure): @@ -612,6 +680,14 @@ class Window(object): """Begin window drag.""" yutani_lib.yutani_window_drag_start(yutani_ctx._ptr, self._ptr) + @property + def x(self): + return self._ptr.contents.x + + @property + def y(self): + return self._ptr.contents.y + @property def width(self): return self._ptr.contents.width @@ -642,34 +718,62 @@ class Decor(object): EVENT_OTHER = 1 EVENT_CLOSE = 2 EVENT_RESIZE = 3 + EVENT_MAXIMIZE = 4 + EVENT_RIGHT = 5 + + class decor_bound(Structure): + _fields_ = [ + ("top_height", c_int), + ("bottom_height", c_int), + ("left_width", c_int), + ("right_width", c_int), + ("width", c_int), + ("height", c_int), + ] def __init__(self): - self.lib = CDLL("libtoaru-decorations.so") + self.lib = CDLL("libtoaru_decorations.so") self.lib.init_decorations() + self._bounds = self.decor_bound() - def width(self): + self._decor_get_bounds = cast(c_void_p.in_dll(self.lib, "decor_get_bounds").value, CFUNCTYPE(c_int, c_void_p, c_void_p)) + + def _get_bounds(self, window): + self._decor_get_bounds(window._ptr if window else None, byref(self._bounds)) + + def bounds(self,window=None): + self._get_bounds(window) + return self._bounds + + def width(self,window=None): """The complete width of the left and right window borders.""" - return int(self.lib.decor_width()) + self._get_bounds(window) + return int(self._bounds.width) - def height(self): + def height(self,window=None): """The complete height of the top and bottom window borders.""" - return int(self.lib.decor_height()) + self._get_bounds(window) + return int(self._bounds.height) - def top_height(self): + def top_height(self,window=None): """The height of the top edge of the decorations.""" - return c_uint32.in_dll(self.lib, "decor_top_height").value + self._get_bounds(window) + return int(self._bounds.top_height) - def bottom_height(self): + def bottom_height(self,window=None): """The height of the bottom edge of the decorations.""" - return c_uint32.in_dll(self.lib, "decor_bottom_height").value + self._get_bounds(window) + return int(self._bounds.bottom_height) - def left_width(self): + def left_width(self,window=None): """The width of the left edge of the decorations.""" - return c_uint32.in_dll(self.lib, "decor_left_width").value + self._get_bounds(window) + return int(self._bounds.left_width) - def right_width(self): + def right_width(self,window=None): """The width of the right edge of the decorations.""" - return c_uint32.in_dll(self.lib, "decor_right_width").value + self._get_bounds(window) + return int(self._bounds.right_width) def render(self, window, title=None): """Render decorations on this window. If a title is not provided, it will be retreived from the window object.""" @@ -682,6 +786,9 @@ class Decor(object): """Let the decorator library handle an event. Usually passed mouse events.""" return self.lib.decor_handle_event(yutani_ctx._ptr, msg._ptr) + def show_menu(self, window, event): + self.lib.decor_show_default_menu(window._ptr, window.x + event.new_x, window.y + event.new_y) + # Demo follows. if __name__ == '__main__': # Connect to the server. @@ -691,15 +798,15 @@ if __name__ == '__main__': d = Decor() # Create a new window. - w = Window(200+d.width(),200+d.height(),title="Python Demo") + w = Window(300+d.width(),300+d.height(),title="Python Demo") # Since this is Python, we can attach data to our window, such # as its internal width (excluding the decorations). - w.int_width = 200 - w.int_height = 200 + w.int_width = 300 + w.int_height = 300 # We can set window shaping... - w.update_shape(WindowShape.THRESHOLD_HALF) + #w.update_shape(WindowShape.THRESHOLD_HALF) # Move the window... w.move(100, 100) diff --git a/userspace/py/lib/yutani_mainloop.py b/util/python-demos/yutani_mainloop.py similarity index 91% rename from userspace/py/lib/yutani_mainloop.py rename to util/python-demos/yutani_mainloop.py index 4628e46e..b6fc94fa 100644 --- a/userspace/py/lib/yutani_mainloop.py +++ b/util/python-demos/yutani_mainloop.py @@ -5,6 +5,12 @@ def handle_event(msg): if msg.type == yutani.Message.MSG_SESSION_END: msg.free() return False + elif msg.type == yutani.Message.MSG_WINDOW_CLOSE: + # TODO should actually send a close signal to the window + msg.free() + return False + elif yutani.yutani_ctx.process_menus(msg): + return True elif msg.type == yutani.Message.MSG_KEY_EVENT: if msg.wid in yutani.yutani_windows: yutani.yutani_windows[msg.wid].keyboard_event(msg) @@ -33,9 +39,6 @@ def handle_event(msg): window = yutani.yutani_windows[msg.wid] if 'window_moved' in dir(window): window.window_moved(msg) - else: - window.x = msg.x - window.y = msg.y elif msg.type == yutani.Message.MSG_WINDOW_MOUSE_EVENT: if msg.wid in yutani.yutani_windows: window = yutani.yutani_windows[msg.wid] diff --git a/util/qemu-harness.py b/util/qemu-harness.py index 1b5099eb..d6aa5186 100755 --- a/util/qemu-harness.py +++ b/util/qemu-harness.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 """ Harness for running QEMU and communicating window sizes through serial. """ @@ -17,13 +17,24 @@ qemu_bin = 'qemu-system-i386' qemu = subprocess.Popen([ qemu_bin, - '-M','accel=kvm:tcg', - '-cdrom','toaruos.iso', - '-vga','std', + '-enable-kvm', + '-cdrom','image.iso', + # 1GB of RAM '-m','1G', - '-soundhw','ac97', + # Enable audio + '-soundhw','ac97,pcspk', + # The GTK interface does not play well, force SDL '-display', 'sdl', - '-serial','tcp::4444,server,nowait' + # /dev/ttyS0 is stdio multiplexed with monitor + '-serial', 'mon:stdio', + # /dev/ttyS1 is TCP connection to the harness + '-serial','tcp::4444,server,nowait', + # Add a VGA card with 32mb of video RAM + '-device', 'VGA,id=video0,vgamem_mb=32', + # Set the fwcfg flag so our userspace app recognizes us + '-fw_cfg','name=opt/org.toaruos.displayharness,string=1', + # Boot directly to graphical mode + '-fw_cfg','name=opt/org.toaruos.bootmode,string=normal' ]) # Give QEMU some time to start up and create a window. @@ -96,7 +107,6 @@ async def heartbeat(transport): asyncio.get_event_loop().call_soon(sys.exit, 0) return if g.width != w or g.height != h: - print("Changed:",g.width,g.height) transport.write(("geometry-changed %d %d\n" % (g.width,g.height)).encode('utf-8')) w = g.width h = g.height diff --git a/util/qemu.sh b/util/qemu.sh new file mode 100644 index 00000000..7911e830 --- /dev/null +++ b/util/qemu.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +qemu-system-x86_64 \ +-kernel fatbase/kernel \ +-initrd \ +fatbase/mod/zero.ko,\ +fatbase/mod/random.ko,\ +fatbase/mod/serial.ko,\ +fatbase/mod/debug_sh.ko,\ +fatbase/mod/procfs.ko,\ +fatbase/mod/tmpfs.ko,\ +fatbase/mod/ata.ko,\ +fatbase/mod/ext2.ko,\ +fatbase/mod/ps2kbd.ko,\ +fatbase/mod/ps2mouse.ko,\ +fatbase/mod/lfbvideo.ko,\ +fatbase/mod/vbox.ko,\ +fatbase/mod/vmware.ko,\ +fatbase/mod/vidset.ko,\ +fatbase/mod/packetfs.ko,\ +fatbase/mod/snd.ko,\ +fatbase/mod/ac97.ko,\ +fatbase/mod/net.ko,\ +fatbase/mod/pcnet.ko,\ +fatbase/mod/rtl.ko,\ +fatbase/mod/e1000.ko,\ +fatbase/mod/pcspkr.ko \ +-append "root=/dev/hda start=--headless" \ +-nographic \ +-no-reboot \ +-hda fatbase/ramdisk.img \ +-enable-kvm \ +-serial mon:stdio \ +-m 1G -soundhw ac97,pcspk + diff --git a/userspace/py/lib/readline.py b/util/readline._py similarity index 94% rename from userspace/py/lib/readline.py rename to util/readline._py index 604742f1..5225d32b 100644 --- a/userspace/py/lib/readline.py +++ b/util/readline._py @@ -3,10 +3,10 @@ import ctypes auto_history = True py = ctypes.CDLL("libpython3.6m.so") -rline_lib = ctypes.CDLL("libtoaru-rline.so") +rline_lib = ctypes.CDLL("libtoaru_rline_exp.so") readline_func = ctypes.c_void_p.in_dll(py,"PyOS_ReadlineFunctionPointer") -t = ctypes.c_char_p.in_dll(rline_lib,"rline_for_python") +t = ctypes.c_char_p.in_dll(rline_lib,"rline_exp_for_python") readline_func.value = ctypes.addressof(t) # Change exit string to "exit()" diff --git a/util/run-virtualbox-cdrom.sh b/util/run-virtualbox-cdrom.sh deleted file mode 100755 index be101100..00000000 --- a/util/run-virtualbox-cdrom.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# Initialize a VirtualBox VM pointing towards a dev hard disk, with grub from a piggyback CD. - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -cd $DIR/.. - -VMNAME="ToaruOS CD" - -echo -e "\e[1;32m>>> Creating virtual machine...\e[0m" -VBoxManage unregistervm "$VMNAME" --delete -VBoxManage createvm --name "$VMNAME" --ostype "Other" --register -VBoxManage modifyvm "$VMNAME" --memory 1024 --audio pulse --audiocontroller ac97 -VBoxManage storagectl "$VMNAME" --add ide --name "IDE" -VBoxManage storageattach "$VMNAME" --storagectl "IDE" --port 0 --device 0 --medium `pwd`/toaruos.iso --type dvddrive - -echo -e "\e[1;32m>>> Starting virtual machine...\e[0m" -VBoxManage startvm "$VMNAME" - -echo -e "\e[1;32m>>> Waiting for virtual machine to shut down...\e[0m" -# Wait for VM to shut down -until $(VBoxManage showvminfo --machinereadable "$VMNAME" | grep -q ^VMState=.poweroff.) -do - sleep 1 -done - -echo -e "\e[1;32m>>> Cleaning up...\e[0m" - -sleep 1 -# Clean up -VBoxManage unregistervm "$VMNAME" --delete # This also removes the vmdk we made - - diff --git a/util/run-virtualbox.sh b/util/run-virtualbox.sh deleted file mode 100755 index f435b575..00000000 --- a/util/run-virtualbox.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash -# Initialize a VirtualBox VM pointing towards a dev hard disk, with grub from a piggyback CD. - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -cd $DIR/.. - -VMNAME="ToaruOS Dev HDD" - - -echo -e "\e[1;32m>>> Generating bootstrap CD...\e[0m" -# Copy the CD directory like we do when building a normal CD -rm -rf vbox-cdrom -mkdir vbox-cdrom -mkdir vbox-cdrom/boot -mkdir vbox-cdrom/boot/grub -cat > vbox-cdrom/boot/grub/grub.cfg <>> Creating virtual machine...\e[0m" -VBoxManage unregistervm "$VMNAME" --delete -VBoxManage internalcommands createrawvmdk -filename vbox-disk.vmdk -rawdisk $DIR/../toaruos-disk.img -VBoxManage createvm --name "$VMNAME" --ostype "Other" --register -VBoxManage modifyvm "$VMNAME" --memory 1024 --audio pulse --audiocontroller ac97 -VBoxManage storagectl "$VMNAME" --add ide --name "IDE" -VBoxManage storageattach "$VMNAME" --storagectl "IDE" --port 0 --device 0 --medium `pwd`/vbox-disk.vmdk --type hdd -VBoxManage storageattach "$VMNAME" --storagectl "IDE" --port 1 --device 0 --medium `pwd`/vbox-boot.iso --type dvddrive - -echo -e "\e[1;32m>>> Starting virtual machine...\e[0m" -VBoxManage startvm "$VMNAME" - -echo -e "\e[1;32m>>> Waiting for virtual machine to shut down...\e[0m" -# Wait for VM to shut down -until $(VBoxManage showvminfo --machinereadable "$VMNAME" | grep -q ^VMState=.poweroff.) -do - sleep 1 -done - -echo -e "\e[1;32m>>> Cleaning up...\e[0m" - -sleep 1 -# Clean up -VBoxManage unregistervm "$VMNAME" --delete # This also removes the vmdk we made -rm vbox-boot.iso - - diff --git a/util/test-travis.exp b/util/test-travis.exp deleted file mode 100644 index 568fd529..00000000 --- a/util/test-travis.exp +++ /dev/null @@ -1,44 +0,0 @@ - -# Start qemu -spawn qemu-system-i386 -kernel toaruos-kernel -m 512 -serial stdio -hda toaruos-disk.img -k en-us -rtc base=localtime -net nic,model=rtl8139 -net user -initrd "hdd/mod/zero.ko,hdd/mod/random.ko,hdd/mod/serial.ko,hdd/mod/procfs.ko,hdd/mod/tmpfs.ko,hdd/mod/ata.ko,hdd/mod/ext2.ko,hdd/mod/debug_shell.ko,hdd/mod/ps2mouse.ko,hdd/mod/ps2kbd.ko,hdd/mod/lfbvideo.ko,hdd/mod/packetfs.ko" -display none -append "start=--vga root=/dev/hda" -no-reboot -no-kvm - -set send_slow { 1 0.001 } - -sleep 0.1 - -expect "toaru-" - -sleep 1 - -send -s "shell\n" -expect "toaru-test" - -send -s "export PATH=/bin:/usr/bin\n" -expect "toaru-test" - -send -s "uname -a\n" -expect "strawberry" -expect "toaru-test" - -send -s "ls /dev\n" -expect "mouse" -expect "toaru-test" - -send -s "cat /proc/meminfo\n" -expect "MemTotal" -expect "toaru-test" - -send -s "cd /tmp\n" -expect "toaru-test" - -send -s "test-write test.c \"#include \nint main(int argc, char * argv[]) {\n printf(\\\"Hello world!\\n\\\");\n return 0;\n}\n\"\n" -expect "wrote 99 bytes" -expect "toaru-test" - -send -s "cat test.c\n" -expect "Hello" -expect "toaru-test" - -# And halt -send -s "reboot\n" -expect "eof" diff --git a/util/test.exp b/util/test.exp deleted file mode 100644 index a90f90f3..00000000 --- a/util/test.exp +++ /dev/null @@ -1,49 +0,0 @@ - -# Start qemu -spawn qemu-system-i386 -kernel toaruos-kernel -m 512 -serial stdio -hda toaruos-disk.img -k en-us -rtc base=localtime -net nic,model=rtl8139 -net user --initrd "hdd/mod/zero.ko,hdd/mod/random.ko,hdd/mod/serial.ko,hdd/mod/procfs.ko,hdd/mod/tmpfs.ko,hdd/mod/ata.ko,hdd/mod/ext2.ko,hdd/mod/debug_shell.ko,hdd/mod/ps2mouse.ko,hdd/mod/ps2kbd.ko,hdd/mod/lfbvideo.ko,hdd/mod/packetfs.ko" -display none -append "start=--vga root=/dev/hda" -no-reboot - -set send_slow { 1 0.001 } - -expect "toaru-" - -sleep 0.1 - -send -s "shell\n" -expect "toaru-test" - -send -s "export PATH=/bin:/usr/bin\n" -expect "toaru-test" - -send -s "uname -a\n" -expect "strawberry" -expect "toaru-test" - -send -s "ls /dev\n" -expect "mouse" -expect "toaru-test" - -send -s "cat /proc/meminfo\n" -expect "MemTotal" -expect "toaru-test" - -send -s "cd /tmp\n" -expect "toaru-test" - -send -s "test-write test.c \"#include \nint main(int argc, char * argv[]) {\n printf(\\\"Hello world!\\n\\\");\n return 0;\n}\n\"\n" -expect "wrote 99 bytes" -expect "toaru-test" - -send -s "cat test.c\n" -expect "Hello" -expect "toaru-test" - -send -s "gcc -o test test.c\n" -expect "toaru-test" - -send -s "./test\n" -expect "Hello world" -expect "toaru-test" - -# And halt -send -s "reboot\n" -expect "eof" diff --git a/util/toaru-vga.tic b/util/toaru-vga.tic deleted file mode 100644 index d1954f0b..00000000 Binary files a/util/toaru-vga.tic and /dev/null differ diff --git a/util/toaru.terminfo b/util/toaru.terminfo deleted file mode 100644 index 577727f1..00000000 --- a/util/toaru.terminfo +++ /dev/null @@ -1,89 +0,0 @@ -toaru|toaru terminal, - mc5i, - xenl, - km, - mir, - msgr, - cols#80, lines#24, - colors#256, it#8, ncv#18, pairs#32767, npc, am, - ind=^J, cr=^M, - nel=^J, ht=^I, - cud1=^J, - cuf1=\E[C, - cuu1=\E[A, - cub1=^H, - home=\E[H, clear=\E[H\E[2J, - hpa=\E[%i%p1%dG, - cup=\E[%i%p1%d;%p2%dH, - ed=\E[J, el=\E[K, - setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, - setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, - setb@, - setf@, - rev=\E[7m, sgr0=\E[0m, - smso=\E[7m, rmso=\E[m, - sgr=\E[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;11%;m, - op=\E[39;49m, - bold=\E[1m, - kcuu1=\E[A, - kcud1=\E[B, - kcuf1=\E[C, - kcub1=\E[D, - kent=\E0M, - cuu=\E[%p1%dA, - cud=\E[%p1%dB, - cuf=\E[%p1%dC, - cub=\E[%p1%dD, - indn=\E[%p1%dS, - rin=\E[%p1%dT, - ri=\E[T, - sc=\E[s, - rc=\E[u, - knp=\E[6~, - kpp=\E[5~, - kf1=\EOP, - kf2=\EOQ, - kf3=\EOR, - kf4=\EOS, - kf5=\E[15~, - kf6=\E[17~, - kf7=\E[18~, - kf8=\E[19~, - kf9=\E[20~, - kf10=\E[21~, - kf11=\E[23~, - kf12=\E[24~, - kcbt=\E[Z, - kdch1=\E[3~, - kend=\EOF, - khome=\EOH, - kich1=\E[2~, - kUP=\E[2A, - kUP3=\E[3A, - kUP4=\E[4A, - kUP5=\E[5A, - kUP6=\E[6A, - kUP7=\E[7A, - kDN=\E[2B, - kDN3=\E[3B, - kDN4=\E[4B, - kDN5=\E[5B, - kDN6=\E[6B, - kDN7=\E[7B, - kRIT=\E[2C, - kRIT3=\E[3C, - kRIT4=\E[4C, - kRIT5=\E[5C, - kRIT6=\E[6C, - kRIT7=\E[7C, - kLFT=\E[2D, - kLFT3=\E[3D, - kLFT4=\E[4D, - kLFT5=\E[5D, - kLFT6=\E[6D, - kLFT7=\E[7D, - -toaru-vga|toaru vga terminal, - use=toaru, - colors#8, - diff --git a/util/toaru.tic b/util/toaru.tic deleted file mode 100644 index 51a402f0..00000000 Binary files a/util/toaru.tic and /dev/null differ diff --git a/util/update-devtable.py b/util/update-devtable.py new file mode 100755 index 00000000..bd71d271 --- /dev/null +++ b/util/update-devtable.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +import os +from pathlib import Path + +def getPaths(base): + out = [] + for root, dirs, files in os.walk(base): + for i in dirs: + out.append(os.path.join(root,i)) + for i in files: + out.append(os.path.join(root,i)) + return out + +with open('util/devtable','w') as devtable: + + # Set sudo apps to setuid, executable, no write + devtable.write('/bin/gsudo f 4555 0 0 - - - - -\n') + devtable.write('/bin/sudo f 4555 0 0 - - - - -\n') + + # Set master.passwd to not be visible except by root + devtable.write('/etc/master.passwd f 600 0 0 - - - - -\n') # /etc/master.passwd should be restricted + + # Copy permissions and set ownership for user files + for user_details in [('local',1000)]: + user, uid = user_details + for path in getPaths('./base/home/{user}'.format(user=user)): + p = Path(path) + path_mod = path.replace('./base','').rstrip('/') + path_type = 'd' if p.is_dir() else 'f' + st = os.stat(path) + mode = '{:o}'.format(st.st_mode & 0o7777) + devtable.write('{path_mod} {path_type} {mode} {uid} {uid} - - - - -\n'.format(path_mod=path_mod,path_type=path_type,mode=mode,uid=uid)) + + # Special case /tmp to allow all users to write + devtable.write('/tmp d 777 0 0 - - - - -\n') + diff --git a/util/update-extents.py b/util/update-extents.py new file mode 100755 index 00000000..f79ab9c1 --- /dev/null +++ b/util/update-extents.py @@ -0,0 +1,303 @@ +#!/usr/bin/env python3 +import array +import struct + +def read_struct(fmt,buf,offset): + out, = struct.unpack_from(fmt,buf,offset) + return out, offset + struct.calcsize(fmt) + +class ISO(object): + + def __init__(self, path): + with open(path, 'rb') as f: + tmp = f.read() + self.data = array.array('b', tmp) + self.sector_size = 2048 + o = 0x10 * self.sector_size + self.type, o = read_struct('B',self.data,o) + self.id, o = read_struct('5s',self.data,o) + self.version, o = read_struct('B',self.data,o) + _unused0, o = read_struct('B',self.data,o) + self.system_id, o = read_struct('32s',self.data,o) + self.volume_id, o = read_struct('32s',self.data,o) + _unused1, o = read_struct('8s',self.data,o) + self.volume_space_lsb, o = read_struct('I',self.data,o) + _unused2, o = read_struct('32s',self.data,o) + self.volume_set_lsb, o = read_struct('H',self.data,o) + self.volume_seq_lsb, o = read_struct('H',self.data,o) + self.logical_block_size_lsb, o = read_struct('H',self.data,o) + self.path_table_size_lsb, o = read_struct('I',self.data,o) + self.path_table_lsb, o = read_struct('I',self.data,o) + self.optional_path_table_msb, o = read_struct('>I',self.data,o) + _offset = o + self.root_dir_entry, o = read_struct('34s',self.data,o) + + self.root = ISOFile(self,_offset) + self._cache = {} + + def get_file(self, path): + if path == '/': + return self.root + else: + if path in self._cache: + return self._cache[path] + units = path.split('/') + units = units[1:] # remove root + me = self.root + for i in units: + next_file = me.find(i) + if not next_file: + me = None + break + else: + me = next_file + self._cache[path] = me + return me + +class ISOFile(object): + + def __init__(self, iso, offset): + self.iso = iso + self.offset = offset + + o = offset + self.length, o = read_struct('B', self.iso.data, o) + if not self.length: + return + self.ext_length, o = read_struct('B', self.iso.data, o) + self.extent_start_lsb, o = read_struct('I',self.iso.data, o) + self.extent_length_lsb, o = read_struct('I',self.iso.data, o) + + self.date_data, o = read_struct('7s', self.iso.data, o) + + self.flags, o = read_struct('b', self.iso.data, o) + self.interleave_units, o = read_struct('b', self.iso.data, o) + self.interleave_gap, o = read_struct('b', self.iso.data, o) + + self.volume_seq_lsb, o = read_struct('H',self.iso.data, o) + + self.name_len, o = read_struct('b', self.iso.data, o) + self.name, o = read_struct('{}s'.format(self.name_len), self.iso.data, o) + self.name = self.name.decode('ascii') + + def write_extents(self): + struct.pack_into('I', self.iso.data, self.offset + 6, self.extent_start_lsb) + struct.pack_into('I', self.iso.data, self.offset + 14, self.extent_length_lsb) + + def readable_name(self): + if not ';' in self.name: + return self.name.lower() + else: + tmp, _ = self.name.split(';') + return tmp.lower() + + + def list(self): + sectors = self.iso.data[self.extent_start_lsb * self.iso.sector_size: self.extent_start_lsb * self.iso.sector_size+ 3 * self.iso.sector_size] + offset = 0 + + while 1: + f = ISOFile(self.iso, self.extent_start_lsb * self.iso.sector_size + offset) + yield f + offset += f.length + if not f.length: + break + + def find(self, name): + sectors = self.iso.data[self.extent_start_lsb * self.iso.sector_size: self.extent_start_lsb * self.iso.sector_size+ 3 * self.iso.sector_size] + offset = 0 + if '.' in name and len(name.split('.')[0]) > 8: + a, b = name.split('.') + name = a[:8] + '.' + b + if '-' in name: + name = name.replace('-','_') + while 1: + f = ISOFile(self.iso, self.extent_start_lsb * self.iso.sector_size + offset) + if not f.length: + if offset < self.extent_length_lsb: + offset += 1 + continue + else: + break + if ';' in f.name: + tmp, _ = f.name.split(';') + if tmp.endswith('.'): + tmp = tmp[:-1] + if tmp.lower() == name.lower(): + return f + elif f.name.lower() == name.lower(): + return f + offset += f.length + return None + +class FAT(object): + + def __init__(self, iso, offset): + self.iso = iso + self.offset = offset + + self.bytespersector, _ = read_struct('H', self.iso.data, offset + 11) + self.sectorspercluster, _ = read_struct('B', self.iso.data, offset + 13) + self.reservedsectors, _ = read_struct('H', self.iso.data, offset + 14) + self.numberoffats, _ = read_struct('B', self.iso.data, offset + 16) + self.numberofdirs, _ = read_struct('H', self.iso.data, offset + 17) + self.fatsize, _ = read_struct('H', self.iso.data, offset + 22) + + self.root_dir_sectors = (self.numberofdirs * 32 + (self.bytespersector - 1)) // self.bytespersector + self.first_data_sector = self.reservedsectors + (self.numberoffats * self.fatsize) + self.root_dir_sectors + self.root_sector= self.first_data_sector - self.root_dir_sectors + self.root = FATDirectory(self, self.offset + self.root_sector * self.bytespersector) + + def get_offset(self, cluster): + return self.offset + ((cluster - 2) * self.sectorspercluster + self.first_data_sector) * self.bytespersector + + def get_file(self, path): + units = path.split('/') + units = units[1:] + + me = self.root + out = None + for i in units: + for fatfile in me.list(): + if fatfile.readable_name() == i: + me = fatfile.to_dir() + out = fatfile + break + else: + return None + return out + +class FATDirectory(object): + + def __init__(self, fat, offset): + + self.fat = fat + self.offset = offset + + def list(self): + + o = self.offset + while 1: + out = FATFile(self.fat, o) + if out.name != '\0\0\0\0\0\0\0\0': + yield out + else: + break + o += out.size + + +class FATFile(object): + + def __init__(self, fat, offset): + + self.fat = fat + self.offset = offset + self.magic_long = None + self.size = 0 + self.long_name = '' + + o = self.offset + self.actual_offset = o + + self.attrib, _ = read_struct('B',self.fat.iso.data,o+11) + + while (self.attrib & 0x0F) == 0x0F: + # Long file name entry + tmp = read_struct('10s',self.fat.iso.data,o+1)[0] + tmp += read_struct('12s',self.fat.iso.data,o+14)[0] + tmp += read_struct('4s',self.fat.iso.data,o+28)[0] + tmp = "".join([x for x in tmp[::2] if x != '\xFF']).strip('\x00') + self.long_name = tmp + self.long_name + self.size += 32 + o = self.offset + self.size + self.actual_offset = o + self.attrib, _ = read_struct('B',self.fat.iso.data,o+11) + + o = self.offset + self.size + + self.name, o = read_struct('8s',self.fat.iso.data,o) + self.ext, o = read_struct('3s',self.fat.iso.data,o) + self.attrib, o = read_struct('B',self.fat.iso.data,o) + self.userattrib, o = read_struct('B',self.fat.iso.data,o) + self.undelete, o = read_struct('b',self.fat.iso.data,o) + self.createtime, o = read_struct('H',self.fat.iso.data,o) + self.createdate, o = read_struct('H',self.fat.iso.data,o) + self.accessdate, o = read_struct('H',self.fat.iso.data,o) + self.clusterhi, o = read_struct('H',self.fat.iso.data,o) + self.modifiedti, o = read_struct('H',self.fat.iso.data,o) + self.modifiedda, o = read_struct('H',self.fat.iso.data,o) + self.clusterlow, o = read_struct('H',self.fat.iso.data,o) + self.filesize, o = read_struct('I',self.fat.iso.data,o) + + self.name = self.name.decode('ascii') + self.ext = self.ext.decode('ascii') + + self.size += 32 + + self.cluster = (self.clusterhi << 16) + self.clusterlow + + def is_dir(self): + return bool(self.attrib & 0x10) + + def is_long(self): + return bool((self.attrib & 0x0F) == 0x0F) + + def to_dir(self): + return FATDirectory(self.fat, self.fat.get_offset(self.cluster)) + + def get_offset(self): + return self.fat.get_offset(self.cluster) + + def readable_name(self): + if self.long_name: + return self.long_name + if self.ext.strip(): + return (self.name.strip() + '.' + self.ext.strip()).lower() + else: + return self.name.strip().lower() + + +image = ISO('image.iso') +fat = image.root.find('FAT.IMG') + +fatfs = FAT(image, fat.extent_start_lsb * image.sector_size) + +def process(fatfile, path): + if fatfile.is_long(): + return + if fatfile.readable_name() == '.': + return + if fatfile.readable_name() == '..': + return + if fatfile.is_dir(): + for i in fatfile.to_dir().list(): + process(i, path + fatfile.readable_name() + '/') + else: + cdfile = image.get_file(path + fatfile.readable_name()) + if not cdfile: + if fatfile.readable_name() != 'bootia32.efi' and fatfile.readable_name() != 'bootx64.efi': + print("Warning:", fatfile.readable_name(), "not found in ISO") + else: + cdfile.extent_start_lsb = fatfile.get_offset() // 2048 + cdfile.extent_length_lsb = fatfile.filesize + cdfile.write_extents() + + +for i in fatfs.root.list(): + process(i,'/') + +with open('image.iso','wb') as f: + f.write(image.data) + diff --git a/util/vimhints.sh b/util/vimhints.sh deleted file mode 100755 index c6be9439..00000000 --- a/util/vimhints.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -for f in $(find kernel modules | fgrep '.c'); do - echo -n "Looking at '$f'... " - - if ! grep -q "vim:" $f; then - echo "needs vimhints... " - - header=$(mktemp) - echo "/* vim: tabstop=4 shiftwidth=4 noexpandtab" >> $header - echo "*/" >> $header - tmpfile=$(mktemp) - cat "$header" "$f" > "$tmpfile" - mv "$tmpfile" "$f" - - rm $header - else - echo "-- already has vimhints" - fi -done