diff options
170 files changed, 2474 insertions, 13098 deletions
diff --git a/.bazel/compiler_flags.bazelrc b/.bazel/compiler_flags.bazelrc new file mode 100644 index 0000000..2b2e5d1 --- /dev/null +++ b/.bazel/compiler_flags.bazelrc @@ -0,0 +1,28 @@ +build --copt=-Wall +build --copt=-Wextra +build --copt=-Wpedantic +build --copt=-Werror=shadow +build --copt=-Wunused-parameter +build --copt=-Wmisleading-indentation +build --copt=-Wundef +build --copt=-Wuninitialized + +# cast warnings +build --copt=-Wcast-align +build --copt=-Wcast-qual + +# conversion +build --copt=-Wconversion +build --copt=-Wsign-conversion +build --copt=-Wdouble-promotion + +# pointers +build --copt=-Wpointer-arith +build --copt=-Wnull-dereference + +# cpp flags +build --cxxopt=-std=c++20 +build --cxxopt=-Wnon-virtual-dtor +build --cxxopt=-Woverloaded-virtual +build --cxxopt=-Wold-style-cast + diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 0000000..c6094bc --- /dev/null +++ b/.bazelignore @@ -0,0 +1 @@ +tools/interface_generator diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..2a0a947 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,11 @@ +# compiler flags +try-import %workspace%/.bazel/compiler_flags.bazelrc + +build --instrument_test_targets + +build:i386 --compilation_mode=opt +build:i386 --platforms=//platforms:i386 + +coverage --combined_report=lcov + +test --compilation_mode=dbg diff --git a/.config b/.config deleted file mode 100644 index e04ec16..0000000 --- a/.config +++ /dev/null @@ -1,27 +0,0 @@ -# -# Automatically generated file; DO NOT EDIT. -# Main menu -# - -# -# Toolchain -# -CONFIG_CFLAGS="-g -Og" -CONFIG_CXXFLAGS="-g -Og" -CONFIG_LDFLAGS="" -# end of Toolchain - -# -# Target -# -CONFIG_ARCH_i686=y -# end of Target - -# -# Devices -# -CONFIG_PIC_8259=y -CONFIG_UART_16550=y -CONFIG_VGA_TEXT_MODE=y -CONFIG_KB_PS2=y -# end of Devices @@ -1,13 +1,2 @@ -lib/musl* -build* -*.d -*.o -*.a -*.elf -*.iso -isodir -src/conf.h -.config.old -test_* -doc -include/ +bazel-* + diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 0000000..9c05b27 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,13 @@ +load("//tools:make_iso.bzl", "make_iso") +load("//tools:qemu.bzl", "qemu") + +make_iso( + name = "glitch", + bootloader = "//grub:grub.cfg", + kernel = "//kernel:glitch.elf", +) + +qemu( + name = "qemu", + cdrom = ":glitch", +) @@ -1,4 +1,18 @@ menu "Toolchain" + choice + prompt "Target architecture" + config ARCH_i686 + bool "i686" + config ARCH_mips + bool "mips" + endchoice + choice + prompt "Toolchain" + config TOOLCHAIN_i686_gcc + bool "i686-elf-gcc" + depends on ARCH_i686 + endchoice + config CFLAGS string "Additional C compiler flags" config CXXFLAGS @@ -7,14 +21,6 @@ menu "Toolchain" string "Additional linker flags" endmenu -menu "Target" - choice - prompt "Target architecture" - config ARCH_i686 - bool "i686" - endchoice -endmenu - menu "Devices" config PIC_8259 bool "PIC 8259" diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..fbf1ad8 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,12 @@ +############################################################################### +# Bazel now uses Bzlmod by default to manage external dependencies. +# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel. +# +# For more details, please check https://github.com/bazelbuild/bazel/issues/18958 +############################################################################### + +register_toolchains( + "//toolchains:i386_elf_gcc", +) + +bazel_dep(name = "googletest", version = "1.14.0") diff --git a/Makefile b/Makefile deleted file mode 100644 index 33b5f76..0000000 --- a/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# ===================================================================== -# spdx-license-identifier: ISC -# glitch top-level makefile -# ===================================================================== - -MAKE := make -MAKEID := $(shell ${MAKE} --version | head -n1) -MAKEFLAGS += -rR --no-print-directory - -ARCH := $(shell sed -nE "s/CONFIG_ARCH_(.+)=y/\1/p" .config) - -.PHONY: all help info run doc clean test valgrind -all: Makefile.config - @${MAKE} -f Makefile.all - -help: - @echo "info: show current configuration" - @echo "all: build kernel image" - @echo "run: run kernel image in qemu" - @echo "test: run all tests" - @echo "valgrind: run all tests in valgrind" - -info: Makefile.config - @echo "- make:" - @echo " MAKE: ${MAKE}" - @echo " MAKEID: ${MAKEID}" - @echo " MAKEFLAGS: ${MAKEFLAGS}" - @${MAKE} -f Makefile.all $@ - -run: Makefile.config - @${MAKE} -f Makefile.all $@ - -doc: doxygen.config - doxygen $< - -clean: - @${MAKE} -C lib clean - @${MAKE} -C ${ARCH} clean - @${MAKE} -C devices clean - @${MAKE} -C src clean - -test: - @echo " -> Running tests in src" - @make -C src test > /dev/null - @echo " -> Running tests in lib" - @make -C lib test > /dev/null - -valgrind: - @echo " -> Running valgrind on tests in lib" - @make -C lib valgrind &> /dev/null - @echo " -> Running valgrind on tests in src" - @make -C src valgrind &> /dev/null - -# configure targets -.config: Kconfig - @alldefconfig - -Makefile.config: .config ${ARCH}/toolchain.mk - @echo -e '## This is a generated file, manual edits might be lost' > Makefile.config - @echo -e '\n## .config' >> Makefile.config - @cat .config >> Makefile.config - @echo -e '\n## toolchain.mk' >> Makefile.config - @cat ${ARCH}/toolchain.mk >> Makefile.config - diff --git a/Makefile.all b/Makefile.all deleted file mode 100644 index a92631f..0000000 --- a/Makefile.all +++ /dev/null @@ -1,61 +0,0 @@ -# ===================================================================== -# spdx-license-identifier: ISC -# glitch kernel binary and image generation -# ===================================================================== - -include Makefile.config - -${ARCH}_LDFLAGS += -T ${ARCH}/linker.ld - -TARGETBIN += glitch -glitch.OBJS += ${ARCH}/arch.a src/kernel.a devices/devs.a lib/libk.a - -include rules.mk - -.PHONY: run info -run: glitch.iso - @${QEMU} -cdrom $^ -d cpu_reset -display gtk,zoom-to-fit=on - -info: - @echo "- target:" - @echo " ARCH: ${ARCH}" - @echo " CC: ${${ARCH}_CC}" - @echo " CCID: ${${ARCH}_CCID}" - @echo " CFLAGS: ${${ARCH}_CFLAGS}" - @echo " CXX: ${${ARCH}_CXX}" - @echo " CXXID: ${${ARCH}_CXXID}" - @echo " CXXFLAGS: ${${ARCH}_CXXFLAGS}" - @echo " LD: ${${ARCH}_LD}" - @echo " LDID: ${${ARCH}_LDID}" - @echo " LDFLAGS: ${${ARCH}_LDFLAGS}" - @echo "- host:" - @echo " CC: ${HOST_CC}" - @echo " CFLAGS: ${HOST_CFLAGS}" - @echo " CXX: ${HOST_CXX}" - @echo " CXXFLAGS: ${HOST_CXXFLAGS}" - @echo " QEMU: ${QEMU}" - -# build targets - -glitch.iso: glitch.elf grub/grub.cfg - @grub-file --is-x86-multiboot2 glitch.elf - @mkdir -p isodir/boot/grub - @mkdir -p isodir/boot/glitch - @grub-script-check grub/grub.cfg - @cp grub/grub.cfg isodir/boot/grub/grub.cfg - @cp glitch.elf isodir/boot/glitch/glitch.elf - @i686-elf-strip isodir/boot/glitch/glitch.elf - @rm -f isodir/boot/glitch/checksums - @sha512sum isodir/boot/glitch/* > isodir/boot/glitch/checksums - @sed -i s/isodir// isodir/boot/glitch/checksums - @grub-mkrescue -o glitch.iso isodir - -lib/libk.a: FORCE - @${MAKE} -C lib libk.a -i686/arch.a: FORCE - @${MAKE} -C ${ARCH} arch.a -devices/devs.a: FORCE - @${MAKE} -C devices devs.a -src/kernel.a: FORCE - @${MAKE} -C src kernel.a - diff --git a/Makefile.config b/Makefile.config deleted file mode 100644 index c771677..0000000 --- a/Makefile.config +++ /dev/null @@ -1,72 +0,0 @@ -## This is a generated file, manual edits might be lost - -## .config -# -# Automatically generated file; DO NOT EDIT. -# Main menu -# - -# -# Toolchain -# -CONFIG_CFLAGS="-g -Og" -CONFIG_CXXFLAGS="-g -Og" -CONFIG_LDFLAGS="" -# end of Toolchain - -# -# Target -# -CONFIG_ARCH_i686=y -# end of Target - -# -# Devices -# -CONFIG_PIC_8259=y -CONFIG_UART_16550=y -CONFIG_VGA_TEXT_MODE=y -CONFIG_KB_PS2=y -# end of Devices - -## toolchain.mk -ARCH=i686 - -# define compiler, linker, archiver and strip and their flags -# FIXME: cpp threadsafe statics -${ARCH}_AS := i686-elf-as - -${ARCH}_CC := i686-elf-gcc -${ARCH}_CCID := $(shell ${${ARCH}_CC} --version | head -n1) -${ARCH}_CFLAGS := -Wall -Wextra -Wpedantic -Werror=shadow -Wconversion -fanalyzer -ffreestanding -std=gnu11 \ - -mgeneral-regs-only \ - $(shell echo ${CONFIG_CFLAGS}) - -${ARCH}_CXX := i686-elf-g++ -${ARCH}_CXXID := $(shell ${${ARCH}_CXX} --version | head -n1) -${ARCH}_CXXFLAGS := -Wall -Wextra -Wpedantic -Werror=shadow -Wconversion -ffreestanding -std=c++17 \ - -mgeneral-regs-only -fno-use-cxa-atexit -fno-threadsafe-statics -fno-exceptions -fno-rtti \ - $(shell echo ${CONFIG_CXXFLAGS}) - -${ARCH}_LD := i686-elf-ld -${ARCH}_LDID := $(shell ${${ARCH}_LD} --version | head -n1) -${ARCH}_LDFLAGS := -static -nostdlib \ - $(shell echo ${CONFIG_LDFLAGS}) - -${ARCH}_AR := i686-elf-ar -${ARCH}_ARFLAGS := -crus - -${ARCH}_STRIP := i686-elf-strip - -# define compiler and flags for test targets -HOST_CC := gcc -HOST_CFLAGS := -Wall -Wextra -Wpedantic -Werror=shadow -Wconversion \ - ${CFLAGS} -HOST_CXX := g++ -HOST_CXXFLAGS := -Wall -Wextra -Wpedantic -Werror=shadow -Wconversion -g -Og \ - $(shell pkg-config --cflags --libs gtest gtest_main gmock) \ - ${CXXFLAGS} - -# emulator name and flags -QEMU := qemu-system-i386 -accel kvm -machine pc - @@ -1,5 +1,10 @@ ## A simple kernel written in C +## supported platforms +- i686 + +Supported toolchains are defined in $ARCH/toolchain.mk + ## drivers - uart: 16550 (write) - vga text mode @@ -7,6 +12,7 @@ - ps2 controller: i8042, with keyboard and mouse ## building +- Code is ANSI C prerequisites: * i686-elf-gcc, i686-elf-binutils * for bootable iso image: grub, mtools diff --git a/arch/i386/BUILD.bazel b/arch/i386/BUILD.bazel new file mode 100644 index 0000000..2842a5b --- /dev/null +++ b/arch/i386/BUILD.bazel @@ -0,0 +1,44 @@ +exports_files( + ["linker.ld"], + visibility = ["//visibility:public"], +) + +cc_library( + name = "arch", + srcs = [ + "boot.s", + "gdt.c", + "init.s", + "isr.c", + "lgdt.c", + "lidt.c", + ], + hdrs = [ + "gdt.h", + "idt.h", + "paging.h", + ] + glob(["sys/*.h"]), + includes = ["."], + target_compatible_with = [ + "@platforms//os:none", + ], + visibility = ["//visibility:public"], + deps = ["//lib/libk:k"], +) + +# tests +cc_test( + name = "test_gdt", + srcs = [ + "gdt.c", + "gdt.h", + "test_gdt.cc", + ], + target_compatible_with = select({ + "@platforms//os:none": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + deps = [ + "@googletest//:gtest_main", + ], +) diff --git a/i686/boot.S b/arch/i386/boot.s index 1eea9a3..40b0389 100644 --- a/i686/boot.S +++ b/arch/i386/boot.s @@ -1,6 +1,37 @@ -#define ASM_FILE -#include <multiboot2.h> -#include "macros.s" +/* The magic field should contain this. */ +.set MULTIBOOT2_HEADER_MAGIC, 0xe85250d6 +/* This should be in %eax. */ +.set MULTIBOOT2_BOOTLOADER_MAGIC, 0x36d76289 +.set MULTIBOOT_ARCHITECTURE_I386, 0 +.set MULTIBOOT_HEADER_TAG_END, 0 +.set MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST, 1 +.set MULTIBOOT_TAG_TYPE_MMAP, 6 + +.set PAGE_RO, 0x001 +.set PAGE_RW, 0x003 + +/* write section to page table macro + * + * Registers used: + * %ecx: loop counter [ set to $1024 ] + * %edx: temporary + * %esi: current page being mapped + * %edi: page entry [ set to $page_addr ] + */ +.macro mmap_section begin, end, access + mov $\begin, %esi # from $begin +1: cmpl $\end, %esi # until $end + jge 2f + + movl %esi, %edx + orl $\access, %edx + movl %edx, (%edi) + + addl $4096, %esi # move to next page + addl $4, %edi # size of page entry is 4 bytes + loop 1b # loop according to %ecx +2: +.endm /* Declare a multiboot header that marks this program as a kernel */ .section .multiboot.header, "a" diff --git a/i686/gdt.c b/arch/i386/gdt.c index c0898f3..3148096 100644 --- a/i686/gdt.c +++ b/arch/i386/gdt.c @@ -4,11 +4,11 @@ void SegmentDescriptor(struct SegmentDescriptor_t *self, unsigned base, unsigned limit, uint8_t access) { self->base_15_0 = base & 0xffff; - self->base_23_16 = (base >> 16) & 0xff; - self->base_31_24 = (base >> 24) & 0xff; + self->base_23_16 = (uint8_t)(base >> 16); + self->base_31_24 = (uint8_t)(base >> 24); self->limit_15_0 = (limit <= 0xffff) ? (limit & 0xffff) : ((limit >> 12) & 0xffff); - self->limit_19_16 = (limit <= 0xffff) ? 0 : ((limit >> 28) & 0xf); + self->limit_19_16 = 0xfu & (uint8_t)((limit <= 0xffff) ? 0 : (limit >> 28)); self->access = access; diff --git a/arch/i386/gdt.h b/arch/i386/gdt.h new file mode 100644 index 0000000..2bdfb22 --- /dev/null +++ b/arch/i386/gdt.h @@ -0,0 +1,55 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +enum Ring { Ring0 = 0x0, Ring1 = 0x1, Ring2 = 0x2, Ring3 = 0x3 }; + +struct __attribute__((packed)) Access { + unsigned accessed : 1; /* if 0, is set by processor when accessed */ + unsigned readwrite : 1; /* code seg: read toggle; data seg: write toggle */ + unsigned direction : 1; /* code seg: conforming bit; data seg: direction bit */ + unsigned executable : 1; /* executable bit */ + unsigned segment : 1; /* true for code/data; false for gates/tss */ + unsigned privilege : 2; /* descriptor privilege level */ + unsigned present : 1; /* true for every active segment */ +}; +/* _Static_assert(sizeof(struct Access) == 1, "access byte size"); */ + +static const struct Access null_access = {0, 0, 0, 0, 0, Ring0, 0}; +static const struct Access ktext_access = {0, 1, 0, 1, 1, Ring0, 1}; +static const struct Access kdata_access = {0, 1, 0, 0, 1, Ring0, 1}; + +/* Segment Descriptor + * A memory structure (part of a table) that tells the CPU the attributes of a given segment + * |31| | | | | | |24|23|22|21|20|19| | |16|15| | | | | | | 8| 7| | | | | | | 0| + * | base_31_24 | G|DB| | A| lim_19_16 | access | base_23_16 | + * | base_15_0 | limit_15_0 | + * |31| | | | | | | | | | | | | | |16|15| | | | | | | | | | | | | | | 0| + * limit size of segment - 1, either in bytes or in 4KiB chunks (check flags) + * base address of segment + * access + * flags defines the segment chunks and 16/32 bit */ +struct __attribute__((packed)) SegmentDescriptor_t { + uint16_t limit_15_0; /* low bits of segment limit */ + uint16_t base_15_0; /* low bits of segment base address */ + uint8_t base_23_16; /* middle bits of segment base address */ + uint8_t access; /* access byte */ + unsigned limit_19_16 : 4; /* high bits of segment limit */ + /* flags */ + bool a : 1; /* unused, available for software use */ + bool rsv : 1; /* reserved */ + bool db : 1; /* false => 16-bit seg; true => 32-bit seg */ + bool granularity : 1; /* limit scaled by 4k when set */ + uint8_t base_31_24; /* high bits of segment address */ +}; +/* _Static_assert(sizeof(struct SegmentDescriptor_t) == 8, "segment descriptor size"); */ + +void SegmentDescriptor(struct SegmentDescriptor_t *self, unsigned base, unsigned limit, uint8_t access); + +void gdt_install(); + +enum SegmentIndex { + ktextDescriptor = 2 * sizeof(struct SegmentDescriptor_t), + kdataDescriptor = 3 * sizeof(struct SegmentDescriptor_t) +}; diff --git a/i686/idt.h b/arch/i386/idt.h index 45744dc..ca39bde 100644 --- a/i686/idt.h +++ b/arch/i386/idt.h @@ -10,14 +10,14 @@ struct interrupt_frame { uint32_t ss; }; -// typedef void (*irq_handler)(); +/* typedef void (*irq_handler)(); */ /* isr.c */ void abort_handler(struct interrupt_frame *frame); void syscall_handler(struct interrupt_frame *frame); -void irq0x00(struct interrupt_frame *frame); // timer interrupt -void irq0x01(struct interrupt_frame *frame); // keyboard interrupt -void irq0x0c(struct interrupt_frame *frame); // mouse interrupt +void irq0x00(struct interrupt_frame *frame); /* timer interrupt */ +void irq0x01(struct interrupt_frame *frame); /* keyboard interrupt */ +void irq0x0c(struct interrupt_frame *frame); /* mouse interrupt */ /* lidt.c */ void idt_install(); diff --git a/i686/init.s b/arch/i386/init.s index ad329bb..ad329bb 100644 --- a/i686/init.s +++ b/arch/i386/init.s diff --git a/i686/isr.c b/arch/i386/isr.c index 8af5d33..acc2961 100644 --- a/i686/isr.c +++ b/arch/i386/isr.c @@ -20,7 +20,7 @@ __attribute__((interrupt)) void syscall_handler(__attribute__((unused)) struct interrupt_frame *frame) { unsigned int n; - asm volatile("mov %%eax, %0" : "=r"(n)); + __asm__("mov %%eax, %0" : "=r"(n)); printf("syscall %x\n, n"); abort(); } diff --git a/arch/i386/lgdt.c b/arch/i386/lgdt.c new file mode 100644 index 0000000..473a91d --- /dev/null +++ b/arch/i386/lgdt.c @@ -0,0 +1,25 @@ +#include "gdt.h" + +struct __attribute__((packed)) Pointer { + uint16_t limit; + uint32_t base; +}; + +static struct SegmentDescriptor_t segments[8] __attribute__((aligned(32))); + +void +gdt_install() +{ + const struct Pointer ptr = {sizeof(segments) - 1, (unsigned)&segments}; + SegmentDescriptor(&segments[0], 0, 0, 0); /* null segment */ + SegmentDescriptor(&segments[2], 0, 0xffffffff, 0x9a); /* ktext segment */ + SegmentDescriptor(&segments[3], 0, 0xffffffff, 0x92); /* kdata segment */ + + __asm__("lgdt (%0)" : : "a"(&ptr)); + + /* load the kernel data segment */ + __asm__("mov %0, %%ds; mov %0, %%es; mov %0, %%fs; mov %0, %%gs; mov %0, %%ss" : : "ax"(kdataDescriptor)); + + /* load the kernel code segment */ + __asm__("ljmp %0, $1f\n1:" : : "i"(ktextDescriptor)); +} diff --git a/arch/i386/lidt.c b/arch/i386/lidt.c new file mode 100644 index 0000000..86567f8 --- /dev/null +++ b/arch/i386/lidt.c @@ -0,0 +1,55 @@ +#include "idt.h" +#include <stdint.h> + +struct __attribute__((packed)) Pointer { + uint16_t limit; + uint32_t base; +}; + +enum Type { + Null = 0, + Intr = 0x8e /* 1000 1110 32-bit interrupt */ +}; + +struct __attribute__((packed)) Gate_t { + uint16_t offset_15_0; /* segment offset low */ + uint16_t selector; /* code segment selector */ + uint8_t __unused; /* unused in protected mode */ + uint8_t type; /* interrupt type */ + uint16_t offset_31_16; /* segment offset high */ +}; +/* _Static_assert(sizeof(struct Gate_t) == 8, "interrupt gate size"); */ + +void +Gate(struct Gate_t *entry, void (*f)(struct interrupt_frame *), uint16_t selector) +{ + uint32_t f_addr = (uint32_t)f; + entry->offset_15_0 = f_addr & 0xffff; + entry->offset_31_16 = (uint16_t)(f_addr >> 16) & 0xffff; + entry->selector = selector; + entry->__unused = 0; + entry->type = Intr; +} + +static struct Gate_t interrupt_table[256] __attribute((aligned(4096))); + +void +idt_install() +{ + int i; + const struct Pointer ptr = {sizeof(interrupt_table) - 1, (unsigned)&interrupt_table}; + + /* exceptions 0x00~0x13 */ + for (i = 0; i <= 0x13; ++i) Gate(&interrupt_table[i], &abort_handler, 0x10); + + /* irq 0x20~0x2f */ + for (i = 0x22; i <= 0x2f; ++i) Gate(&interrupt_table[i], &abort_handler, 0x10); + Gate(&interrupt_table[0x20], &irq0x00, 0x10); + Gate(&interrupt_table[0x21], &irq0x01, 0x10); + Gate(&interrupt_table[0x2c], &irq0x0c, 0x10); + + /* syscall 0x80 */ + Gate(&interrupt_table[0x80], &syscall_handler, 0x10); + + __asm__("lidt (%0)" : : "a"(&ptr)); +} diff --git a/i686/linker.ld b/arch/i386/linker.ld index 61a3be9..61a3be9 100644 --- a/i686/linker.ld +++ b/arch/i386/linker.ld diff --git a/arch/i386/paging.h b/arch/i386/paging.h new file mode 100644 index 0000000..f5bfa78 --- /dev/null +++ b/arch/i386/paging.h @@ -0,0 +1,59 @@ +#pragma once + +/* DirectoryEntry + * |31| | | | | | | | | | | | | | | | | | | |11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + * | page table 4-kb aligned address | avail | G| S| | A| C| W| U| R| P| */ +struct __attribute__((packed)) DirectoryEntry { + unsigned present : 1; /* 0: if set, the page is actually in physical memory */ + unsigned writeable : 1; /* 1: if set, the page is read/write; otherwise the page is read-only */ + unsigned user : 1; /* 2: if set, then page can be access by all; otherwise only the supervisor can access it */ + unsigned writethrough : 1; /* 3: if set, write-through caching is enabled; otherwise write-back is enabled instead */ + unsigned cachedisable : 1; /* 4: if set, the page will not be cached */ + unsigned accessed : 1; /* 5: set by the CPU when the page is read from or written to */ + unsigned dirty : 1; /* 6: used to determine whether a page has been written to */ + unsigned pagesize : 1; /* 7: page size == 0 */ + unsigned global : 1; + unsigned int __available__ : 3; /* available to the OS */ + unsigned int address : 20; +}; +/* TODO _Static_assert(sizeof(struct DirectoryEntry) == 4, "DirectoryEntry size"); */ + +/* DirectoryEntry4MB + * |31| | | | | | | | |22|21|20| | | | | | |13|12|11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + * | bits 31-22 of address |RS| bits 39-22 of |AT| avail | G|PS| D| A|CD|WT|US|RW| P| + * | |VD| address */ +struct __attribute__((packed)) DirectoryEntry4MB { + unsigned present : 1; /* 0: if set, the page is actually in physical memory */ + unsigned writeable : 1; /* 1: if set, the page is read/write; otherwise the page is read-only */ + unsigned useraccess : 1; /* 2: if set, then page can be access by all; otherwise only the supervisor can access it */ + unsigned writethrough : 1; /* 3: if set, write-through caching is enabled; otherwise write-back is enabled instead */ + unsigned cachedisable : 1; /* 4: if set, the page will not be cached */ + unsigned accessed : 1; /* 5: set by the CPU when the page is read from or written to */ + unsigned dirty : 1; /* 6: used to determine whether a page has been written to */ + unsigned pagesize : 1; /* 7: page size == 1 */ + unsigned global : 1; /* 8: */ + unsigned __available__ : 3; /* 11..9 available to the OS */ + unsigned pat : 1; /* 12: page attribute table */ + unsigned int address_high : 8; + unsigned rsvd : 1; /* 21 */ + unsigned int address_low : 10; +}; +/* TODO _Static_assert(sizeof(struct DirectoryEntry4MB) == 4, "DirectoryEntry4M size"); */ + +/* TableEntry + * |31| | | | | | | | | | | | | | | | | | | |11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| + * | page table 4-kb aligned address | avail | G| | D| A| C| W|US|RW| P| */ +struct __attribute__((packed)) TableEntry { + unsigned present : 1; /* if set, the page is actually in physical memory */ + unsigned writeable : 1; /* if set, the page is read/write; otherwise the page is read-only */ + unsigned user : 1; /* if set, then page can be access by all; otherwise only the supervisor can access it */ + unsigned writethrough : 1; /* if set, write-through caching is enabled; otherwise write-back is enabled instead */ + unsigned cachedisable : 1; /* if set, the page will not be cached */ + unsigned accessed : 1; /* set by the CPU when the page is read from or written to */ + unsigned dirty : 1; /* used to determine whether a page has been written to */ + unsigned pat : 1; /* page attribute table? */ + unsigned global : 1; + unsigned int __available__ : 3; /* available to the OS */ + unsigned int address : 20; +}; +/* TODO _Static_assert(sizeof(struct TableEntry) == 4, "TableEntry size"); */ diff --git a/arch/i386/sys/control.h b/arch/i386/sys/control.h new file mode 100644 index 0000000..89ab067 --- /dev/null +++ b/arch/i386/sys/control.h @@ -0,0 +1,24 @@ +#pragma once + +static __inline__ void +abort() +{ + /* Symbol h is already defined? +__asm__(R"(cli +h: hlt +jmp h)"); +*/ + __asm__("cli; hlt"); +} + +static __inline__ void +enable_interrupts() +{ + __asm__("sti"); +} + +static __inline__ void +disable_interrupts() +{ + __asm__("cli"); +} diff --git a/i686/sys/cpuid.h b/arch/i386/sys/cpuid.h index 65b43c6..6613967 100644 --- a/i686/sys/cpuid.h +++ b/arch/i386/sys/cpuid.h @@ -12,7 +12,7 @@ struct CPUVersion { unsigned int family_ex : 8; unsigned int __unused_2 : 4; } __attribute__((packed, aligned(__alignof__(unsigned int)))); -// FIXME _Static_assert(sizeof(struct CPUVersion) == sizeof(unsigned int), "cpuid version struct size"); +/* FIXME _Static_assert(sizeof(struct CPUVersion) == sizeof(unsigned int), "cpuid version struct size"); */ unsigned int family(const struct CPUVersion v) diff --git a/arch/i386/sys/io.h b/arch/i386/sys/io.h new file mode 100644 index 0000000..4ff5d85 --- /dev/null +++ b/arch/i386/sys/io.h @@ -0,0 +1,92 @@ +#pragma once + +/* port listings */ +enum UART { + COM1 = 0x3f8, + COM2 = 0x2f8, + COM3 = 0x3e8, + COM4 = 0x2e8, + COM5 = 0x5f8, + COM6 = 0x4f8, + COM7 = 0x5e8, + COM8 = 0x4e8 +}; + +static __inline__ void +outb(unsigned char val, unsigned short port) +{ + __asm__("outb %0,%1" : : "a"(val), "dN"(port)); +} + +static __inline__ void +outw(unsigned short val, unsigned short port) +{ + __asm__("outw %0,%1" : : "a"(val), "dN"(port)); +} + +static __inline__ void +outl(unsigned int val, unsigned short port) +{ + __asm__("outl %0,%1" : : "a"(val), "dN"(port)); +} + +static __inline__ unsigned char +inb(unsigned short port) +{ + unsigned char val; + __asm__("inb %1,%0" : "=a"(val) : "dN"(port)); + return val; +} + +static __inline__ unsigned short +inw(unsigned short port) +{ + unsigned short val; + __asm__("inw %1,%0" : "=a"(val) : "dN"(port)); + return val; +} + +static __inline__ unsigned int +inl(unsigned short port) +{ + unsigned int val; + __asm__("inl %1,%0" : "=a"(val) : "dN"(port)); + return val; +} + +static __inline__ void +outsb(unsigned short port, const void *__buf, unsigned long __n) +{ + __asm__("cld; rep; outsb" : "+S"(__buf), "+c"(__n) : "d"(port)); +} + +static __inline__ void +outsw(unsigned short port, const void *__buf, unsigned long __n) +{ + __asm__("cld; rep; outsw" : "+S"(__buf), "+c"(__n) : "d"(port)); +} + +static __inline__ void +outsl(unsigned short port, const void *__buf, unsigned long __n) +{ + __asm__("cld; rep; outsl" : "+S"(__buf), "+c"(__n) : "d"(port)); +} + +static __inline__ void +insb(unsigned short port, void *__buf, unsigned long __n) +{ + __asm__("cld; rep; insb" : "+D"(__buf), "+c"(__n) : "d"(port)); +} + +static __inline__ void +insw(unsigned short port, void *__buf, unsigned long __n) +{ + __asm__("cld; rep; insw" : "+D"(__buf), "+c"(__n) : "d"(port)); +} + +static __inline__ void +insl(unsigned short port, void *__buf, unsigned long __n) +{ + __asm__("cld; rep; insl" : "+D"(__buf), "+c"(__n) : "d"(port)); +} + diff --git a/i686/sys/syscall.h b/arch/i386/sys/syscall.h index 9e62c89..9e62c89 100644 --- a/i686/sys/syscall.h +++ b/arch/i386/sys/syscall.h diff --git a/arch/i386/test_gdt.cc b/arch/i386/test_gdt.cc new file mode 100644 index 0000000..3501ae9 --- /dev/null +++ b/arch/i386/test_gdt.cc @@ -0,0 +1,25 @@ +#include <gtest/gtest.h> + +extern "C" { +#include "gdt.h" +} + +TEST(i686GDT, KnownAccessByteValues) +{ + EXPECT_EQ(*(uint8_t *)&null_access, 0x00); + EXPECT_EQ(*(uint8_t *)&ktext_access, 0x9a); + EXPECT_EQ(*(uint8_t *)&kdata_access, 0x92); +} + +TEST(i686GDT, NullSegmentDescriptor) +{ + struct SegmentDescriptor_t d; + SegmentDescriptor(&d, 0, 0, 0); + EXPECT_EQ(*(uint64_t *)&d, 0); +} + +TEST(i686GDT, SegmentIndex) +{ + EXPECT_EQ(ktextDescriptor, 0x10); + EXPECT_EQ(kdataDescriptor, 0x18); +} diff --git a/devices/BUILD.bazel b/devices/BUILD.bazel new file mode 100644 index 0000000..0c58d48 --- /dev/null +++ b/devices/BUILD.bazel @@ -0,0 +1,22 @@ +cc_library( + name = "drivers", + srcs = [ + "i8042.c", + "mouse.c", + "pckbd.c", + "pic_8259.c", + "uart/uart_16550.c", + "uart/uart_16550.h", + "vga.c", + ], + hdrs = glob(["include/*.h"]), + defines = [ + "__ARCH__=i386", + ], + includes = ["include"], + visibility = ["//visibility:public"], + deps = [ + "//arch/i386:arch", + "//lib/libk:k", + ], +) diff --git a/devices/Makefile b/devices/Makefile deleted file mode 100644 index 3c61f6d..0000000 --- a/devices/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -include ../Makefile.config - -INCLUDES := -I../${ARCH} -${ARCH}_CFLAGS += ${INCLUDES} -${ARCH}_CXXFLAGS += ${INCLUDES} - -TARGETLIB += devs -devs.SRCS = pic_8259.c uart_16550.cpp vga.cpp i8042.c pckbd.c mouse.c - -include ../rules.mk - diff --git a/devices/i8042.c b/devices/i8042.c index c612e6d..cfd96a8 100644 --- a/devices/i8042.c +++ b/devices/i8042.c @@ -8,8 +8,8 @@ #include <stdio.h> #include <sys/io.h> -// r status register -// w command register +/* r status register */ +/* w command register */ #define comm_port 0x64 #define comm_enable_first_ps2 0xae #define comm_enable_second_ps2 0xa8 @@ -19,16 +19,18 @@ #define data_port 0x60 #define data_enable_scanning 0xf4 -// TODO: All output to port 0x60 or 0x64 must be preceded by waiting for bit 1 (value=2) of port 0x64 to become clear. -// TODO: Similarly, bytes cannot be read from port 0x60 until bit 0 (value=1) of port 0x64 is set. +/* TODO: All output to port 0x60 or 0x64 must be preceded by waiting for bit 1 (value=2) of port 0x64 to become clear. + * TODO: Similarly, bytes cannot be read from port 0x60 until bit 0 (value=1) of port 0x64 is set. */ void ps2_ctrl_init() { - // eat all previous keystrikes + int i; + uint8_t test, conf; + + /* eat all previous keystrikes */ while (inb(comm_port) & 0x1) inb(data_port); - uint8_t test; outb(0xaa, comm_port); test = inb(data_port); printf("i8042: self test 0xaa:%x %s\n", test, test == 0x55 ? "ok" : "failed"); @@ -39,30 +41,30 @@ ps2_ctrl_init() test = inb(data_port); printf("i8042: port2 test 0xa9:%x %s\n", test, test == 0x00 ? "ok" : "failed"); - // printf("8042: init keyboard\n"); + /* printf("8042: init keyboard\n"); */ outb(comm_enable_first_ps2, comm_port); outb(comm_enable_second_ps2, comm_port); - // resets the cpu - // outb(0xfe, 0x64); + /* resets the cpu */ + /* outb(0xfe, 0x64); */ outb(0xf2, 0x60); printf("i8042: id port1: "); while ((inb(0x64) & 0x01) == 0) {} - for (int i = 0; i < 3; ++i) printf("%x ", inb(0x60)); + for (i = 0; i < 3; ++i) printf("%x ", inb(0x60)); printf("\n"); outb(0xd4, 0x64); outb(0xf2, 0x60); printf("i8042: id port2: "); while ((inb(0x64) & 0x01) == 0) {} - for (int i = 0; i < 3; ++i) printf("%x ", inb(0x60)); + for (i = 0; i < 3; ++i) printf("%x ", inb(0x60)); printf("\n"); outb(comm_read_ctrl_config, comm_port); - uint8_t conf = (inb(data_port) | 1) & ~0x10; - conf |= 0x22; // mouse + conf = (uint8_t)((inb(data_port) | 1) & ~0x10); + conf |= 0x22; /* mouse */ outb(comm_write_ctrl_config, comm_port); outb(conf, data_port); @@ -81,7 +83,6 @@ ps2_read_port1() unsigned char ps2_read_port2() { - outb(0xd4, 0x64); return inb(0x60); } diff --git a/devices/keyboard.h b/devices/include/keyboard.h index 5f4fcc2..5f4fcc2 100644 --- a/devices/keyboard.h +++ b/devices/include/keyboard.h diff --git a/devices/mouse.h b/devices/include/mouse.h index a34ecb4..a34ecb4 100644 --- a/devices/mouse.h +++ b/devices/include/mouse.h diff --git a/devices/pic.h b/devices/include/pic.h index c545c60..c545c60 100644 --- a/devices/pic.h +++ b/devices/include/pic.h diff --git a/devices/ps2_controller.h b/devices/include/ps2_controller.h index d2f7e80..d2f7e80 100644 --- a/devices/ps2_controller.h +++ b/devices/include/ps2_controller.h diff --git a/devices/include/uart.h b/devices/include/uart.h new file mode 100644 index 0000000..8b44519 --- /dev/null +++ b/devices/include/uart.h @@ -0,0 +1,32 @@ +#pragma once + +#ifdef __ARCH__ +#include <stdio.h> +#include <sys/io.h> + +#else +/* from stdio */ +typedef struct FILE { + int id; + void (*putc)(const struct FILE *, char); + int (*puts)(const struct FILE *, const char *, int); + void (*flush)(const struct FILE *); +} FILE; + +/* from sys/io */ +unsigned char inb(unsigned short); +void outb(unsigned char, unsigned short); + +enum UART { + COM1 = 0x3f8, + COM2 = 0x2f8, + COM3 = 0x3e8, + COM4 = 0x2e8, + COM5 = 0x5f8, + COM6 = 0x4f8, + COM7 = 0x5e8, + COM8 = 0x4e8, +}; +#endif + +FILE *uart_init(unsigned short port); diff --git a/devices/include/vga.h b/devices/include/vga.h new file mode 100644 index 0000000..df0d921 --- /dev/null +++ b/devices/include/vga.h @@ -0,0 +1,33 @@ +#pragma once + +#include <stdio.h> + +/** Hardware text mode color constants. */ +enum vga_color { + VGA_COLOR_BLACK = 0, + VGA_COLOR_BLUE = 1, + VGA_COLOR_GREEN = 2, + VGA_COLOR_CYAN = 3, + VGA_COLOR_RED = 4, + VGA_COLOR_MAGENTA = 5, + VGA_COLOR_BROWN = 6, + VGA_COLOR_LIGHT_GREY = 7, + VGA_COLOR_DARK_GREY = 8, + VGA_COLOR_LIGHT_BLUE = 9, + VGA_COLOR_LIGHT_GREEN = 10, + VGA_COLOR_LIGHT_CYAN = 11, + VGA_COLOR_LIGHT_RED = 12, + VGA_COLOR_LIGHT_MAGENTA = 13, + VGA_COLOR_LIGHT_BROWN = 14, + VGA_COLOR_WHITE = 15 +}; + +FILE *vga_init(void *addr); +void vga_clear(enum vga_color foreground, enum vga_color background); + +/* void vga_putc(char a); */ +/* void vga_puts(const char *string, int len); */ + +/* void vga_enable_cursor(unsigned char start, unsigned char end); */ +/* void vga_disable_cursor(); */ +void vga_update_cursor(void); diff --git a/devices/mouse.c b/devices/mouse.c index a950e8c..a03388a 100644 --- a/devices/mouse.c +++ b/devices/mouse.c @@ -7,29 +7,33 @@ void mouse_init() { - // Sending a command or data byte to the mouse (to port 0x60) must be preceded by sending a 0xD4 byte to port 0x64 - // (with appropriate waits on port 0x64, bit 1, before sending each output byte). Note: this 0xD4 byte does not - // generate any ACK, from either the keyboard or mouse. + int i; - // enable second ps/2 - // outb(0xa8, 0x64); + /* Sending a command or data byte to the mouse (to port 0x60) must be preceded by sending a 0xD4 byte to port 0x64 + * (with appropriate waits on port 0x64, bit 1, before sending each output byte). Note: this 0xD4 byte does not + * generate any ACK, from either the keyboard or mouse. */ - // outb(0x64, 0xd4); - // outb(0x60, 0xf4); - // printf("mouse_init: enable streaming(0xf4): %x\n", inb(0x60)); + /* enable second ps/2 */ + /* outb(0xa8, 0x64); */ + + /* outb(0x64, 0xd4); */ + /* outb(0x60, 0xf4); */ + /* printf("mouse_init: enable streaming(0xf4): %x\n", inb(0x60)); */ outb(0xd4, 0x64); - outb(0xeb, 0x60); // single packet + outb(0xeb, 0x60); /* single packet */ printf("mouse_init: single packet 0xeb\n"); while ((inb(0x64) & 0x01) == 0) {} - for (int i = 0; i < 10; ++i) printf("%x ", inb(0x60)); + for (i = 0; i < 10; ++i) printf("%x ", inb(0x60)); printf("\n"); } void mouse_packet() { + int i; + printf("mouse packet: "); - for (int i = 0; i < 4; ++i) printf("%x ", ps2_read_port2()); + for (i = 0; i < 4; ++i) printf("%x ", ps2_read_port2()); printf("\n"); } diff --git a/devices/pckbd.c b/devices/pckbd.c index d550f91..0e99fe6 100644 --- a/devices/pckbd.c +++ b/devices/pckbd.c @@ -26,22 +26,22 @@ ps2_keyboard_irq_handler() const uint8_t key = ps2_read_port1(); switch (key) { - case 0x2a: // left shift down - case 0x36: // right shift down + case 0x2a: /* left shift down */ + case 0x36: /* right shift down */ shift_case = 1; return; - case 0xaa: // left shift up - case 0xb6: // right shift up + case 0xaa: /* left shift up */ + case 0xb6: /* right shift up */ shift_case = 0; return; - case 0x5b: // left meta - case 0x5c: // right meta + case 0x5b: /* left meta */ + case 0x5c: /* right meta */ return; - case 0x58: // F12 - // vga_clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); + case 0x58: /* F12 */ + /* vga_clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); */ return; } diff --git a/devices/pic_8259.c b/devices/pic_8259.c index 75a2d0e..75aaf6d 100644 --- a/devices/pic_8259.c +++ b/devices/pic_8259.c @@ -6,11 +6,11 @@ #define PIC2 0xa0 #define DATA 1 -// initialization +/* initialization */ #define ICW1_INIT 0x10 -// TODO +/* TODO */ #define ICW1_ICW4 0x01 -// 8086/88 mode +/* 8086/88 mode */ #define ICW4_8086 0x01 void @@ -19,31 +19,39 @@ pic_init() outb(ICW1_INIT | ICW1_ICW4, PIC1); outb(ICW1_INIT | ICW1_ICW4, PIC2); - outb(0x20, PIC1 + DATA); // offset 0x20 - outb(0x28, PIC2 + DATA); // offset 0x28 + outb(0x20, PIC1 + DATA); /* offset 0x20 */ + outb(0x28, PIC2 + DATA); /* offset 0x28 */ - outb(0x04, PIC1 + DATA); // tell master pic there is a slave pic - outb(0x02, PIC2 + DATA); // tell slave pic its cascade identity + outb(0x04, PIC1 + DATA); /* tell master pic there is a slave pic */ + outb(0x02, PIC2 + DATA); /* tell slave pic its cascade identity */ outb(ICW4_8086, PIC1 + DATA); outb(ICW4_8086, PIC2 + DATA); - // PIC masks + /* PIC masks */ outb(0xff, PIC1 + DATA); outb(0xff, PIC2 + DATA); } +static unsigned char +irq_mask(unsigned char irq) +{ + unsigned char mask = (unsigned char)~(1u << irq); + return 0xff & mask; +} + void pic_enable() { unsigned char mask1 = 0xff; - mask1 &= ~(1 << 0); // irq0 timer - mask1 &= ~(1 << 1); // irq1 keyboard - mask1 &= ~(1 << 2); // irq1 cascade + unsigned char mask2 = 0xff; + + mask1 &= irq_mask(0); /* irq0 timer */ + mask1 &= irq_mask(1); /* irq1 keyboard */ + mask1 &= irq_mask(2); /* irq2 cascade */ outb(mask1, PIC1 + DATA); - unsigned char mask2 = 0xff; - mask2 &= ~(1 << 4); // irq12 mouse + mask2 &= irq_mask(12 - 8); /* irq12 mouse */ outb(mask2, PIC2 + DATA); enable_interrupts(); diff --git a/devices/uart.hpp b/devices/uart.hpp deleted file mode 100644 index c86557c..0000000 --- a/devices/uart.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include <stdio.h> -#include <sys/io.h> - -template <UART port> FILE *uart_init(); -template <> FILE *uart_init<COM1>(); diff --git a/devices/uart/sys_io.hh b/devices/uart/sys_io.hh new file mode 100644 index 0000000..142c9c1 --- /dev/null +++ b/devices/uart/sys_io.hh @@ -0,0 +1,34 @@ +#pragma once + +#include <gmock/gmock.h> + +class IPort { +public: + virtual unsigned char inb(unsigned short) const = 0; + virtual void outb(unsigned char, unsigned short) const = 0; +}; + +class MockPort : public IPort { +public: + MOCK_METHOD(unsigned char, inb, (unsigned short), (const, override)); + MOCK_METHOD(void, outb, (unsigned char, unsigned short), (const, override)); +}; + +static std::unique_ptr<MockPort> mockPort; + +// mock free functions +extern "C" { +unsigned char +inb(unsigned short v) +{ + EXPECT_TRUE(mockPort) << "MockPort was not set up by the test fixture"; + return mockPort->inb(v); +} + +void +outb(unsigned char p, unsigned short v) +{ + EXPECT_TRUE(mockPort) << "MockPort was not set up by the test fixture"; + return mockPort->outb(p, v); +} +} diff --git a/devices/uart/uart_16550.c b/devices/uart/uart_16550.c new file mode 100644 index 0000000..4697cf3 --- /dev/null +++ b/devices/uart/uart_16550.c @@ -0,0 +1,78 @@ +#include "uart_16550.h" +#include <stddef.h> + +int +uart_thre(unsigned short port) +{ + return inb(port + LineStatus) & THRE; +} + +void +uart_putc(const FILE *self, char a) +{ + const unsigned short port = (unsigned short)self->id; + + while (uart_thre(port) == 0) {} + outb((unsigned char)a, port); + + if (a == '\n') { + while (uart_thre(port) == 0) {} + outb('\r', port); + } +} + +int +uart_puts(const FILE *self, const char *string, int length) +{ + int i; + int written = 0; + + if (length == -1) + while (*string != '\0') { + uart_putc(self, *string); + ++string; + ++written; + } + + else + for (i = 0; i < length; ++i) { + uart_putc(self, string[i]); + ++written; + } + + return written; +} + +void +uart_flush(__attribute__((unused)) const FILE *self) +{ +} + +FILE uart_stream; + +FILE * +uart_init(unsigned short port) +{ + outb(0x00, port + 1); /* Disable all interrupts */ + outb(0x80, port + 3); /* Enable DLAB (set baud rate divisor) */ + outb(0x03, port + 0); /* Set divisor to 3 (lo byte) 38400 baud */ + outb(0x00, port + 1); /* (hi byte) */ + outb(0x03, port + 3); /* 8 bits, no parity, one stop bit */ + outb(0xc7, port + 2); /* Enable FIFO, clear them, with 14-byte threshold */ + outb(0x0b, port + 4); /* IRQs enabled, RTS/DSR set */ + outb(0x1e, port + 4); /* Set in loopback mode, test the serial chip */ + outb(0xae, port + 0); /* Test serial chip (send byte 0xAE and check if serial */ + /* returns same byte) */ + + /* Check if serial is faulty (i.e: not same byte as sent) */ + if (inb(port + 0) != 0xae) { return NULL; } + + /* If serial is not faulty set it in normal operation mode */ + /* (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) */ + outb(0x0f, port + 4); + uart_stream.id = port; + uart_stream.putc = &uart_putc; + uart_stream.puts = &uart_puts; + uart_stream.flush = &uart_flush; + return &uart_stream; +} diff --git a/devices/uart/uart_16550.h b/devices/uart/uart_16550.h new file mode 100644 index 0000000..bbeb9b7 --- /dev/null +++ b/devices/uart/uart_16550.h @@ -0,0 +1,49 @@ +#pragma once + +#include "uart.h" + +int uart_thre(unsigned short port); +void uart_putc(const FILE *self, char a); +int uart_puts(const FILE *self, const char *string, int length); +void uart_flush(__attribute__((unused)) const FILE *self); + +enum uart_16550_offset { + Data = 0, /* read from receive buffer / write to transmit buffer | BaudDiv_l */ + InterruptControl = 1, /* interrupt enable | BaudDiv_h */ + FifoControl = 2, /* interrupt ID and FIFO control */ + LineControl = 3, /* most significant bit is the DLAB */ + ModemControl = 4, + LineStatus = 5, + ModemStatus = 6, + Scratch = 7 +}; + +/* Line Control + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * |dla| | parity | s | data | */ +enum LineControl { + d5bit = 0x00, /* 0000 0000 data bits */ + d6bit = 0x01, /* 0000 0001 */ + d7bit = 0x02, /* 0000 0010 */ + d8bit = 0x03, /* 0000 0011 */ + /* none = 0b00000000, // parity bits */ + odd = 0x08, /* 0000 1000 */ + even = 0x18, /* 0001 1000 */ + mark = 0x28, /* 0010 1000 */ + space = 0x38, /* 0011 1000 */ + /* s1bit = 0b00000000, // stop bits */ + s2bit = 0x04, /* 0000 0100 1.5 for 5bit data; 2 otherwise */ + dlab = 0x80 /* 1000 0000 divisor latch access bit */ +}; + +/* Line Status Register */ +enum LineStatus { + DR = (1 << 0), /* data ready: see if there is data to read */ + OE = (1 << 1), /* overrun error: see if there has been data lost */ + PE = (1 << 2), /* parity error: see if there was error in transmission */ + FE = (1 << 3), /* framing error: see if a stop bit was missing */ + BI = (1 << 4), /* break indicator: see if there is a break in data input */ + THRE = (1 << 5), /* transmitter holding register empty: see if transmission buffer is empty */ + TEMT = (1 << 6), /* transmitter empty: see if transmitter is not doing anything */ + ERRO = (1 << 7) /* impending error: see if there is an error with a word in the input buffer */ +}; diff --git a/devices/uart/unittest_uart_16550.cc b/devices/uart/unittest_uart_16550.cc new file mode 100644 index 0000000..f8124bb --- /dev/null +++ b/devices/uart/unittest_uart_16550.cc @@ -0,0 +1,116 @@ +#include "sys_io.hh" +#include <gtest/gtest.h> + +using ::testing::_; +using ::testing::MockFunction; +using ::testing::Return; + +namespace k { +extern "C" { +#include "uart.h" +#include "uart_16550.h" +} +} // namespace k + +class Uart16550 : public ::testing::Test { +protected: + void + SetUp() + { + ASSERT_FALSE(mockPort); + mockPort.reset(new MockPort); + } + void + TearDown() + { + ASSERT_TRUE(mockPort); + mockPort.reset(); + } +}; + +TEST_F(Uart16550, uart_thre) +{ + // set up expectations + EXPECT_CALL(*mockPort, inb(k::COM1 + k::LineStatus)).Times(1).WillOnce(Return(k::THRE)); + + const auto result = uart_thre(k::COM1); + EXPECT_TRUE(result); +} + +TEST_F(Uart16550, uart_putc) +{ + k::FILE f{k::COM1, nullptr, nullptr, nullptr}; + + // set up expectations + EXPECT_CALL(*mockPort, inb(k::COM1 + k::LineStatus)).Times(1).WillRepeatedly(Return(k::THRE)); + EXPECT_CALL(*mockPort, outb('a', k::COM1)).Times(1); + + uart_putc(&f, 'a'); +} + +TEST_F(Uart16550, uart_putc_newline) +{ + k::FILE f{k::COM1, nullptr, nullptr, nullptr}; + + // set up expectations + EXPECT_CALL(*mockPort, inb(k::COM1 + k::LineStatus)).Times(2).WillRepeatedly(Return(k::THRE)); + EXPECT_CALL(*mockPort, outb('\n', k::COM1)).Times(1); + EXPECT_CALL(*mockPort, outb('\r', k::COM1)).Times(1); + + uart_putc(&f, '\n'); +} + +TEST_F(Uart16550, uart_puts) +{ + k::FILE f{k::COM1, nullptr, nullptr, nullptr}; + const char *string{"This is a test string to write over uart"}; + const int length = (int)strlen(string); + + // set up expectations + EXPECT_CALL(*mockPort, inb(k::COM1 + k::LineStatus)).Times(length).WillRepeatedly(Return(k::THRE)); + EXPECT_CALL(*mockPort, outb(_, k::COM1)).Times(length); + + const auto result = uart_puts(&f, string, length); + ASSERT_EQ(result, length); +} + +TEST_F(Uart16550, uart_puts_WithUnknownLength) +{ + k::FILE f{k::COM1, nullptr, nullptr, nullptr}; + const char *string{"This is a test string to write over uart"}; + const int length = (int)strlen(string); + + // set up expectations + EXPECT_CALL(*mockPort, inb(k::COM1 + k::LineStatus)).Times(length).WillRepeatedly(Return(k::THRE)); + EXPECT_CALL(*mockPort, outb(_, k::COM1)).Times(length); + + const auto result = uart_puts(&f, string, -1); + ASSERT_EQ(result, length); +} + +TEST_F(Uart16550, uart_puts_WithPartialLength) +{ + k::FILE f{k::COM1, nullptr, nullptr, nullptr}; + const char *string{"This is a test string to write over uart"}; + const int length = (int)strlen(string); + const int partial = 10; + + ASSERT_LT(partial, length); + + // set up expectations + EXPECT_CALL(*mockPort, inb(k::COM1 + k::LineStatus)).Times(partial).WillRepeatedly(Return(k::THRE)); + EXPECT_CALL(*mockPort, outb(_, k::COM1)).Times(partial); + + const auto result = uart_puts(&f, string, partial); + ASSERT_EQ(result, partial); +} + +TEST_F(Uart16550, uart_flush) +{ + k::FILE f{k::COM1, nullptr, nullptr, nullptr}; + + // set up expectations + // no mock calls are expected + + uart_flush(&f); +} diff --git a/devices/uart_16550.cpp b/devices/uart_16550.cpp deleted file mode 100644 index 9620981..0000000 --- a/devices/uart_16550.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "uart.hpp" -#include <sys/io.hpp> - -template <UART port> struct Uart16550 : public kIoDevice, private Port<unsigned short, port> { - using Base = Port<unsigned short, port>; - using Ports = UART; - using PortOffset = UARTPortOffset; - - // Line Control - // | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - // |dla| | parity | s | data | - enum LineControl : unsigned char { - d5bit = 0x00, // 0000 0000 data bits - d6bit = 0x01, // 0000 0001 - d7bit = 0x02, // 0000 0010 - d8bit = 0x03, // 0000 0011 - none = 0x00, // 0000 0000 parity bits - odd = 0x08, // 0000 1000 - even = 0x18, // 0001 1000 - mark = 0x28, // 0010 1000 - space = 0x38, // 0011 1000 - s1bit = 0x00, // 0000 0000 stop bits - s2bit = 0x04, // 0000 0100 1.5 for 5bit data; 2 otherwise - dlab = 0x80 // 1000 0000 divisor latch access bit - }; - - // Line Status Register - enum LineStatus : unsigned char { - DR = (1 << 0), // data ready: see if there is data to read - OE = (1 << 1), // overrun error: see if there has been data lost - PE = (1 << 2), // parity error: see if there was error in transmission - FE = (1 << 3), // framing error: see if a stop bit was missing - BI = (1 << 4), // break indicator: see if there is a break in data input - THRE = (1 << 5), // transmitter holding register empty: see if transmission buffer is empty - TEMT = (1 << 6), // transmitter empty: see if transmitter is not doing anything - ERRO = (1 << 7), // impending error: see if there is an error with a word in the input buffer - }; - - [[nodiscard]] static bool - test() - { - Base::out(0x00, 1); // Disable all interrupts - Base::out(0x80, 3); // Enable DLAB (set baud rate divisor) - Base::out(0x03, 0); // Set divisor to 3 (lo byte) 38400 baud - Base::out(0x00, 1); // (hi byte) - Base::out(0x03, 3); // 8 bits, no parity, one stop bit - Base::out(0xc7, 2); // Enable FIFO, clear them, with 14-byte threshold - Base::out(0x0b, 4); // IRQs enabled, RTS/DSR set - Base::out(0x1e, 4); // Set in loopback mode, test the serial chip - Base::out(0xae, 0); // Test serial chip (send byte 0xAE and check if serial - // returns same byte) - - // Check if serial is faulty (i.e: not same byte as sent) - if (Base::in() != 0xae) { return false; } - - // If serial is not faulty set it in normal operation mode - // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) - Base::out(0x0f, 4); - return true; - } - - [[nodiscard]] static bool - thre() - { - return Base::in(PortOffset::LineStatus)&THRE; - } - - void - putc(char a) override - { - while (!thre()) {} - Base::out(a); - if (a == '\n') putc('\r'); - } - - int - puts(const char *string, int length) override - { - int written = 0; - - if (length == -1) - while (*string != '\0') { - putc(*string); - ++string; - ++written; - } - - else { - for (int i = 0; i < length; ++i) putc(string[i]); - written += length; - } - - return written; - } - - void - flush() override - { - } -}; - -static_assert(sizeof(Uart16550<COM1>) == sizeof(void *)); - -template <> -FILE * -uart_init<COM1>() -{ - static Uart16550<COM1> device; - return &device; -} diff --git a/devices/vga.cpp b/devices/vga.c index 3f83a5f..51f860f 100644 --- a/devices/vga.cpp +++ b/devices/vga.c @@ -1,26 +1,31 @@ -#include "vga.hpp" +#include "vga.h" #include <stdint.h> #include <sys/io.h> -// FIXME user a Port #define cga_idx_port 0x3d4 #define cga_dat_port 0x3d5 -// FIXME make constexpr #define cursor_start 0x0a #define cursor_end 0x0b #define cursor_addr_h 0x0e #define cursor_addr_l 0x0f #define cursor_hide 0x20 -static_assert(sizeof(struct VGA::VGAEntry) == 2, "sizeof VGAEntry"); +struct __attribute__((packed)) VGAEntry { + char text; + unsigned foreground : 4; + unsigned background : 4; +}; +/* TODO _Static_assert(sizeof(struct VGAEntry) == 2, "sizeof VGAEntry"); */ -// FIXME make constexpr const int width = 80; const int height = 25; -// *** Cursor *** -// FIXME make VGA members +struct VGAEntry *buffer; +int col = 0; +int row = 0; + +/* *** Cursor *** */ void vga_enable_cursor(unsigned char start, unsigned char end) { @@ -39,21 +44,23 @@ vga_disable_cursor() } void -VGA::update_cursor() +vga_update_cursor(void) { - const uint16_t pos = row * width + col; + const uint16_t pos = (uint16_t)(row * width + col); outb(cursor_addr_l, cga_idx_port); - outb(pos & 0xff, cga_dat_port); + outb((unsigned char)pos & 0xff, cga_dat_port); outb(cursor_addr_h, cga_idx_port); - outb((pos >> 8) & 0xff, cga_dat_port); + outb((unsigned char)(pos >> 8) & 0xff, cga_dat_port); } -// *** Text Mode Output *** +/* *** Text Mode Output *** */ void -VGA::putc(char a) +vga_putc(__attribute__((unused)) const FILE *self, char a) { + int i, x, y; + switch (a) { case '\n': col = 0; @@ -77,62 +84,75 @@ VGA::putc(char a) } if (row == height) { - // scroll up - for (int y = 1; y < height; ++y) - for (int x = 0; x < width; ++x) { + /* scroll up */ + for (y = 1; y < height; ++y) + for (x = 0; x < width; ++x) { const int prev = (y - 1) * width + x; const int curr = y * width + x; buffer[prev] = buffer[curr]; } - // blank out last row - for (int i = (height - 1) * width; i < height * width; ++i) buffer[i].text = ' '; + /* blank out last row */ + for (i = (height - 1) * width; i < height * width; ++i) buffer[i].text = ' '; --row; } } int -VGA::puts(const char *string, int len) +vga_puts(const FILE *self, const char *string, int len) { + int i; + int written = 0; if (len == -1) while (*string != '\0') { - putc(*string); + vga_putc(self, *string); ++string; ++written; } else - for (int i = 0; i < len; ++i) { - putc(string[i]); + for (i = 0; i < len; ++i) { + vga_putc(self, string[i]); ++written; } return written; } -// *** Text Mode *** -VGA::VGA(void *addr) +void +vga_flush(__attribute__((unused)) const FILE *self) { - buffer = (struct VGAEntry *)addr; - vga_enable_cursor(14, 15); - clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); + vga_update_cursor(); } + +/* *** Text Mode *** */ +FILE vga_stream; + FILE * -vga_init(void *buffer) +vga_init(void *addr) { - static VGA device(buffer); - return &device; + buffer = (struct VGAEntry *)addr; + vga_enable_cursor(14, 15); + vga_clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); + + vga_stream.id = 0; + vga_stream.putc = &vga_putc; + vga_stream.puts = &vga_puts; + vga_stream.flush = &vga_flush; + return &vga_stream; } void -VGA::clear(enum vga_color foreground, enum vga_color background) +vga_clear(enum vga_color foreground, enum vga_color background) { - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) { + int x, y; + + for (y = 0; y < height; ++y) + for (x = 0; x < width; ++x) { const int index = y * width + x; buffer[index].text = ' '; buffer[index].foreground = foreground; buffer[index].background = background; } col = row = 0; - update_cursor(); + vga_update_cursor(); } diff --git a/devices/vga.hpp b/devices/vga.hpp deleted file mode 100644 index 5287d73..0000000 --- a/devices/vga.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include <stdio.h> - -/** Hardware text mode color constants. */ -enum vga_color { - VGA_COLOR_BLACK = 0, - VGA_COLOR_BLUE = 1, - VGA_COLOR_GREEN = 2, - VGA_COLOR_CYAN = 3, - VGA_COLOR_RED = 4, - VGA_COLOR_MAGENTA = 5, - VGA_COLOR_BROWN = 6, - VGA_COLOR_LIGHT_GREY = 7, - VGA_COLOR_DARK_GREY = 8, - VGA_COLOR_LIGHT_BLUE = 9, - VGA_COLOR_LIGHT_GREEN = 10, - VGA_COLOR_LIGHT_CYAN = 11, - VGA_COLOR_LIGHT_RED = 12, - VGA_COLOR_LIGHT_MAGENTA = 13, - VGA_COLOR_LIGHT_BROWN = 14, - VGA_COLOR_WHITE = 15, -}; - -FILE *vga_init(void *buffer); - -struct VGA : public kIoDevice { - VGA(void *addr); - - void putc(char a) override; - int puts(const char *string, int length) override; - void - flush() override - { - update_cursor(); - } - - struct __attribute__((packed)) VGAEntry { - unsigned char text; - unsigned char foreground : 4; - unsigned char background : 4; - }; - -private: - void clear(enum vga_color foreground, enum vga_color background); - void update_cursor(); - - struct VGAEntry *buffer; - int col = 0; - int row = 0; -}; diff --git a/grub/BUILD.bazel b/grub/BUILD.bazel new file mode 100644 index 0000000..2d12cc1 --- /dev/null +++ b/grub/BUILD.bazel @@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +exports_files(["grub.cfg"]) + +cc_library( + name = "multiboot2", + hdrs = ["include/multiboot2.h"], + includes = ["include"], +) diff --git a/grub/multiboot2.h b/grub/include/multiboot2.h index 5a3db5a..5a3db5a 100644 --- a/grub/multiboot2.h +++ b/grub/include/multiboot2.h diff --git a/i686-elf-gcc.txt b/i686-elf-gcc.txt new file mode 100644 index 0000000..b5f3bd0 --- /dev/null +++ b/i686-elf-gcc.txt @@ -0,0 +1,9 @@ +[binaries] +c = 'i686-elf-gcc' +cpp = 'i686-elf-g++' +ld = 'i686-elf-ld' +ar = 'i686-elf-ar' +strip = 'i686-elf-strip' + +[built-in options] +c_args = ['-ffreestanding', '-mgeneral-regs-only'] diff --git a/i686/Makefile b/i686/Makefile deleted file mode 100644 index ba780a9..0000000 --- a/i686/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -include ../Makefile.config - -INCLUDES := -isystem../grub -${ARCH}_CFLAGS += ${INCLUDES} -${ARCH}_CXXFLAGS += ${INCLUDES} - -TARGETLIB += arch -arch.SRCS = boot.S init.s \ - gdt.c lgdt.c \ - lidt.c isr.c - -include ../rules.mk - diff --git a/i686/gdt.h b/i686/gdt.h deleted file mode 100644 index f00ff7f..0000000 --- a/i686/gdt.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include <stdbool.h> -#include <stdint.h> - -enum Ring { Ring0 = 0x0, Ring1 = 0x1, Ring2 = 0x2, Ring3 = 0x3 }; - -struct __attribute__((packed)) Access { - bool accessed : 1; // if 0, is set by processor when accessed - bool readwrite : 1; // code seg: read toggle; data seg: write toggle - bool direction : 1; // code seg: conforming bit; data seg: direction bit - bool executable : 1; // executable bit - bool segment : 1; // true for code/data; false for gates/tss - enum Ring privilege : 2; // descriptor privilege level - bool present : 1; // true for every active segment -}; -_Static_assert(sizeof(struct Access) == 1, "access byte size"); - -static const struct Access null_access = {false, false, false, false, false, false, false}; -static const struct Access ktext_access = {.readwrite = true, .executable = true, .segment = true, .present = true}; -static const struct Access kdata_access = {.readwrite = true, .segment = true, .present = true}; - -// Segment Descriptor -// A memory structure (part of a table) that tells the CPU the attributes of a given segment -// |31| | | | | | |24|23|22|21|20|19| | |16|15| | | | | | | 8| 7| | | | | | | 0| -// | base_31_24 | G|DB| | A| lim_19_16 | access | base_23_16 | -// | base_15_0 | limit_15_0 | -// |31| | | | | | | | | | | | | | |16|15| | | | | | | | | | | | | | | 0| -// limit size of segment - 1, either in bytes or in 4KiB chunks (check flags) -// base address of segment -// access -// flags defines the segment chunks and 16/32 bit -struct __attribute__((packed)) SegmentDescriptor_t { - uint16_t limit_15_0; // low bits of segment limit - uint16_t base_15_0; // low bits of segment base address - uint8_t base_23_16; // middle bits of segment base address - uint8_t access; // access byte - uint8_t limit_19_16 : 4; // high bits of segment limit - // flags - bool a : 1; // unused, available for software use - bool rsv : 1; // reserved - bool db : 1; // false => 16-bit seg; true => 32-bit seg - bool granularity : 1; // limit scaled by 4k when set - uint8_t base_31_24; // high bits of segment address -}; -_Static_assert(sizeof(struct SegmentDescriptor_t) == 8, "segment descriptor size"); - -void SegmentDescriptor(struct SegmentDescriptor_t *self, unsigned base, unsigned limit, uint8_t access); - -void gdt_install(); - -enum SegmentIndex { - ktextDescriptor = 2 * sizeof(struct SegmentDescriptor_t), - kdataDescriptor = 3 * sizeof(struct SegmentDescriptor_t), -}; diff --git a/i686/lgdt.c b/i686/lgdt.c deleted file mode 100644 index 10781db..0000000 --- a/i686/lgdt.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "gdt.h" - -struct __attribute__((packed)) Pointer { - uint16_t limit; - uint32_t base; -}; - -static struct SegmentDescriptor_t segments[8] __attribute__((aligned(32))); - -void -gdt_install() -{ - SegmentDescriptor(&segments[0], 0, 0, 0); // null segment - SegmentDescriptor(&segments[2], 0, 0xffffffff, 0x9a); // ktext - SegmentDescriptor(&segments[3], 0, 0xffffffff, 0x92); // kdata - - const struct Pointer ptr = {.limit = sizeof(segments) - 1, .base = (unsigned)&segments}; - asm volatile("lgdt (%0)" : : "a"(&ptr)); - - // load the kernel data segment - asm volatile(R"(mov %0, %%ds - mov %0, %%es - mov %0, %%fs - mov %0, %%gs - mov %0, %%ss -)" - : - : "ax"(kdataDescriptor)); - - // load the kernel code segment - asm volatile(R"(ljmp %0, $1f - 1:)" - : - : "i"(ktextDescriptor)); -} diff --git a/i686/lidt.c b/i686/lidt.c deleted file mode 100644 index cf8084e..0000000 --- a/i686/lidt.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "idt.h" -#include <stdint.h> - -struct __attribute__((packed)) Pointer { - uint16_t limit; - uint32_t base; -}; - -enum Type { - Null = 0, - Intr = 0x8e, // 1000 1110 32-bit interrupt -}; - -struct __attribute__((packed)) Gate_t { - uint16_t offset_15_0; // segment offset low - uint16_t selector; // code segment selector - uint8_t __unused; // unused in protected mode - uint8_t type; // interrupt type - uint16_t offset_31_16; // segment offset high -}; -_Static_assert(sizeof(struct Gate_t) == 8, "interrupt gate size"); - -void -Gate(struct Gate_t *entry, void (*f)(struct interrupt_frame *), uint16_t selector) -{ - uint32_t f_addr = (uint32_t)f; - entry->offset_15_0 = f_addr & 0xffff; - entry->offset_31_16 = (f_addr >> 16) & 0xffff; - entry->selector = selector; - entry->__unused = 0; - entry->type = Intr; -} - -static struct Gate_t interrupt_table[256] __attribute((aligned(4096))); - -void -idt_install() -{ - // exceptions 0x00~0x13 - for (int i = 0; i <= 0x13; ++i) Gate(&interrupt_table[i], &abort_handler, 0x10); - - // irq 0x20~0x2f - for (int i = 0x22; i <= 0x2f; ++i) Gate(&interrupt_table[i], &abort_handler, 0x10); - Gate(&interrupt_table[0x20], &irq0x00, 0x10); - Gate(&interrupt_table[0x21], &irq0x01, 0x10); - Gate(&interrupt_table[0x2c], &irq0x0c, 0x10); - - // syscall 0x80 - Gate(&interrupt_table[0x80], &syscall_handler, 0x10); - - const struct Pointer ptr = {.limit = sizeof(interrupt_table) - 1, .base = (unsigned)&interrupt_table}; - asm volatile("lidt (%0)" : : "a"(&ptr)); -} diff --git a/i686/macros.s b/i686/macros.s deleted file mode 100644 index a9b8b4d..0000000 --- a/i686/macros.s +++ /dev/null @@ -1,25 +0,0 @@ -.set PAGE_RO, 0x001 -.set PAGE_RW, 0x003 -/* write section to page table macro - * - * Registers used: - * %ecx: loop counter [ set to $1024 ] - * %edx: temporary - * %esi: current page being mapped - * %edi: page entry [ set to $page_addr ] - */ -.macro mmap_section begin, end, access - mov $\begin, %esi # from $begin -1: cmpl $\end, %esi # until $end - jge 2f - - movl %esi, %edx - orl $\access, %edx - movl %edx, (%edi) - - addl $4096, %esi # move to next page - addl $4, %edi # size of page entry is 4 bytes - loop 1b # loop according to %ecx -2: -.endm - diff --git a/i686/paging.h b/i686/paging.h deleted file mode 100644 index f9c04a8..0000000 --- a/i686/paging.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -// DirectoryEntry -// |31| | | | | | | | | | | | | | | | | | | |11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| -// | page table 4-kb aligned address | avail | G| S| | A| C| W| U| R| P| -struct __attribute__((packed)) DirectoryEntry { - unsigned present : 1; // 0: if set, the page is actually in physical memory - unsigned writeable : 1; // 1: if set, the page is read/write; otherwise the page is read-only - unsigned user : 1; // 2: if set, then page can be access by all; otherwise only the supervisor can access it - unsigned writethrough : 1; // 3: if set, write-through caching is enabled; otherwise write-back is enabled instead - unsigned cachedisable : 1; // 4: if set, the page will not be cached - unsigned accessed : 1; // 5: set by the CPU when the page is read from or written to - unsigned dirty : 1; // 6: used to determine whether a page has been written to - unsigned pagesize : 1; // 7: page size == 0 - unsigned global : 1; - unsigned int __available__ : 3; // available to the OS - unsigned int address : 20; -}; -_Static_assert(sizeof(struct DirectoryEntry) == 4, "DirectoryEntry size"); - -// DirectoryEntry4MB -// |31| | | | | | | | |22|21|20| | | | | | |13|12|11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| -// | bits 31-22 of address |RS| bits 39-22 of |AT| avail | G|PS| D| A|CD|WT|US|RW| P| -// | |VD| address -struct __attribute__((packed)) DirectoryEntry4MB { - unsigned present : 1; // 0: if set, the page is actually in physical memory - unsigned writeable : 1; // 1: if set, the page is read/write; otherwise the page is read-only - unsigned useraccess : 1; // 2: if set, then page can be access by all; otherwise only the supervisor can access it - unsigned writethrough : 1; // 3: if set, write-through caching is enabled; otherwise write-back is enabled instead - unsigned cachedisable : 1; // 4: if set, the page will not be cached - unsigned accessed : 1; // 5: set by the CPU when the page is read from or written to - unsigned dirty : 1; // 6: used to determine whether a page has been written to - unsigned pagesize : 1; // 7: page size == 1 - unsigned global : 1; // 8: - unsigned __available__ : 3; // 11..9 available to the OS - unsigned pat : 1; // 12: page attribute table - unsigned int address_high : 8; - unsigned rsvd : 1; // 21 - unsigned int address_low : 10; -}; -_Static_assert(sizeof(struct DirectoryEntry4MB) == 4, "DirectoryEntry4M size"); - -// TableEntry -// |31| | | | | | | | | | | | | | | | | | | |11| | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| -// | page table 4-kb aligned address | avail | G| | D| A| C| W|US|RW| P| -struct __attribute__((packed)) TableEntry { - unsigned present : 1; // if set, the page is actually in physical memory - unsigned writeable : 1; // if set, the page is read/write; otherwise the page is read-only - unsigned user : 1; // if set, then page can be access by all; otherwise only the supervisor can access it - unsigned writethrough : 1; // if set, write-through caching is enabled; otherwise write-back is enabled instead - unsigned cachedisable : 1; // if set, the page will not be cached - unsigned accessed : 1; // set by the CPU when the page is read from or written to - unsigned dirty : 1; // used to determine whether a page has been written to - unsigned pat : 1; // page attribute table? - unsigned global : 1; - unsigned int __available__ : 3; // available to the OS - unsigned int address : 20; -}; -_Static_assert(sizeof(struct TableEntry) == 4, "TableEntry size"); diff --git a/i686/sys/control.h b/i686/sys/control.h deleted file mode 100644 index 7dde3c8..0000000 --- a/i686/sys/control.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -static inline void -abort() -{ - /* Symbol h is already defined? -asm volatile(R"(cli -h: hlt -jmp h)"); -*/ - asm volatile(R"(cli -hlt)"); -} - -static inline void -enable_interrupts() -{ - asm volatile("sti"); -} - -static inline void -disable_interrupts() -{ - asm volatile("cli"); -} diff --git a/i686/sys/io.h b/i686/sys/io.h deleted file mode 100644 index b6c24c5..0000000 --- a/i686/sys/io.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -// port listings -enum UART { - COM1 = 0x3f8, - COM2 = 0x2f8, - COM3 = 0x3e8, - COM4 = 0x2e8, - COM5 = 0x5f8, - COM6 = 0x4f8, - COM7 = 0x5e8, - COM8 = 0x4e8, -}; -enum UARTPortOffset { - Data = 0, // read from receive buffer / write to transmit buffer | BaudDiv_l - InterruptControl = 1, // interrupt enable | BaudDiv_h - FifoControl = 2, // interrupt ID and FIFO control - LineControl = 3, // most significant bit is the DLAB - ModemControl = 4, - LineStatus = 5, - ModemStatus = 6, - Scratch = 7, -}; - -static inline void -outb(unsigned char val, unsigned short port) -{ - asm volatile("outb %0,%1" : : "a"(val), "dN"(port)); -} - -static inline void -outw(unsigned short val, unsigned short port) -{ - asm volatile("outw %0,%1" : : "a"(val), "dN"(port)); -} - -static inline void -outl(unsigned int val, unsigned short port) -{ - asm volatile("outl %0,%1" : : "a"(val), "dN"(port)); -} - -static inline unsigned char -inb(unsigned short port) -{ - unsigned char val; - asm volatile("inb %1,%0" : "=a"(val) : "dN"(port)); - return val; -} - -static inline unsigned short -inw(unsigned short port) -{ - unsigned short val; - asm volatile("inw %1,%0" : "=a"(val) : "dN"(port)); - return val; -} - -static inline unsigned int -inl(unsigned short port) -{ - unsigned int val; - asm volatile("inl %1,%0" : "=a"(val) : "dN"(port)); - return val; -} - -static inline void -outsb(unsigned short port, const void *__buf, unsigned long __n) -{ - asm volatile("cld; rep; outsb" : "+S"(__buf), "+c"(__n) : "d"(port)); -} - -static inline void -outsw(unsigned short port, const void *__buf, unsigned long __n) -{ - asm volatile("cld; rep; outsw" : "+S"(__buf), "+c"(__n) : "d"(port)); -} - -static inline void -outsl(unsigned short port, const void *__buf, unsigned long __n) -{ - asm volatile("cld; rep; outsl" : "+S"(__buf), "+c"(__n) : "d"(port)); -} - -static inline void -insb(unsigned short port, void *__buf, unsigned long __n) -{ - asm volatile("cld; rep; insb" : "+D"(__buf), "+c"(__n) : "d"(port)); -} - -static inline void -insw(unsigned short port, void *__buf, unsigned long __n) -{ - asm volatile("cld; rep; insw" : "+D"(__buf), "+c"(__n) : "d"(port)); -} - -static inline void -insl(unsigned short port, void *__buf, unsigned long __n) -{ - asm volatile("cld; rep; insl" : "+D"(__buf), "+c"(__n) : "d"(port)); -} - diff --git a/i686/sys/io.hpp b/i686/sys/io.hpp deleted file mode 100644 index 9759a3a..0000000 --- a/i686/sys/io.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -/** - * Ports provide communication with devices on the x86 IO bus. - */ -template <typename T, unsigned short port> struct Port { - /** - * Read value from port - */ - static T - in(unsigned short offset = 0) - { - if constexpr (sizeof(T) == sizeof(unsigned char)) return inb(port + offset); - else if constexpr (sizeof(T) == sizeof(unsigned short)) - return inw(port + offset); - else if constexpr (sizeof(T) == sizeof(unsigned int)) - return inl(port + offset); - } - - /** - * Write value to port - */ - static void - out(T val, unsigned short offset = 0) - { - if constexpr (sizeof(T) == sizeof(unsigned char)) outb(val, port + offset); - else if constexpr (sizeof(T) == sizeof(unsigned short)) - outw(val, port + offset); - else if constexpr (sizeof(T) == sizeof(unsigned int)) - outl(val, port + offset); - } - -}; diff --git a/i686/test/gdt.c b/i686/test/gdt.c deleted file mode 100644 index 2947b42..0000000 --- a/i686/test/gdt.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "gdt.h" -#include <assert.h> -#include <stdlib.h> - -int -main() -{ - assert(*(uint8_t *)&null_access == 0x00); - assert(*(uint8_t *)&ktext_access == 0x9a); - assert(*(uint8_t *)&kdata_access == 0x92); - - struct SegmentDescriptor_t d; - SegmentDescriptor(&d, 0, 0, 0); - assert(*(uint64_t *)&d == 0); - - assert(ktextDescriptor == 0x10); - assert(kdataDescriptor == 0x18); - - return EXIT_SUCCESS; -} diff --git a/i686/toolchain.mk b/i686/toolchain.mk deleted file mode 100644 index 791966b..0000000 --- a/i686/toolchain.mk +++ /dev/null @@ -1,40 +0,0 @@ -ARCH=i686 - -# define compiler, linker, archiver and strip and their flags -# FIXME: cpp threadsafe statics -${ARCH}_AS := i686-elf-as - -${ARCH}_CC := i686-elf-gcc -${ARCH}_CCID := $(shell ${${ARCH}_CC} --version | head -n1) -${ARCH}_CFLAGS := -Wall -Wextra -Wpedantic -Werror=shadow -Wconversion -fanalyzer -ffreestanding -std=gnu11 \ - -mgeneral-regs-only \ - $(shell echo ${CONFIG_CFLAGS}) - -${ARCH}_CXX := i686-elf-g++ -${ARCH}_CXXID := $(shell ${${ARCH}_CXX} --version | head -n1) -${ARCH}_CXXFLAGS := -Wall -Wextra -Wpedantic -Werror=shadow -Wconversion -ffreestanding -std=c++17 \ - -mgeneral-regs-only -fno-use-cxa-atexit -fno-threadsafe-statics -fno-exceptions -fno-rtti \ - $(shell echo ${CONFIG_CXXFLAGS}) - -${ARCH}_LD := i686-elf-ld -${ARCH}_LDID := $(shell ${${ARCH}_LD} --version | head -n1) -${ARCH}_LDFLAGS := -static -nostdlib \ - $(shell echo ${CONFIG_LDFLAGS}) - -${ARCH}_AR := i686-elf-ar -${ARCH}_ARFLAGS := -crus - -${ARCH}_STRIP := i686-elf-strip - -# define compiler and flags for test targets -HOST_CC := gcc -HOST_CFLAGS := -Wall -Wextra -Wpedantic -Werror=shadow -Wconversion \ - ${CFLAGS} -HOST_CXX := g++ -HOST_CXXFLAGS := -Wall -Wextra -Wpedantic -Werror=shadow -Wconversion -g -Og \ - $(shell pkg-config --cflags --libs gtest gtest_main gmock) \ - ${CXXFLAGS} - -# emulator name and flags -QEMU := qemu-system-i386 -accel kvm -machine pc - diff --git a/kernel/BUILD.bazel b/kernel/BUILD.bazel new file mode 100644 index 0000000..e7ed087 --- /dev/null +++ b/kernel/BUILD.bazel @@ -0,0 +1,37 @@ +load("//tools:configure_file.bzl", "configure_file") + +configure_file( + name = "conf", + template = "conf.h.in", +) + +cc_binary( + name = "glitch.elf", + srcs = [ + "boot.h", + "kernel.c", + "mem.h", + "mem/vmm.c", + "mmap.c", + "mmap.h", + "multiboot2.c", + "task.h", + ":conf.h", + ], + includes = ["."], + linkopts = [ + "-T", + "$(location //arch/i386:linker.ld)", + ], + target_compatible_with = [ + "@platforms//os:none", + ], + visibility = ["//visibility:public"], + deps = [ + "//arch/i386:arch", + "//arch/i386:linker.ld", + "//devices:drivers", + "//grub:multiboot2", + "//lib/libk:k", + ], +) diff --git a/kernel/boot.h b/kernel/boot.h new file mode 100644 index 0000000..646fb4c --- /dev/null +++ b/kernel/boot.h @@ -0,0 +1,21 @@ +/* *** glitch kernel *** + * spdx-license-identifier: ISC + * description: kernel boot information + * */ + +#pragma once + +typedef struct { + /* kernel command line */ + char cmdline[64]; + + /* memory map */ + unsigned bitmap[1024 * 32]; + + /* module */ + unsigned module_start; + unsigned module_end; + char module_cmdline[64]; +} boot_info_t; + +/* TODO _Static_assert((1024 * 32 * sizeof(unsigned) * 8) == (1024 * 1024), "bitmap size check"); */ diff --git a/kernel/conf.h.in b/kernel/conf.h.in new file mode 100644 index 0000000..61352d7 --- /dev/null +++ b/kernel/conf.h.in @@ -0,0 +1,4 @@ +#pragma once + +#define VERSION {VERSION} +#define CC {CC} diff --git a/src/kernel.cpp b/kernel/kernel.c index 063fe11..98269c1 100644 --- a/src/kernel.cpp +++ b/kernel/kernel.c @@ -1,10 +1,8 @@ -//===================================================================== -// glitch kernel -// spdx-license-identifier: ISC -// description: kernel entry point -//===================================================================== +/* *** glitch kernel *** + * spdx-license-identifier: ISC + * description: kernel entry point + * */ -extern "C" { #include "conf.h" #include "mem.h" #include <keyboard.h> @@ -13,31 +11,31 @@ extern "C" { #include <ps2_controller.h> #include <stdio.h> #include <sys/cpuid.h> -} -#include <uart.hpp> -#include <vga.hpp> +#include <uart.h> +#include <vga.h> FILE *stdin; FILE *stdout; FILE *stderr; -extern "C" void -kmain() +void +kmain(void) { - stderr = uart_init<COM1>(); + stderr = uart_init(COM1); vmm_map(0xb8000, 0xc03ff000); stdout = vga_init((void *)0xc03ff000); printf("glitch [version " VERSION "] [" CC "]\n"); fprintf(stderr, "glitch [version " VERSION "] [" CC "]\n"); { + struct CPUVersion v; + char vendor[13] = {'\0'}; unsigned int eax; __get_cpuid(0, &eax, (unsigned int *)vendor, (unsigned int *)(vendor + 8), (unsigned int *)(vendor + 4)); - struct CPUVersion v; __get_cpuid(1, (unsigned int *)&v, &eax, &eax, &eax); - printf("CPU: %s family %u model %u stepping %u\n", vendor, family(v), model(v), v.stepping); - fprintf(stderr, "CPU: %s family %u model %u stepping %u\n", vendor, family(v), model(v), v.stepping); + printf("cpuid: %s family %u model %u stepping %u\n", vendor, family(v), model(v), v.stepping); + fprintf(stderr, "cpuid: %s family %u model %u stepping %u\n", vendor, family(v), model(v), v.stepping); } pic_init(); diff --git a/src/mem/vmm.c b/kernel/mem/vmm.c index 77b06a8..a07dd72 100644 --- a/src/mem/vmm.c +++ b/kernel/mem/vmm.c @@ -16,15 +16,15 @@ to_vaddr(unsigned paddr) unsigned int vmm_map(unsigned int paddr, unsigned int vaddr) { - if (paddr & 0xfff || vaddr & 0xfff) return 0; + struct TableEntry *table; + const unsigned table_idx = vaddr >> 22; /* high 10 bits */ + const unsigned entry_idx = (vaddr >> 12) & 0x3ff; /* low 10 bits */ - const unsigned table_idx = vaddr >> 22; // high 10 bits - const unsigned entry_idx = (vaddr >> 12) & 0x3ff; // low 10 bits + if (paddr & 0xfff || vaddr & 0xfff) return 0; if (k_pagedir[table_idx].present == 0) return 0; - struct TableEntry *table = (struct TableEntry *)to_vaddr(k_pagedir[table_idx].address << 12); - - table[entry_idx].address = paddr >> 12; + table = (struct TableEntry *)to_vaddr(k_pagedir[table_idx].address << 12); + table[entry_idx].address = (paddr >> 12) & 0xfffff; table[entry_idx].present = 1; table[entry_idx].writeable = 1; @@ -34,14 +34,12 @@ vmm_map(unsigned int paddr, unsigned int vaddr) void alloc4M() { - // enable pse in cr4 - asm volatile(R"( - movl %cr4, %eax - orl $0x10, %eax - movl %eax, %cr4 -)"); - - struct DirectoryEntry4MB *directory = (struct DirectoryEntry4MB *)&k_pagedir[0x301]; + struct DirectoryEntry4MB *directory; + + /* enable pse in cr4 */ + __asm__("movl %cr4, %eax; orl $0x10, %eax; movl %eax, %cr4"); + + directory = (struct DirectoryEntry4MB *)&k_pagedir[0x301]; directory->address_low = 0x1; directory->present = 1; directory->writeable = 1; diff --git a/src/mmap.c b/kernel/mmap.c index 3fe35b5..e5d4be6 100644 --- a/src/mmap.c +++ b/kernel/mmap.c @@ -1,4 +1,6 @@ #include "mmap.h" +#include <multiboot2.h> + #ifdef DEBUG #include <stdio.h> #endif @@ -6,16 +8,20 @@ __attribute__((section(".multiboot.text"))) unsigned multiboot2_mmap(const struct multiboot_mmap_entry entries[], unsigned entry_count, unsigned bitmap[1024 * 32]) { - // clear out the bitmap - for (unsigned i = 0; i < 1024 * 32; ++i) bitmap[i] = 0; - unsigned avail_frames = 0; + unsigned i, l; + multiboot_uint64_t avail_frames = 0; + multiboot_uint64_t n_frames; + multiboot_uint64_t table_idx; + + /* clear out the bitmap */ + for (i = 0; i < 1024 * 32; ++i) bitmap[i] = 0; - // loop through all the mmap_entry structures where type is MULTIBOOT_MEMORY_AVAILABLE - for (unsigned i = 0; i < entry_count; ++i) { + /* loop through all the mmap_entry structures where type is MULTIBOOT_MEMORY_AVAILABLE */ + for (i = 0; i < entry_count; ++i) { if (entries[i].type != MULTIBOOT_MEMORY_AVAILABLE) continue; - // number of frames in this entry - unsigned n_frames = entries[i].len / 4096; + /* number of frames in this entry */ + n_frames = entries[i].len / 4096; avail_frames += n_frames; #ifdef DEBUG @@ -23,8 +29,8 @@ multiboot2_mmap(const struct multiboot_mmap_entry entries[], unsigned entry_coun n_frames / 32, n_frames % 32); #endif - // the bitmap is an array of blocks, each holding 32 (2^5) values - unsigned table_idx = (entries[i].addr >> 17); // get the upper 15 bits + /* the bitmap is an array of blocks, each holding 32 (2^5) values */ + table_idx = (entries[i].addr >> 17); /* get the upper 15 bits */ while (n_frames != 0) { if (n_frames >= 32) { @@ -34,7 +40,7 @@ multiboot2_mmap(const struct multiboot_mmap_entry entries[], unsigned entry_coun } else { unsigned block = bitmap[table_idx]; - for (unsigned l = 0; l < n_frames; ++l) block |= (1 << l); + for (l = 0; l < n_frames; ++l) block |= (1 << l); bitmap[table_idx] = block; n_frames = 0; } diff --git a/src/mmap.h b/kernel/mmap.h index 13f40f2..13f40f2 100644 --- a/src/mmap.h +++ b/kernel/mmap.h diff --git a/src/multiboot2.c b/kernel/multiboot2.c index ea06e96..bd6250f 100644 --- a/src/multiboot2.c +++ b/kernel/multiboot2.c @@ -7,7 +7,8 @@ boot_info_t info __attribute__((section(".init"))); __attribute__((section(".multiboot.text"))) void multiboot_strncpy(char *dest, const char *src, unsigned n) { - for (unsigned i = 0; i < n && src[i] != '\0'; ++i) dest[i] = src[i]; + unsigned i; + for (i = 0; i < n && src[i] != '\0'; ++i) dest[i] = src[i]; } __attribute__((section(".multiboot.text"))) void @@ -44,6 +45,6 @@ __multiboot2(multiboot_uint32_t addr) break; default: break; - } // switch - } // for + } + } } diff --git a/src/sched.hpp b/kernel/sched.hpp index cfa3ff0..cfa3ff0 100644 --- a/src/sched.hpp +++ b/kernel/sched.hpp diff --git a/src/sched/roundrobin.cpp b/kernel/sched/roundrobin.cpp index c3d6cb6..c3d6cb6 100644 --- a/src/sched/roundrobin.cpp +++ b/kernel/sched/roundrobin.cpp diff --git a/src/tst/roundrobin.cc b/kernel/sched/test_roundrobin.cc index 1431788..89f60bf 100644 --- a/src/tst/roundrobin.cc +++ b/kernel/sched/test_roundrobin.cc @@ -43,7 +43,7 @@ TEST(roundrobin, RoundRobinQueue) std::cout << "Completed in (us): " << duration << std::endl; // test should complete in 250us unless running on valgrind - if (!RUNNING_ON_VALGRIND) EXPECT_LE(duration, 250); + if (!RUNNING_ON_VALGRIND) { EXPECT_LE(duration, 250); } EXPECT_EQ(queue.head, nullptr); EXPECT_EQ(queue.tail, nullptr); diff --git a/src/tst/taskqueue.cc b/kernel/sched/test_taskqueue.cc index 217c44d..217c44d 100644 --- a/src/tst/taskqueue.cc +++ b/kernel/sched/test_taskqueue.cc diff --git a/src/task.h b/kernel/task.h index 0d59bb1..0d59bb1 100644 --- a/src/task.h +++ b/kernel/task.h diff --git a/lib/Makefile b/lib/Makefile deleted file mode 100644 index f5eeded..0000000 --- a/lib/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -include ../Makefile.config - -TARGETLIB += libk -libk.SRCS = \ - libk/endian/little.c \ - libk/stdio/printf.c libk/stdio/fprintf.c libk/stdio/vfprintf.cpp \ - libk/stdlib/memcpy.c libk/stdlib/memset.c libk/stdlib/linked_list_allocator.c \ - libk/string/itoa.c - -TESTS += tst/endian_little tst/mem tst/string tst/linked_list_allocator - -TARGETLIB += blake2 -blake2.SRCS = blake2/blake2s.c -TESTS += tst/blake2s_selftest - -include ../rules.mk - diff --git a/lib/blake2/BUILD.bazel b/lib/blake2/BUILD.bazel new file mode 100644 index 0000000..4723ae6 --- /dev/null +++ b/lib/blake2/BUILD.bazel @@ -0,0 +1,28 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "blake2s", + srcs = ["blake2s.c"], + hdrs = ["include/blake2s.h"], + includes = ["include"], + deps = select({ + "@platforms//os:none": ["//lib/libk:k"], + "//conditions:default": [], + }), +) + +cc_test( + name = "test_blake2s", + srcs = [ + "blake2s_kat.h", + "blake2s_selftest.cc", + ], + target_compatible_with = select({ + "@platforms//os:none": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + deps = [ + "//lib/blake2:blake2s", + "@googletest//:gtest_main", + ], +) diff --git a/lib/blake2/blake2s.c b/lib/blake2/blake2s.c index b924a1e..9206c89 100644 --- a/lib/blake2/blake2s.c +++ b/lib/blake2/blake2s.c @@ -34,14 +34,16 @@ G(uint32_t v[16], unsigned a, unsigned b, unsigned c, unsigned d, uint32_t x, ui void F(struct BLAKE2s_ctx *ctx, uint32_t m[16], uint32_t f) { - // Initialize local work vector v + unsigned i; + + /* Initialize local work vector v */ uint32_t v[16] = {ctx->h[0], ctx->h[1], ctx->h[2], ctx->h[3], ctx->h[4], ctx->h[5], ctx->h[6], ctx->h[7], IV[0], IV[1], IV[2], IV[3], IV[4] ^ ctx->t[0], IV[5] ^ ctx->t[1], IV[6], IV[7]}; - if (f) v[14] = ~v[14]; // if last block flag, invert all bits + if (f) v[14] = ~v[14]; /* if last block flag, invert all bits */ - // cryptographic mixing - for (unsigned i = 0; i < 10; ++i) { + /* cryptographic mixing */ + for (i = 0; i < 10; ++i) { G(v, 0, 4, 8, 12, m[SIGMA[i][0]], m[SIGMA[i][1]]); G(v, 1, 5, 9, 13, m[SIGMA[i][2]], m[SIGMA[i][3]]); G(v, 2, 6, 10, 14, m[SIGMA[i][4]], m[SIGMA[i][5]]); @@ -53,8 +55,8 @@ F(struct BLAKE2s_ctx *ctx, uint32_t m[16], uint32_t f) G(v, 3, 4, 9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]); } - // xor the two halves - for (unsigned i = 0; i < 8; ++i) ctx->h[i] ^= (v[i] ^ v[i + 8]); + /* xor the two halves */ + for (i = 0; i < 8; ++i) ctx->h[i] ^= (v[i] ^ v[i + 8]); } int @@ -70,14 +72,14 @@ BLAKE2s_init(struct BLAKE2s_ctx *ctx, uint8_t outlen, const void *key, uint8_t k ctx->param.fanout = 1; ctx->param.depth = 1; - // copy IV into state vector h + /* copy IV into state vector h */ memcpy(ctx->h, IV, 32); - // copy param block 0 onto h[0] + /* copy param block 0 onto h[0] */ ctx->h[0] ^= (ctx->param.depth << 24) ^ (ctx->param.fanout << 16) ^ (keylen << 8) ^ outlen; if (keylen > 0) { BLAKE2s_update(ctx, key, keylen); - ctx->c = 64; // at the end + ctx->c = 64; /* at the end */ } return 0; @@ -88,15 +90,16 @@ BLAKE2s_init(struct BLAKE2s_ctx *ctx, uint8_t outlen, const void *key, uint8_t k void BLAKE2s_update(struct BLAKE2s_ctx *ctx, const void *d, size_t dd) { - for (unsigned i = 0; i < dd;) { + unsigned i, j; + for (i = 0; i < dd;) { - if (ctx->c == 64) { // if block is full, consume block + if (ctx->c == 64) { /* if block is full, consume block */ ctx->t[0] += ctx->c; if (ctx->t[0] < ctx->c) ctx->t[1] += 1; - ctx->c = 0; // reset counter + ctx->c = 0; /* reset counter */ uint32_t *m = (uint32_t *)ctx->b; - for (unsigned j = 0; j < 16; ++j) m[j] = htole32(m[j]); + for (j = 0; j < 16; ++j) m[j] = htole32(m[j]); F(ctx, m, 0); } @@ -110,14 +113,16 @@ BLAKE2s_update(struct BLAKE2s_ctx *ctx, const void *d, size_t dd) void BLAKE2s_final(struct BLAKE2s_ctx *ctx, void *out) { + unsigned i; + ctx->t[0] += ctx->c; if (ctx->t[0] < ctx->c) ctx->t[1] += 1; - for (; ctx->c < 64; ++(ctx->c)) ctx->b[ctx->c] = 0; // fill up block with zeroes + for (; ctx->c < 64; ++(ctx->c)) ctx->b[ctx->c] = 0; /* fill up block with zeroes */ uint32_t *m = (uint32_t *)ctx->b; - for (unsigned i = 0; i < 16; ++i) m[i] = htole32(m[i]); + for (i = 0; i < 16; ++i) m[i] = htole32(m[i]); F(ctx, m, 1); - for (unsigned i = 0; i < ctx->param.outlen; ++i) ((uint8_t *)out)[i] = (ctx->h[i >> 2] >> (8 * (i & 3))) & 0xff; + for (i = 0; i < ctx->param.outlen; ++i) ((uint8_t *)out)[i] = (ctx->h[i >> 2] >> (8 * (i & 3))) & 0xff; } diff --git a/lib/tst/blake2s_genkat.py b/lib/blake2/blake2s_genkat.py index 2dd5370..2dd5370 100755 --- a/lib/tst/blake2s_genkat.py +++ b/lib/blake2/blake2s_genkat.py diff --git a/lib/tst/blake2s_kat.h b/lib/blake2/blake2s_kat.h index aa42ef5..dec250a 100644 --- a/lib/tst/blake2s_kat.h +++ b/lib/blake2/blake2s_kat.h @@ -1,5 +1,7 @@ #pragma once +#include <cstdint> + static const unsigned KATs_len = 256; static const uint8_t KAT_secret[32] = { 0xba, 0x80, 0xfb, 0x8f, 0x1b, 0x7b, 0xa1, 0x49, 0x3c, 0x6a, 0xe8, 0x8f, 0xd, 0x66, 0xa1, 0xae, 0xff, 0xa2, 0x5c, 0x8a, 0x7d, 0x4c, 0x1f, 0xb6, 0x81, 0x1, 0xb5, 0xe4, 0xc2, 0x8e, 0x37, 0x3 }; static const uint8_t KATs[256][32] = { diff --git a/lib/tst/blake2s_selftest.cc b/lib/blake2/blake2s_selftest.cc index 58199f6..420544d 100644 --- a/lib/tst/blake2s_selftest.cc +++ b/lib/blake2/blake2s_selftest.cc @@ -1,8 +1,10 @@ // Self test Modules for BLAKE2s +#include "blake2s_kat.h" #include <gtest/gtest.h> -#include "../blake2/blake2s.c" -#include "blake2s_kat.h" +extern "C" { +#include "blake2s.h" +} static_assert(sizeof(BLAKE2s_param) == (8 * sizeof(uint32_t)), "sizeof struct BLAKE2s_param"); @@ -67,12 +69,6 @@ blake2s_selftest() return 0; } -TEST(blake2s, rotr_u32) -{ - EXPECT_EQ(rotr_u32(0xdecafade, 16), 0xfadedeca); - EXPECT_EQ(rotr_u32(0xdecafade, 8), 0xdedecafa); -} - TEST(blake2s, selftest) { EXPECT_EQ(blake2s_selftest(), 0); } TEST(blake2s, selftestAllInOne) diff --git a/lib/blake2/blake2s.h b/lib/blake2/include/blake2s.h index 64b4156..ede170c 100644 --- a/lib/blake2/blake2s.h +++ b/lib/blake2/include/blake2s.h @@ -4,8 +4,8 @@ #include <stdint.h> struct BLAKE2s_param { - uint8_t outlen; // digest length - uint8_t keylen; // key length + uint8_t outlen; /* digest length */ + uint8_t keylen; /* key length */ uint8_t fanout; uint8_t depth; uint32_t leaf_length; @@ -18,11 +18,11 @@ struct BLAKE2s_param { }; struct BLAKE2s_ctx { - uint8_t b[64]; // input buffer - size_t c; // pointer for b[] - uint32_t h[8]; // chained state vector h - uint32_t t[2]; // total number of bytes - struct BLAKE2s_param param; // parameter block + uint8_t b[64]; /* input buffer */ + size_t c; /* pointer for b[] */ + uint32_t h[8]; /* chained state vector h */ + uint32_t t[2]; /* total number of bytes */ + struct BLAKE2s_param param; /* parameter block */ }; /** @@ -41,11 +41,11 @@ int BLAKE2s_init(struct BLAKE2s_ctx *ctx, uint8_t outlen, const void *key, uint8 void BLAKE2s_update(struct BLAKE2s_ctx *ctx, const void *d, size_t dd); void BLAKE2s_final(struct BLAKE2s_ctx *ctx, void *out); -// All-in-one convenience function. -static inline int -BLAKE2s(void *out, uint8_t outlen, // return buffer for digest - const void *key, uint8_t keylen, // optional secret key - const void *in, size_t inlen) // data to be hashed +/* All-in-one convenience function. */ +static __inline__ int +BLAKE2s(void *out, uint8_t outlen, /* return buffer for digest */ + const void *key, uint8_t keylen, /* optional secret key */ + const void *in, size_t inlen) /* data to be hashed */ { struct BLAKE2s_ctx ctx; if (BLAKE2s_init(&ctx, outlen, key, keylen)) return -1; diff --git a/lib/libk/BUILD.bazel b/lib/libk/BUILD.bazel new file mode 100644 index 0000000..51b4c1b --- /dev/null +++ b/lib/libk/BUILD.bazel @@ -0,0 +1,80 @@ +filegroup( + name = "k_srcs", + srcs = [ + "endian/little.c", + "stdio/fprintf.c", + "stdio/printf.c", + "stdio/vfprintf.c", + "stdlib/linked_list_allocator.c", + "stdlib/memcpy.c", + "stdlib/memset.c", + "string/itoa.c", + ], +) + +cc_library( + name = "k", + srcs = [":k_srcs"], + hdrs = glob(["include/*.h"]), + includes = ["include"], + target_compatible_with = [ + "@platforms//os:none", + ], + visibility = ["//visibility:public"], +) + +# tests +cc_library( + name = "k_sut", + includes = ["."], + target_compatible_with = select({ + "@platforms//os:none": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + textual_hdrs = [":k_srcs"], +) + +cc_test( + name = "test_endian_little", + srcs = [ + "endian/test_endian_little.cc", + ], + deps = [ + ":k_sut", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_linked_list_allocator", + srcs = [ + "stdlib/test_allocator.hh", + "stdlib/test_linked_list_allocator.cc", + ], + deps = [ + ":k_sut", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_mem", + srcs = [ + "stdlib/test_mem.cc", + ], + deps = [ + ":k_sut", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_string", + srcs = [ + "string/test_string.cc", + ], + deps = [ + ":k_sut", + "@googletest//:gtest_main", + ], +) diff --git a/lib/libk/endian/little.c b/lib/libk/endian/little.c index 042bb55..56a20ad 100644 --- a/lib/libk/endian/little.c +++ b/lib/libk/endian/little.c @@ -1,6 +1,4 @@ -//===================================================================== -// spdx-license-identifier: ISC -//===================================================================== +/* spdx-license-identifier: ISC */ #include "endian.h" diff --git a/lib/tst/endian_little.cc b/lib/libk/endian/test_endian_little.cc index 9c8c73b..97ee286 100644 --- a/lib/tst/endian_little.cc +++ b/lib/libk/endian/test_endian_little.cc @@ -2,7 +2,7 @@ #include <gtest/gtest.h> namespace libk { -#include "../libk/endian/little.c" +#include "little.c" } // namespace libk TEST(endian_little, htole16) diff --git a/lib/libk/endian.h b/lib/libk/include/endian.h index 70bc5f7..6aa2669 100644 --- a/lib/libk/endian.h +++ b/lib/libk/include/endian.h @@ -1,13 +1,11 @@ -//===================================================================== -// spdx-license-identifier: ISC -//===================================================================== +/* spdx-license-identifier: ISC */ #pragma once #include <stdint.h> -// These functions convert the byte encoding of integer values from host byte order to and from little-endian and -// big-endian byte order +/* These functions convert the byte encoding of integer values from host byte order to and from little-endian and + * big-endian byte order */ uint16_t htole16(uint16_t host_16b); uint32_t htole32(uint32_t host_32b); uint64_t htole64(uint64_t host_64b); diff --git a/lib/libk/stdio.h b/lib/libk/include/stdio.h index 5ef68f1..7a6e663 100644 --- a/lib/libk/stdio.h +++ b/lib/libk/include/stdio.h @@ -2,27 +2,19 @@ #include <stdarg.h> -///@defgroup libk libk -///@{ -///@defgroup stdio stdio -///@{ +/** An object type used for streams */ +typedef struct FILE { + int id; -#ifdef __cplusplus -/** - * An object type used for streams - */ -struct kIoDevice { /** Function that prints a character to the stream */ - virtual void putc(char) = 0; + void (*putc)(const struct FILE *, char); + /** Function that prints a string to the stream */ - virtual int puts(const char *, int) = 0; + int (*puts)(const struct FILE *, const char *, int); + /** Flush write buffers */ - virtual void flush() = 0; -}; -typedef kIoDevice FILE; -#else -typedef void FILE; -#endif + void (*flush)(const struct FILE *); +} FILE; /** A FILE value corresponding to stdin, the keyboard buffer */ extern FILE *stdin; @@ -31,28 +23,19 @@ extern FILE *stdout; /** A FILE value corresponding to stderr, the uart */ extern FILE *stderr; -#ifdef __cplusplus -extern "C" { -#endif /** * Write the formatted string to stdout * Supports ``%s`` (string), ``%d`` (decimal), ``%u`` (unsigned), ``%x`` (hexadecimal) * @return number of bytes written */ -int printf(const char *restrict format, ...); +int printf(const char *__restrict__ format, ...); /** * Write the formatted string to stream; see printf */ -int fprintf(FILE *restrict stream, const char *restrict format, ...); +int fprintf(FILE *__restrict__ stream, const char *__restrict__ format, ...); /** * Write the formatted string to stream; see printf */ -int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap); -#ifdef __cplusplus -} -#endif - -///@} -///@} +int vfprintf(FILE *__restrict__ stream, const char *__restrict__ format, va_list ap); diff --git a/lib/libk/stdlib.h b/lib/libk/include/stdlib.h index 84d9b2d..143c931 100644 --- a/lib/libk/stdlib.h +++ b/lib/libk/include/stdlib.h @@ -2,11 +2,6 @@ #include <stddef.h> -///@defgroup libk libk -///@{ -///@defgroup stdlib stdlib -///@{ - /** * Allocate size bytes and return a pointer to the allocated memory */ @@ -25,7 +20,4 @@ void *memset(void *s, int c, long unsigned n); /** * Copy n bytes from memory area src to memory area dest. The memory areas must not overlap. */ -void *memcpy(void *restrict dest, const void *restrict src, long unsigned n); - -///@} -///@} +void *memcpy(void *__restrict__ dest, const void *__restrict__ src, long unsigned n); diff --git a/lib/libk/include/string.h b/lib/libk/include/string.h new file mode 100644 index 0000000..45b05a5 --- /dev/null +++ b/lib/libk/include/string.h @@ -0,0 +1,14 @@ +#pragma once + +#define OCTAL 8 +#define DECIMAL 10 +#define HEX 16 + +/** + * Convert int into a string + */ +char *itoa(char *p, int x, unsigned base); +/** + * Convert unsigned int into a string + */ +char *utoa(char *p, unsigned x, unsigned base); diff --git a/lib/libk/stdio/fprintf.c b/lib/libk/stdio/fprintf.c index 9a96dc6..c088f54 100644 --- a/lib/libk/stdio/fprintf.c +++ b/lib/libk/stdio/fprintf.c @@ -1,11 +1,12 @@ #include <stdio.h> int -fprintf(FILE *restrict stream, const char *restrict format, ...) +fprintf(FILE *__restrict__ stream, const char *__restrict__ format, ...) { + int c = 0; va_list ap; va_start(ap, format); - int c = vfprintf(stream, format, ap); + c += vfprintf(stream, format, ap); va_end(ap); return c; } diff --git a/lib/libk/stdio/printf.c b/lib/libk/stdio/printf.c index 4efc1ac..4c45593 100644 --- a/lib/libk/stdio/printf.c +++ b/lib/libk/stdio/printf.c @@ -1,11 +1,12 @@ #include <stdio.h> int -printf(const char *restrict format, ...) +printf(const char *__restrict__ format, ...) { + int c = 0; va_list ap; va_start(ap, format); - int c = vfprintf(stdout, format, ap); + c += vfprintf(stdout, format, ap); va_end(ap); return c; } diff --git a/lib/libk/stdio/vfprintf.cpp b/lib/libk/stdio/vfprintf.c index aa9256d..807c26a 100644 --- a/lib/libk/stdio/vfprintf.cpp +++ b/lib/libk/stdio/vfprintf.c @@ -3,40 +3,41 @@ static char buffer[3 * sizeof(int) + 2]; -extern "C" int -vfprintf(FILE *restrict stream, const char *restrict format, va_list params) +int +vfprintf(FILE *__restrict__ stream, const char *__restrict__ format, va_list params) { int written = 0; + int i; int s = 0; int l = 0; - for (int i = 0; format[i] != '\0'; ++i) { + for (i = 0; format[i] != '\0'; ++i) { if (format[i] == '%') { - written += stream->puts(&format[s], l); + written += stream->puts(stream, &format[s], l); s = i + 2; ++i; switch (format[i]) { case 's': { const char *arg = va_arg(params, const char *); - written += stream->puts(arg, -1); + written += stream->puts(stream, arg, -1); } break; case 'c': { - const int arg = va_arg(params, int); - stream->putc(arg); + const char arg = (char)va_arg(params, int); + stream->putc(stream, arg); ++written; } break; case 'd': { const char *arg = itoa(buffer, va_arg(params, int), 10); - written += stream->puts(arg, -1); + written += stream->puts(stream, arg, -1); } break; case 'u': { const char *arg = utoa(buffer, va_arg(params, unsigned int), 10); - written += stream->puts(arg, -1); + written += stream->puts(stream, arg, -1); } break; case 'x': { const char *arg = utoa(buffer, va_arg(params, unsigned int), 16); - written += stream->puts(arg, -1); + written += stream->puts(stream, arg, -1); } break; } @@ -47,8 +48,8 @@ vfprintf(FILE *restrict stream, const char *restrict format, va_list params) ++l; } - if (l > 0) { written += stream->puts(&format[s], l); } + if (l > 0) { written += stream->puts(stream, &format[s], l); } - stream->flush(); + stream->flush(stream); return written; } diff --git a/lib/libk/stdlib/linked_list_allocator.c b/lib/libk/stdlib/linked_list_allocator.c index 66c63d1..bcec580 100644 --- a/lib/libk/stdlib/linked_list_allocator.c +++ b/lib/libk/stdlib/linked_list_allocator.c @@ -31,13 +31,14 @@ alloc_init(void *mem, size_t size) void * malloc(size_t size) { + struct Chunk *iter; if (begin == NULL) return NULL; - // find free chunk that is at least (size + sizeof(struct Chunk)) - for (struct Chunk *iter = begin; iter != NULL; iter = iter->next) { + /* find free chunk that is at least (size + sizeof(struct Chunk)) */ + for (iter = begin; iter != NULL; iter = iter->next) { if (iter->used != 0 || iter->size < size) continue; - // if there's at least sizeof(struct Chunk) bytes left over, create a new Chunk + /* if there's at least sizeof(struct Chunk) bytes left over, create a new Chunk */ if (iter->size >= (size + 2 * sizeof(struct Chunk))) { struct Chunk *next = (struct Chunk *)((uintptr_t)iter + sizeof(struct Chunk) + size); Chunk_ctor(next, iter->size - size - sizeof(struct Chunk)); @@ -57,18 +58,20 @@ malloc(size_t size) void free(void *ptr) { + struct Chunk *chunk; if (ptr == NULL) return; - struct Chunk *chunk = (struct Chunk *)((uintptr_t)ptr - sizeof(struct Chunk)); + + chunk = (struct Chunk *)((uintptr_t)ptr - sizeof(struct Chunk)); chunk->used = 0; - // merge next chunk + /* merge next chunk */ if (chunk->next != NULL && chunk->next->used == 0) { chunk->size += chunk->next->size + sizeof(struct Chunk); chunk->next = chunk->next->next; if (chunk->next != NULL) chunk->next->prev = chunk; } - // merge into prev chunk + /* merge into prev chunk */ if (chunk->prev != NULL && chunk->prev->used == 0) { chunk->prev->size += chunk->size + sizeof(struct Chunk); chunk->prev->next = chunk->next; diff --git a/lib/libk/stdlib/memcpy.c b/lib/libk/stdlib/memcpy.c index 90470d5..db7d21e 100644 --- a/lib/libk/stdlib/memcpy.c +++ b/lib/libk/stdlib/memcpy.c @@ -1,5 +1,5 @@ void * -memcpy(void *restrict dest, const void *restrict src, long unsigned n) +memcpy(void *__restrict__ dest, const void *__restrict__ src, long unsigned n) { char *pDest = (char *)dest; const char *pSrc = (const char *)src; diff --git a/lib/libk/stdlib/memset.c b/lib/libk/stdlib/memset.c index a16bd05..2a86f8e 100644 --- a/lib/libk/stdlib/memset.c +++ b/lib/libk/stdlib/memset.c @@ -1,7 +1,8 @@ void * memset(void *s, int c, long unsigned n) { + unsigned i; char *pDest = (char *)s; - for (unsigned i = 0; i < n; ++i) pDest[i] = (char)c; + for (i = 0; i < n; ++i) pDest[i] = (char)c; return s; } diff --git a/lib/tst/allocator.hh b/lib/libk/stdlib/test_allocator.hh index 3bc1715..3bc1715 100644 --- a/lib/tst/allocator.hh +++ b/lib/libk/stdlib/test_allocator.hh diff --git a/lib/tst/linked_list_allocator.cc b/lib/libk/stdlib/test_linked_list_allocator.cc index a2575d5..5963ce1 100644 --- a/lib/tst/linked_list_allocator.cc +++ b/lib/libk/stdlib/test_linked_list_allocator.cc @@ -3,7 +3,7 @@ #include <iostream> namespace libk { -#include "../libk/stdlib/linked_list_allocator.c" +#include "linked_list_allocator.c" std::ostream & operator<<(std::ostream &os, const Chunk &b) @@ -16,7 +16,7 @@ operator<<(std::ostream &os, const Chunk &b) } }; // namespace libk -#include "allocator.hh" +#include "test_allocator.hh" TEST(UninitializedAllocator, malloc) { EXPECT_EQ(libk::malloc(1024), nullptr); } diff --git a/lib/tst/mem.cc b/lib/libk/stdlib/test_mem.cc index 1ad266c..f8a5e18 100644 --- a/lib/tst/mem.cc +++ b/lib/libk/stdlib/test_mem.cc @@ -3,8 +3,8 @@ #define restrict __restrict__ namespace libk { -#include "../libk/stdlib/memcpy.c" -#include "../libk/stdlib/memset.c" +#include "memcpy.c" +#include "memset.c" } // namespace libk TEST(mem, memset) diff --git a/lib/libk/string.h b/lib/libk/string.h deleted file mode 100644 index c8196c8..0000000 --- a/lib/libk/string.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -///@defgroup libk libk -///@{ -///@defgroup string string -///@{ - -#define OCTAL 8 -#define DECIMAL 10 -#define HEX 16 - -#ifdef __cplusplus -extern "C" { -#endif -/** - * Convert int into a string - */ -char *itoa(char *p, int x, int base); -/** - * Convert unsigned int into a string - */ -char *utoa(char *p, unsigned x, int base); -#ifdef __cplusplus -} -#endif - -///@} -///@} diff --git a/lib/libk/string/itoa.c b/lib/libk/string/itoa.c index 2db9768..0997345 100644 --- a/lib/libk/string/itoa.c +++ b/lib/libk/string/itoa.c @@ -4,7 +4,7 @@ static const char *numbers = "0123456789abcdef"; char * -utoa(char *p, unsigned x, int base) +utoa(char *p, unsigned x, unsigned base) { p += 3 * sizeof(unsigned); *--p = '\0'; @@ -18,12 +18,12 @@ utoa(char *p, unsigned x, int base) } char * -itoa(char *p, int x, int base) +itoa(char *p, int x, unsigned base) { const bool is_negative = (x < 0); if (is_negative) x = -x; - p = utoa(p, x, base); + p = utoa(p, (unsigned)x, base); if (is_negative) *--p = '-'; return p; diff --git a/lib/tst/string.cc b/lib/libk/string/test_string.cc index f22c123..d12b318 100644 --- a/lib/tst/string.cc +++ b/lib/libk/string/test_string.cc @@ -1,7 +1,7 @@ #include <gtest/gtest.h> namespace libk { -#include "../libk/string/itoa.c" +#include "itoa.c" } char buffer[64]; diff --git a/platforms/BUILD.bazel b/platforms/BUILD.bazel new file mode 100644 index 0000000..1f13594 --- /dev/null +++ b/platforms/BUILD.bazel @@ -0,0 +1,7 @@ +platform( + name = "i386", + constraint_values = [ + "@platforms//cpu:i386", + "@platforms//os:none", + ], +) diff --git a/project_config.bzl b/project_config.bzl new file mode 100644 index 0000000..a4c58fb --- /dev/null +++ b/project_config.bzl @@ -0,0 +1,2 @@ +def version(): + return "0.1.0" diff --git a/rules.mk b/rules.mk deleted file mode 100644 index 833664d..0000000 --- a/rules.mk +++ /dev/null @@ -1,142 +0,0 @@ -# generate objects from sources -# arg 1: target.SRCS -# arg 2: object suffix prefix -# returns: target.OBJS -objects = $(foreach f,$($1),$(addsuffix $2.o,$(basename $f))) - -# generate depends from .S .c .cpp sources -# arg 1: target.SRCS -# arg 2: dependency suffix prefix -# returns: target.DEPS -depends = $(foreach f,$(filter %.S %.c %.cpp,$($1)),$(addsuffix $2.d,$(basename $f))) - -# default target -all: targets - - -# TARGETBIN: binaries using the target architecture -$(foreach T,${TARGETBIN},\ - $(eval $T.OBJS += $(call objects,$T.SRCS,_${ARCH}) ) \ - $(eval $T.DEPS += $(call depends,$T.SRCS,_${ARCH}) ) \ - $(eval include $($T.DEPS) ) \ - $(eval $T.elf: ${$T.OBJS} ) \ - $(eval DEFAULT_TARGETS += $T.elf) \ -) - -# TARGETLIB: static libraries using the target architecture -$(foreach T,${TARGETLIB},\ - $(eval $T.OBJS += $(call objects,$T.SRCS,_${ARCH}) ) \ - $(eval $T.DEPS += $(call depends,$T.SRCS,_${ARCH}) ) \ - $(eval include $($T.DEPS) ) \ - $(eval $T.a: ${$T.OBJS} ) \ - $(eval DEFAULT_TARGETS += $T.a) \ -) - -# HOSTTARGETBIN: binaries using the host compiler -$(foreach T,${HOSTTARGETBIN},\ - $(eval $T.OBJS += $(call objects,$T.SRCS,) ) \ - $(eval $T.DEPS += $(call depends,$T.SRCS,) ) \ - $(eval include $($T.DEPS) ) \ - $(eval $T: ${$T.OBJS}; @echo ' LD HOST $T'; ${HOST_CC} ${HOST_LDFLAGS} -o $T ${$T.OBJS} ) \ - $(eval DEFAULT_TARGETS += $T) \ -) - -TESTS.DEPS = $(foreach F,${TESTS},$(addsuffix .d,$F)) -include ${TESTS.DEPS} - -debug: - @echo "TARGETBIN ${TARGETBIN}" - @echo "TARGETLIB ${TARGETLIB}" - @echo "HOSTTARGETBIN ${HOSTTARGETBIN}" - @echo "HOSTTARGETLIB ${HOSTTARGETLIB}" - @echo "DEFAULT_TARGETS ${DEFAULT_TARGETS}" - @echo "TESTS ${TESTS}" - @echo " DEPS ${TESTS.DEPS}" - -%.info: - @echo "Target: $(basename $@)" - @echo " SRCS: ${$(basename $@).SRCS}" - @echo " OBJS: ${$(basename $@).OBJS}" - @echo " DEPS: ${$(basename $@).DEPS}" - -targets: ${DEFAULT_TARGETS} - @echo " -> Built ${DEFAULT_TARGETS}" - -# extra flags -${ARCH}_CFLAGS += -I../lib/libk \ - -Werror=implicit-function-declaration -${ARCH}_CXXFLAGS += -I../lib/libk -Drestrict=__restrict__ - -# Target depndency rules -%_${ARCH}.d: %.S - @${${ARCH}_CC} ${${ARCH}_CFLAGS} -M -MT $(<:.S=_${ARCH}.o) $< -MF $@ - -%_${ARCH}.d: %.c - @${${ARCH}_CC} ${${ARCH}_CFLAGS} -M -MT $(<:.c=_${ARCH}.o) $< -MF $@ - -%_${ARCH}.d: %.cpp - @${${ARCH}_CXX} ${${ARCH}_CXXFLAGS} -M -MT $(<:.cpp=_${ARCH}.o) $< -MF $@ - -# Host dependency rules -%.d: %.c - @${HOST_CC} ${HOST_CFLAGS} -M -MT $(<:.c=.o) $< -MF $@ - -%.d: %.cc - @${HOST_CXX} ${HOST_CXXFLAGS} -M -MT $(<:.cc=) $< -MF $@ - -# Target suffix rules -%.a: - @echo ' AR $@' - @${${ARCH}_AR} ${${ARCH}_ARFLAGS} $@ $(filter %.o,$^) - -%_${ARCH}.o: %.s - @echo ' AS $<' - @${${ARCH}_AS} ${${ARCH}_ASFLAGS} -c -o $@ $< - -%_${ARCH}.o: %.S - @echo ' CC $<' - @${${ARCH}_CC} ${${ARCH}_CFLAGS} -c -o $@ $< - -%_${ARCH}.o: %.c - @echo ' CC $<' - @${${ARCH}_CC} ${${ARCH}_CFLAGS} -c -o $@ $< - -%_${ARCH}.o: %.cpp - @echo ' CXX $<' - @${${ARCH}_CXX} ${${ARCH}_CXXFLAGS} -c -o $@ $< - -%.elf: - @echo ' LD $@' - @${${ARCH}_LD} ${${ARCH}_LDFLAGS} -o $@ $^ - @echo -n ' B2b ' - @b2sum $@ | cut -d' ' -f1 - -# Host suffix rules -%.o: %.c - @echo ' CC HOST $<' - @${HOST_CC} ${HOST_CFLAGS} -c -o $@ $< - -# test rules -tst/%: tst/%.cc - @echo ' CXX TEST $@' - @${HOST_CXX} ${HOST_CXXFLAGS} $< -o $@ - -.PHONY: test.base valgrind.base clean.base FORCE -test.base: ${TESTS} - @echo " -> Running tests in $(shell pwd | xargs basename)" - @$(foreach f,$^,echo " -> $f"; ./$f &&) echo "Done" - -valgrind.base: ${TESTS} - @echo " -> Running valgrind on tests in $(shell pwd | xargs basename)" - @$(foreach f,$^,echo " -> $f"; valgrind --leak-check=full ./$f;) - -clean.base: FORCE - @echo " -> Cleaning $(shell pwd | xargs basename)" - @$(foreach V,$(filter %.OBJS, ${.VARIABLES}), rm -rf $($(V))) - @$(foreach V,$(filter %.DEPS, ${.VARIABLES}), rm -rf $($(V))) - @rm -rf *.a - @rm -rf ${TESTS} - -%: %.base ; - -FORCE: ; diff --git a/scripts/test_runner.py b/scripts/test_runner.py new file mode 100755 index 0000000..53bebd3 --- /dev/null +++ b/scripts/test_runner.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +""" Test runner """ + +import argparse +import os +import subprocess + +def main(): + """ Main function""" + + parser = argparse.ArgumentParser(description='Run test executables') + parser.add_argument('-v', '--verbose', action='store_true', help='Show test stdout/stderr') + parser.add_argument('--valgrind', action='store_true', help='Run tests under valgrind') + parser.add_argument('test', type=str, nargs='+', help='test executable to run') + args = parser.parse_args() + + cwd = os.getcwd() + fail_count = 0 + + for test in args.test: + cmd = [] + if args.valgrind: + cmd += [ 'valgrind', '--leak-check=full', '--error-exitcode=128' ] + cmd.append(os.path.join(cwd, test)) + #print(cmd) + + if not args.verbose: + print(f' {test:.<48}', end='') + result = subprocess.run(cmd, capture_output=not args.verbose, check=False) + if not args.verbose: + print('ok' if result.returncode == 0 else 'failed') + if result.returncode != 0: + fail_count += 1 + + print(f' Ran {len(args.test)} tests, {fail_count} failed') + + +if __name__ == '__main__': + main() diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index f9ab6fe..0000000 --- a/src/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -include ../Makefile.config - -INCLUDES := -isystem../grub -I../${ARCH} -I../devices -${ARCH}_CFLAGS += ${INCLUDES} -${ARCH}_CXXFLAGS += ${INCLUDES} - -TARGETLIB += kernel -kernel.SRCS := multiboot2.c mmap.c kernel.cpp mem/vmm.c -kernel.OBJS := conf.h - -TESTS += tst/taskqueue tst/roundrobin - -include ../rules.mk - -conf.h: conf.h.in - @echo ' GEN $@' - @cp conf.h.in conf.h - @sed -i 's/@VERSION@/$(shell git describe)/' conf.h - @sed -i 's/@CC@/${${ARCH}_CCID}/' conf.h - diff --git a/src/boot.h b/src/boot.h deleted file mode 100644 index 8d62bdc..0000000 --- a/src/boot.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - // kernel command line - char cmdline[64]; - - // memory map - unsigned bitmap[1024 * 32]; - - // module - unsigned module_start; - unsigned module_end; - char module_cmdline[64]; -} boot_info_t; - -_Static_assert((1024 * 32 * sizeof(unsigned) * 8) == (1024 * 1024), "bitmap size check"); - -#ifdef __cplusplus -} -#endif diff --git a/src/conf.h.in b/src/conf.h.in deleted file mode 100644 index 52093a8..0000000 --- a/src/conf.h.in +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#define VERSION "@VERSION@" -#define CC "@CC@" diff --git a/toolchains/BUILD.bazel b/toolchains/BUILD.bazel new file mode 100644 index 0000000..d46f812 --- /dev/null +++ b/toolchains/BUILD.bazel @@ -0,0 +1,34 @@ +load(":i386_elf_gcc.bzl", "cc_toolchain_config") + +package(default_visibility = ["//visibility:public"]) + +filegroup(name = "empty") + +cc_toolchain_config(name = "i386_elf_gcc_toolchain_config") + +cc_toolchain( + name = "i386_elf_gcc_toolchain", + all_files = ":empty", + compiler_files = ":empty", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 0, + toolchain_config = ":i386_elf_gcc_toolchain_config", + toolchain_identifier = "none_i386-toolchain", +) + +toolchain( + name = "i386_elf_gcc", + exec_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:linux", + ], + target_compatible_with = [ + "@platforms//cpu:i386", + "@platforms//os:none", + ], + toolchain = ":i386_elf_gcc_toolchain", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) diff --git a/toolchains/i386_elf_gcc.bzl b/toolchains/i386_elf_gcc.bzl new file mode 100644 index 0000000..ad933d2 --- /dev/null +++ b/toolchains/i386_elf_gcc.bzl @@ -0,0 +1,123 @@ +load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") +load( + "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + "feature", + "flag_group", + "flag_set", + "tool_path", +) + +all_link_actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, +] + +all_compile_actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.clif_match, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.lto_backend, + ACTION_NAMES.preprocess_assemble, +] + +def _impl(ctx): + tool_paths = [ + tool_path( + name = "gcc", + path = "/usr/bin/i686-elf-gcc", + ), + tool_path( + name = "ld", + path = "/usr/bin/i686-elf-ld", + ), + tool_path( + name = "ar", + path = "/usr/bin/i686-elf-ar", + ), + tool_path( + name = "cpp", + path = "/usr/bin/i686-elf-cpp", + ), + tool_path( + name = "gcov", + path = "/bin/false", + ), + tool_path( + name = "nm", + path = "/usr/bin/i686-elf-nm", + ), + tool_path( + name = "objdump", + path = "/usr/bin/i686-elf-objdump", + ), + tool_path( + name = "strip", + path = "/usr/bin/i686-elf-strip", + ), + ] + + features = [ + feature( + name = "default_compiler_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = all_compile_actions, + flag_groups = [ + flag_group( + flags = [ + "-fanalyzer", + "-ffreestanding", + "-mgeneral-regs-only", + ], + ), + ], + ), + ], + ), + feature( + name = "default_linker_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = ([ + flag_group( + flags = [ + "-nostdlib", + ], + ), + ]), + ), + ], + ), + ] + + return cc_common.create_cc_toolchain_config_info( + ctx = ctx, + features = features, + cxx_builtin_include_directories = [ + "/usr/lib/gcc/i686-elf", + ], + toolchain_identifier = "local", + host_system_name = "local", + target_system_name = "local", + target_cpu = "i686", + target_libc = "unknown", + compiler = "gcc", + abi_version = "unknown", + abi_libc_version = "unknown", + tool_paths = tool_paths, + ) + +cc_toolchain_config = rule( + implementation = _impl, + attrs = {}, + provides = [CcToolchainConfigInfo], +) diff --git a/toolchains/i386_qemu.bzl b/toolchains/i386_qemu.bzl new file mode 100644 index 0000000..c9f8535 --- /dev/null +++ b/toolchains/i386_qemu.bzl @@ -0,0 +1,8 @@ +_wrapper_template = """\ +#!/bin/bash +qemu-system-i386 -accel kvm -machine pc -d cpu_reset -display gtk,zoom-to-fit=on -cdrom {cdrom} +""" + +def qemu_wrapper(): + return _wrapper_template + diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel new file mode 100644 index 0000000..fddb974 --- /dev/null +++ b/tools/BUILD.bazel @@ -0,0 +1,6 @@ +package(default_visibility = ["//visibility:public"]) + +py_binary( + name = "make_iso", + srcs = ["make_iso.py"], +) diff --git a/tools/configure_file.bzl b/tools/configure_file.bzl new file mode 100644 index 0000000..8fdd75c --- /dev/null +++ b/tools/configure_file.bzl @@ -0,0 +1,29 @@ +load("//:project_config.bzl", "version") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") + +def configure_file(**kwargs): + _configure_file( + source_file = "{name}.h".format(**kwargs), + **kwargs + ) + +def _configure_file_impl(ctx): + cc_toolchain = find_cc_toolchain(ctx) + + ctx.actions.expand_template( + template = ctx.file.template, + output = ctx.outputs.source_file, + substitutions = { + "{VERSION}": '"{}"'.format(version()), + "{CC}": '"{} " __VERSION__'.format(cc_toolchain.compiler), + }, + ) + +_configure_file = rule( + attrs = { + "template": attr.label(allow_single_file = True), + "source_file": attr.output(mandatory = True), + }, + toolchains = use_cc_toolchain(), + implementation = _configure_file_impl, +) diff --git a/tools/interface_generator/.bazelrc b/tools/interface_generator/.bazelrc new file mode 100644 index 0000000..71d2e60 --- /dev/null +++ b/tools/interface_generator/.bazelrc @@ -0,0 +1,2 @@ +build --cxxopt=-std=c++20 + diff --git a/tools/interface_generator/BUILD.bazel b/tools/interface_generator/BUILD.bazel new file mode 100644 index 0000000..8c4bde6 --- /dev/null +++ b/tools/interface_generator/BUILD.bazel @@ -0,0 +1,13 @@ +load("@rules_python//python:pip.bzl", "compile_pip_requirements") + +package(default_visibility = ["//visibility:public"]) + +# This rule adds a convenient way to update the requirements file. +compile_pip_requirements( + name = "requirements", + src = "requirements.txt", + requirements_txt = "requirements_lock.txt", +) + +# make license available to test package +exports_files(["LICENSE.md"]) diff --git a/tools/interface_generator/LICENSE.md b/tools/interface_generator/LICENSE.md new file mode 100644 index 0000000..ddb4966 --- /dev/null +++ b/tools/interface_generator/LICENSE.md @@ -0,0 +1,16 @@ +Copyright (c) 2024 aqua@iserlohn-fortress.net + +Permission to use, copy, modify, and 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. + +SPDX License Identifier: [ISC](https://spdx.org/licenses/ISC.html) diff --git a/tools/interface_generator/MODULE.bazel b/tools/interface_generator/MODULE.bazel new file mode 100644 index 0000000..53b2ba4 --- /dev/null +++ b/tools/interface_generator/MODULE.bazel @@ -0,0 +1,20 @@ +############################################################################### +# Bazel now uses Bzlmod by default to manage external dependencies. +# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel. +# +# For more details, please check https://github.com/bazelbuild/bazel/issues/18958 +############################################################################### + +module(name = "interface_generator", version = "0.1.0") + +# external dependencies +bazel_dep(name = "googletest", version = "1.15.2") +bazel_dep(name = "rules_python", version = "0.34.0") + +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") +pip.parse( + hub_name = "pip", + python_version = "3.11", + requirements_lock = "//:requirements_lock.txt", +) +use_repo(pip, "pip") diff --git a/tools/interface_generator/bin/BUILD.bazel b/tools/interface_generator/bin/BUILD.bazel new file mode 100644 index 0000000..04843b9 --- /dev/null +++ b/tools/interface_generator/bin/BUILD.bazel @@ -0,0 +1,45 @@ +load("@pip//:requirements.bzl", "requirement") +load("//private:defs.bzl", "py_pytest") + +""" interface declaration """ + +py_library( + name = "interface_declaration", + srcs = ["interface_declaration.py"], +) + +""" templates """ + +py_library( + name = "templates", + srcs = ["templates.py"], + data = glob(["templates/*"]), +) + +""" interface_generator """ + +py_binary( + name = "interface_generator", + srcs = [ + "interface_generator.py", + "templates.py", + ], + imports = ["."], + visibility = ["//visibility:public"], + deps = [ + ":interface_declaration", + ":templates", + requirement("mako"), + ], +) + +""" pytest """ + +py_pytest( + name = "pytest", + srcs = glob(["*.py"]), + data = glob(["templates/*"]), + deps = [ + requirement("mako"), + ], +) diff --git a/tools/interface_generator/bin/interface_declaration.py b/tools/interface_generator/bin/interface_declaration.py new file mode 100644 index 0000000..4560bbd --- /dev/null +++ b/tools/interface_generator/bin/interface_declaration.py @@ -0,0 +1,58 @@ +""" +interface_declaration.py +""" + +from dataclasses import dataclass, asdict +from pathlib import Path + + +@dataclass +class InterfaceDeclaration: + """interface declaration class""" + + name: str + license_hdr: str + system_includes: list[str] + types: list[dict] + functions: list[dict] + + def read_license(self, path: Path): + """read and starrify a license""" + if path is None: + self.license_hdr = "" + return + + with open(path, encoding="utf-8") as license_file: + self.license_hdr = "".join( + [ + f" * { line.rstrip().ljust(72)[:72] } * \n" + for line in license_file.readlines() + ] + ).rstrip() + + def __init__(self, name: str, license_path: Path): + self.name = name if name is not None else "kstdio" + self.read_license(license_path) + self.system_includes = ["stdarg.h"] + self.types = [ + { + "name": "File", + "members": [ + "int fd", + "int (*putc)(const struct kstdio_File*, const char)", + "int (*puts)(const struct kstdio_File*, const char*)", + ], + }, + ] + self.functions = [ + { + "name": "printf", + "return": "int", + "arguments": ["const char* format"], + "argument_names": ["format"], + }, + ] + + def into_dict(self) -> dict: + """create a dictionary for use in mako""" + return asdict(self) diff --git a/tools/interface_generator/bin/interface_declaration_unittest.py b/tools/interface_generator/bin/interface_declaration_unittest.py new file mode 100644 index 0000000..b2ad80c --- /dev/null +++ b/tools/interface_generator/bin/interface_declaration_unittest.py @@ -0,0 +1,19 @@ +""" +interface declaration unit tests +""" + +import unittest +from interface_declaration import InterfaceDeclaration + + +class InterfaceDeclarationUnittest(unittest.TestCase): + """interface_declaration unit tests""" + + def test_interfacedeclaration_class_asdict(self): + """test mock interface""" + interface = InterfaceDeclaration("kstdio", None) + interface_dict = interface.into_dict() + + self.assertEqual(interface.name, "kstdio") + self.assertEqual(len(interface.license_hdr), 0) + self.assertEqual(interface_dict["name"], "kstdio") diff --git a/tools/interface_generator/bin/interface_generator.py b/tools/interface_generator/bin/interface_generator.py new file mode 100755 index 0000000..eab93d7 --- /dev/null +++ b/tools/interface_generator/bin/interface_generator.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +""" +interface_generator.py +""" + +from argparse import ArgumentParser +from pathlib import Path +import sys +from mako.lookup import TemplateLookup +from interface_declaration import InterfaceDeclaration +from templates import get_templates, get_templates_dir + +PROG = { + "name": "interface_generator", + "version": "0.1", +} + + +def generate_file( + template: Path, templates: Path, output, interface: InterfaceDeclaration +): + """generate file using a tempalte and write it to the output location""" + lookup = TemplateLookup(directories=[".", templates.absolute()]) + mako_template = lookup.get_template(str(template.relative_to(templates))) + output_name = template.stem.replace("interface", interface.name) + print(f"{interface.name} via {template.name} => {output_name}") + + result = mako_template.render(**interface.into_dict(), PROG=PROG) + + if isinstance(output, Path): + # print(f"writing to {(output / output_name).absolute()}") + with open(output / output_name, "w", encoding="utf-8") as output_file: + print(result, file=output_file) + else: + print(result, file=output) + + +def main(): + """main function""" + parser = ArgumentParser( + prog="interface_generator", + description="Generate C header and mock files from an interface declaration", + ) + parser.add_argument( + "-i", + "--interface", + type=Path, + # required=True, + help="path to interface file", + ) + parser.add_argument( + "-t", + "--templates", + type=Path, + default=get_templates_dir(), + help="templates location", + ) + parser.add_argument( + "-l", + "--license", + type=Path, + required=True, + help="path to license file", + ) + parser.add_argument( + "-o", + "--output", + type=Path, + default=sys.stdout, + help="path to output, stdout by default", + ) + + args = parser.parse_args() + # print(args) + + interface = InterfaceDeclaration(args.interface, args.license) + # print(interface) + + for template in get_templates(args.templates): + # print(template) + generate_file(template, args.templates, args.output, interface) + + +if __name__ == "__main__": + main() diff --git a/tools/interface_generator/bin/templates.py b/tools/interface_generator/bin/templates.py new file mode 100644 index 0000000..9f7539e --- /dev/null +++ b/tools/interface_generator/bin/templates.py @@ -0,0 +1,19 @@ +"""template helper functions""" + +from pathlib import Path +import re + + +TEMPLATE_PATTERN = re.compile(r"^[^_]\S+\.mako$") + + +def get_templates_dir(name="templates") -> Path: + """get the templates directory""" + return Path(__file__).parent / name + + +def get_templates(path: Path) -> list[Path]: + """list templates in given path""" + result = list(path.glob("*.mako")) + result = [item for item in result if TEMPLATE_PATTERN.match(item.name)] + return result diff --git a/tools/interface_generator/bin/templates/__c_functions.mako b/tools/interface_generator/bin/templates/__c_functions.mako new file mode 100644 index 0000000..2e40119 --- /dev/null +++ b/tools/interface_generator/bin/templates/__c_functions.mako @@ -0,0 +1,4 @@ +/* Functions */ +% for fn in functions: +${fn['return']} ${name}_${fn['name']}(${ ", ".join(fn['arguments']) }); +% endfor diff --git a/tools/interface_generator/bin/templates/__c_system_include.mako b/tools/interface_generator/bin/templates/__c_system_include.mako new file mode 100644 index 0000000..d6a9d09 --- /dev/null +++ b/tools/interface_generator/bin/templates/__c_system_include.mako @@ -0,0 +1,4 @@ +/* System includes */ +% for path in system_includes: +#include <${path}> +% endfor diff --git a/tools/interface_generator/bin/templates/__c_types.mako b/tools/interface_generator/bin/templates/__c_types.mako new file mode 100644 index 0000000..ce6b6b5 --- /dev/null +++ b/tools/interface_generator/bin/templates/__c_types.mako @@ -0,0 +1,6 @@ +/* Types */ +% for type in types: +typedef struct ${name}_${type['name']} { +${ "\n".join([ " {};".format(member) for member in type['members'] ]) } +} ${name}_${type['name']}; +% endfor diff --git a/tools/interface_generator/bin/templates/__header.mako b/tools/interface_generator/bin/templates/__header.mako new file mode 100644 index 0000000..43ce1e7 --- /dev/null +++ b/tools/interface_generator/bin/templates/__header.mako @@ -0,0 +1,5 @@ +/* This file is generated by ${PROG['name']} v${PROG['version']} */ + +/****************************************************************************** +${ license_hdr } + ******************************************************************************/ diff --git a/tools/interface_generator/bin/templates/interface.h.mako b/tools/interface_generator/bin/templates/interface.h.mako new file mode 100644 index 0000000..47ea940 --- /dev/null +++ b/tools/interface_generator/bin/templates/interface.h.mako @@ -0,0 +1,8 @@ +<%include file="__header.mako" /> +#ifndef ${ name.upper() } +#define ${ name.upper() } + +<%include file="__c_system_include.mako" /> +<%include file="__c_types.mako" /> +<%include file="__c_functions.mako" /> +#endif /* ${ name.upper() } */ diff --git a/tools/interface_generator/bin/templates/interface_mock.cpp.mako b/tools/interface_generator/bin/templates/interface_mock.cpp.mako new file mode 100644 index 0000000..721f2c4 --- /dev/null +++ b/tools/interface_generator/bin/templates/interface_mock.cpp.mako @@ -0,0 +1,32 @@ +<%include file="__header.mako" /> + +#include <stdexcept> +#include "${name}_mock.hpp" + +static I${name}_mock *s_instance = nullptr; + +I${name}_mock::I${name}_mock() +{ + if(s_instance != nullptr) + { + throw std::runtime_error("Creating a second instance of mock object"); + } + s_instance = this; +} + +I${name}_mock::~I${name}_mock() +{ + // destructors shouldn't throw exceptions + s_instance = nullptr; +} + +% for fn in functions: +${fn['return']} ${name}_${fn['name']}(${ ", ".join(fn['arguments']) }) +{ + if(s_instance == nullptr) + { + throw std::runtime_error("No mock created to handle function ${name}_${fn['name']}"); + } + return s_instance->${fn['name']}(${ ", ".join(fn['argument_names']) }); +} +% endfor diff --git a/tools/interface_generator/bin/templates/interface_mock.hpp.mako b/tools/interface_generator/bin/templates/interface_mock.hpp.mako new file mode 100644 index 0000000..e33d50e --- /dev/null +++ b/tools/interface_generator/bin/templates/interface_mock.hpp.mako @@ -0,0 +1,26 @@ +<%include file="__header.mako" /> +#ifndef ${ name.upper() }_MOCK +#define ${ name.upper() }_MOCK + +extern "C" { +#include "${ name }.h" +} + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +class I${name}_mock +{ +public: + I${name}_mock(); + ~I${name}_mock(); + + /* Functions */ +% for fn in functions: + MOCK_METHOD(${fn['return']}, ${fn['name']}, (${ ", ".join(fn['arguments']) })); +% endfor +}; + +using ${name}_mock = ::testing::NiceMock<I${name}_mock>; + +#endif /* ${ name.upper() }_MOCK */ diff --git a/tools/interface_generator/bin/templates_unittest.py b/tools/interface_generator/bin/templates_unittest.py new file mode 100644 index 0000000..acb1685 --- /dev/null +++ b/tools/interface_generator/bin/templates_unittest.py @@ -0,0 +1,30 @@ +""" +templates unit tests +""" + +import unittest +from pathlib import Path +import templates + + +class TemplatesUnittest(unittest.TestCase): + """templates unit tests""" + + def test_get_templates_dir_is_valid(self): + """verify that default templates dir is valid""" + path = templates.get_templates_dir() + + self.assertTrue(isinstance(path, Path)) + self.assertTrue(path.exists()) + self.assertTrue(path.is_dir()) + + def test_get_templates(self): + """verify that templates are available by default""" + path = templates.get_templates_dir() + result = templates.get_templates(path) + + self.assertGreater(len(result), 0) + for template in result: + self.assertTrue(isinstance(template, Path)) + self.assertTrue(template.exists()) + self.assertTrue(template.is_file()) diff --git a/tools/interface_generator/defs.bzl b/tools/interface_generator/defs.bzl new file mode 100644 index 0000000..238588f --- /dev/null +++ b/tools/interface_generator/defs.bzl @@ -0,0 +1,53 @@ +def _generate_interface_impl(ctx): + out_hdrs = [ + ctx.actions.declare_file(ctx.attr.interface + ".h"), + ctx.actions.declare_file(ctx.attr.interface + "_mock.hpp"), + ] + out_srcs = [ + ctx.actions.declare_file(ctx.attr.interface + "_mock.cpp"), + ] + args = ["-l", ctx.file.license.path, "-o", out_hdrs[0].dirname] + + ctx.actions.run( + tools = ctx.attr._interface_generator_tool[DefaultInfo].data_runfiles.files, + inputs = [ctx.file.license], + outputs = out_srcs + out_hdrs, + executable = ctx.executable._interface_generator_tool, + arguments = args, + mnemonic = "GenerateInterface", + ) + + compilation_ctx = cc_common.create_compilation_context( + headers = depset(out_hdrs), + includes = depset([out_hdrs[0].dirname]), + ) + + return [ + DefaultInfo(files = depset(out_srcs)), + CcInfo(compilation_context = compilation_ctx), + ] + +generate_interface_rule = rule( + implementation = _generate_interface_impl, + attrs = { + "interface": attr.string(), + "license": attr.label(allow_single_file = True), + "_interface_generator_tool": attr.label( + executable = True, + cfg = "exec", + allow_files = True, + providers = [DefaultInfo], + default = Label("//bin:interface_generator"), + ), + "outs": attr.output_list(), + }, +) + +def generate_interface(name, interface, license, visibility = None): + generate_interface_rule( + name = name, + interface = interface, + outs = [name + "_mock.cpp"], + license = license, + visibility = visibility, + ) diff --git a/tools/interface_generator/private/BUILD.bazel b/tools/interface_generator/private/BUILD.bazel new file mode 100644 index 0000000..3012bcb --- /dev/null +++ b/tools/interface_generator/private/BUILD.bazel @@ -0,0 +1,9 @@ +""" targets internal to the tool and rule """ + +package(default_visibility = ["//:__pkg__"]) + +exports_files([ + "mypyrc", + "pylintrc", + "pytest_wrapper.py", +]) diff --git a/tools/interface_generator/private/defs.bzl b/tools/interface_generator/private/defs.bzl new file mode 100644 index 0000000..8e2ae8d --- /dev/null +++ b/tools/interface_generator/private/defs.bzl @@ -0,0 +1,29 @@ +load("@pip//:requirements.bzl", "requirement") + +def py_pytest(name, srcs, deps = [], data = [], **kwargs): + native.py_test( + name = name, + srcs = ["//private:pytest_wrapper.py"], + main = "//private:pytest_wrapper.py", + legacy_create_init = False, + imports = ["."], + args = [ + "--capture=no", + "--black", + "--pylint", + "--pylint-rcfile=$(location //private:pylintrc)", + "--mypy", + "--mypy-config-file=$(location //private:mypyrc)", + ] + ["$(location :%s)" % x for x in srcs], + deps = [ + requirement("pytest"), + requirement("pytest-black"), + requirement("pytest-pylint"), + requirement("pytest-mypy"), + ] + deps, + data = [ + "//private:mypyrc", + "//private:pylintrc", + ] + srcs + data, + **kwargs + ) diff --git a/tools/interface_generator/private/mypyrc b/tools/interface_generator/private/mypyrc new file mode 100644 index 0000000..d787271 --- /dev/null +++ b/tools/interface_generator/private/mypyrc @@ -0,0 +1,2 @@ +[mypy] +disable_error_code = import-untyped diff --git a/tools/interface_generator/private/pylintrc b/tools/interface_generator/private/pylintrc new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/interface_generator/private/pylintrc diff --git a/tools/interface_generator/private/pytest_wrapper.py b/tools/interface_generator/private/pytest_wrapper.py new file mode 100755 index 0000000..b4def3b --- /dev/null +++ b/tools/interface_generator/private/pytest_wrapper.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +import sys +import pytest + +if __name__ == "__main__": + sys.exit(pytest.main(sys.argv[1:])) diff --git a/tools/interface_generator/requirements.txt b/tools/interface_generator/requirements.txt new file mode 100644 index 0000000..c285e04 --- /dev/null +++ b/tools/interface_generator/requirements.txt @@ -0,0 +1,6 @@ +Mako==1.3.3 +MarkupSafe==2.1.5 +pytest==8.3.2 +pytest-black==0.3.12 +pytest-pylint==0.21.0 +pytest-mypy==0.10.3 diff --git a/tools/interface_generator/requirements_lock.txt b/tools/interface_generator/requirements_lock.txt new file mode 100644 index 0000000..62c9eb4 --- /dev/null +++ b/tools/interface_generator/requirements_lock.txt @@ -0,0 +1,220 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# bazel run //:requirements.update +# +astroid==3.2.4 \ + --hash=sha256:0e14202810b30da1b735827f78f5157be2bbd4a7a59b7707ca0bfc2fb4c0063a \ + --hash=sha256:413658a61eeca6202a59231abb473f932038fbcbf1666587f66d482083413a25 + # via pylint +attrs==24.2.0 \ + --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ + --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 + # via pytest-mypy +black==24.8.0 \ + --hash=sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6 \ + --hash=sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e \ + --hash=sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f \ + --hash=sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018 \ + --hash=sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e \ + --hash=sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd \ + --hash=sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4 \ + --hash=sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed \ + --hash=sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2 \ + --hash=sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42 \ + --hash=sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af \ + --hash=sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb \ + --hash=sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368 \ + --hash=sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb \ + --hash=sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af \ + --hash=sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed \ + --hash=sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47 \ + --hash=sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2 \ + --hash=sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a \ + --hash=sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c \ + --hash=sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920 \ + --hash=sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1 + # via pytest-black +click==8.1.7 \ + --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ + --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de + # via black +dill==0.3.8 \ + --hash=sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca \ + --hash=sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7 + # via pylint +filelock==3.15.4 \ + --hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \ + --hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7 + # via pytest-mypy +iniconfig==2.0.0 \ + --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ + --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 + # via pytest +isort==5.13.2 \ + --hash=sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109 \ + --hash=sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6 + # via pylint +mako==1.3.3 \ + --hash=sha256:5324b88089a8978bf76d1629774fcc2f1c07b82acdf00f4c5dd8ceadfffc4b40 \ + --hash=sha256:e16c01d9ab9c11f7290eef1cfefc093fb5a45ee4a3da09e2fec2e4d1bae54e73 + # via -r requirements.txt +markupsafe==2.1.5 \ + --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \ + --hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \ + --hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \ + --hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \ + --hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \ + --hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \ + --hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \ + --hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \ + --hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \ + --hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \ + --hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \ + --hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \ + --hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \ + --hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \ + --hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \ + --hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \ + --hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \ + --hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \ + --hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \ + --hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \ + --hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \ + --hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \ + --hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \ + --hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \ + --hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \ + --hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \ + --hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \ + --hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \ + --hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \ + --hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \ + --hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \ + --hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \ + --hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \ + --hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \ + --hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \ + --hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \ + --hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \ + --hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \ + --hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \ + --hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \ + --hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \ + --hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \ + --hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \ + --hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \ + --hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \ + --hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \ + --hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \ + --hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \ + --hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \ + --hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \ + --hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \ + --hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \ + --hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \ + --hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \ + --hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \ + --hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \ + --hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \ + --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ + --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ + --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 + # via + # -r requirements.txt + # mako +mccabe==0.7.0 \ + --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \ + --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e + # via pylint +mypy==1.11.1 \ + --hash=sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54 \ + --hash=sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a \ + --hash=sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72 \ + --hash=sha256:11965c2f571ded6239977b14deebd3f4c3abd9a92398712d6da3a772974fad69 \ + --hash=sha256:1a81cf05975fd61aec5ae16501a091cfb9f605dc3e3c878c0da32f250b74760b \ + --hash=sha256:2684d3f693073ab89d76da8e3921883019ea8a3ec20fa5d8ecca6a2db4c54bbe \ + --hash=sha256:2c63350af88f43a66d3dfeeeb8d77af34a4f07d760b9eb3a8697f0386c7590b4 \ + --hash=sha256:45df906e8b6804ef4b666af29a87ad9f5921aad091c79cc38e12198e220beabd \ + --hash=sha256:4c956b49c5d865394d62941b109728c5c596a415e9c5b2be663dd26a1ff07bc0 \ + --hash=sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525 \ + --hash=sha256:749fd3213916f1751fff995fccf20c6195cae941dc968f3aaadf9bb4e430e5a2 \ + --hash=sha256:79c07eb282cb457473add5052b63925e5cc97dfab9812ee65a7c7ab5e3cb551c \ + --hash=sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5 \ + --hash=sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de \ + --hash=sha256:a2b43895a0f8154df6519706d9bca8280cda52d3d9d1514b2d9c3e26792a0b74 \ + --hash=sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c \ + --hash=sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e \ + --hash=sha256:a831671bad47186603872a3abc19634f3011d7f83b083762c942442d51c58d58 \ + --hash=sha256:b639dce63a0b19085213ec5fdd8cffd1d81988f47a2dec7100e93564f3e8fb3b \ + --hash=sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417 \ + --hash=sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411 \ + --hash=sha256:d44be7551689d9d47b7abc27c71257adfdb53f03880841a5db15ddb22dc63edb \ + --hash=sha256:e1e30dc3bfa4e157e53c1d17a0dad20f89dc433393e7702b813c10e200843b03 \ + --hash=sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca \ + --hash=sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8 \ + --hash=sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08 \ + --hash=sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809 + # via pytest-mypy +mypy-extensions==1.0.0 \ + --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ + --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 + # via + # black + # mypy +packaging==24.1 \ + --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ + --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 + # via + # black + # pytest +pathspec==0.12.1 \ + --hash=sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08 \ + --hash=sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712 + # via black +platformdirs==4.2.2 \ + --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ + --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 + # via + # black + # pylint +pluggy==1.5.0 \ + --hash=sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1 \ + --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669 + # via pytest +pylint==3.2.6 \ + --hash=sha256:03c8e3baa1d9fb995b12c1dbe00aa6c4bcef210c2a2634374aedeb22fb4a8f8f \ + --hash=sha256:a5d01678349454806cff6d886fb072294f56a58c4761278c97fb557d708e1eb3 + # via pytest-pylint +pytest==8.3.2 \ + --hash=sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5 \ + --hash=sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce + # via + # -r requirements.txt + # pytest-black + # pytest-mypy + # pytest-pylint +pytest-black==0.3.12 \ + --hash=sha256:1d339b004f764d6cd0f06e690f6dd748df3d62e6fe1a692d6a5500ac2c5b75a5 + # via -r requirements.txt +pytest-mypy==0.10.3 \ + --hash=sha256:7638d0d3906848fc1810cb2f5cc7fceb4cc5c98524aafcac58f28620e3102053 \ + --hash=sha256:f8458f642323f13a2ca3e2e61509f7767966b527b4d8adccd5032c3e7b4fd3db + # via -r requirements.txt +pytest-pylint==0.21.0 \ + --hash=sha256:88764b8e1d5cfa18809248e0ccc2fc05035f08c35f0b0222ddcfea1c3c4e553e \ + --hash=sha256:f10d9eaa72b9fbe624ee4b55da0481f56482eee0a467afc1ee3ae8b1fefbd0b4 + # via -r requirements.txt +toml==0.10.2 \ + --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ + --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f + # via pytest-black +tomlkit==0.13.0 \ + --hash=sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72 \ + --hash=sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264 + # via pylint +typing-extensions==4.12.2 \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 + # via mypy diff --git a/tools/interface_generator/test/BUILD.bazel b/tools/interface_generator/test/BUILD.bazel new file mode 100644 index 0000000..2166c4e --- /dev/null +++ b/tools/interface_generator/test/BUILD.bazel @@ -0,0 +1,24 @@ +load("//:defs.bzl", "generate_interface") + +generate_interface( + name = "kstdio", + interface = "kstdio", + license = "//:LICENSE.md", + visibility = ["//visibility:private"], +) + +cc_library( + name = "kstdio_mock", + srcs = ["kstdio_mock.cpp"], + deps = [ + ":kstdio", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_kstdio", + srcs = ["test_kstdio.cpp"], + deps = [":kstdio_mock"], +) diff --git a/tools/interface_generator/test/test_kstdio.cpp b/tools/interface_generator/test/test_kstdio.cpp new file mode 100644 index 0000000..95540a4 --- /dev/null +++ b/tools/interface_generator/test/test_kstdio.cpp @@ -0,0 +1,20 @@ +#include "kstdio_mock.hpp" + +using ::testing::StrEq; + +class kstdioFixture : public ::testing::Test { +protected: + void + SetUp() + { + } + + kstdio_mock m_kstdio_mock; +}; + +TEST_F(kstdioFixture, printfCallsMock) +{ + EXPECT_CALL(m_kstdio_mock, printf(StrEq("hello world"))); + + kstdio_printf("hello world"); +} diff --git a/tools/kconfig/.gitignore b/tools/kconfig/.gitignore deleted file mode 100644 index 22c5c61..0000000 --- a/tools/kconfig/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# generated files -parser.tab.h -parser.tab.c -lex.yy.c - -# binaries -conf -mconf diff --git a/tools/kconfig/Makefile b/tools/kconfig/Makefile deleted file mode 100644 index b7dd104..0000000 --- a/tools/kconfig/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -include ../../Makefile.config - -HOSTTARGETBIN += conf mconf - -lxdiag_srcs := \ - lxdialog/checklist.c lxdialog/inputbox.c lxdialog/menubox.c lxdialog/textbox.c lxdialog/util.c lxdialog/yesno.c - -parser_srcs := \ - confdata.c expr.c menu.c preprocess.c symbol.c util.c \ - lex.yy.c parser.tab.c - -conf.SRCS := ${parser_srcs} conf.c - -mconf.SRCS := ${parser_srcs} ${lxdiag_srcs} mconf.c - -HOST_CFLAGS := -D_GNU_SOURCE $(shell pkg-config --cflags ncursesw) -HOST_LDFLAGS := $(shell pkg-config --libs ncursesw) - -include ../../rules.mk - -%.tab.c: %.y - bison --header --debug $< - -lex.yy.c: lexer.l parser.tab.c - flex $< - -clean: clean.base - @rm -f parser.tab.h parser.tab.c lex.yy.c diff --git a/tools/kconfig/README.md b/tools/kconfig/README.md deleted file mode 100644 index 0c3f693..0000000 --- a/tools/kconfig/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## kconfig - -Description: extracted from the linux kernel - -source: https://kernel.org/ - -commit: 0988a0ea791999ebbf95693f2676381825b05033 - -path: scripts/kconfig diff --git a/tools/kconfig/conf.c b/tools/kconfig/conf.c deleted file mode 100644 index 33d19e4..0000000 --- a/tools/kconfig/conf.c +++ /dev/null @@ -1,921 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ - -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <getopt.h> -#include <sys/time.h> -#include <errno.h> - -#include "lkc.h" - -static void conf(struct menu *menu); -static void check_conf(struct menu *menu); - -enum input_mode { - oldaskconfig, - syncconfig, - oldconfig, - allnoconfig, - allyesconfig, - allmodconfig, - alldefconfig, - randconfig, - defconfig, - savedefconfig, - listnewconfig, - helpnewconfig, - olddefconfig, - yes2modconfig, - mod2yesconfig, - mod2noconfig, -}; -static enum input_mode input_mode = oldaskconfig; -static int input_mode_opt; -static int indent = 1; -static int tty_stdio; -static int sync_kconfig; -static int conf_cnt; -static char line[PATH_MAX]; -static struct menu *rootEntry; - -static void print_help(struct menu *menu) -{ - struct gstr help = str_new(); - - menu_get_ext_help(menu, &help); - - printf("\n%s\n", str_get(&help)); - str_free(&help); -} - -static void strip(char *str) -{ - char *p = str; - int l; - - while ((isspace(*p))) - p++; - l = strlen(p); - if (p != str) - memmove(str, p, l + 1); - if (!l) - return; - p = str + l - 1; - while ((isspace(*p))) - *p-- = 0; -} - -/* Helper function to facilitate fgets() by Jean Sacren. */ -static void xfgets(char *str, int size, FILE *in) -{ - if (!fgets(str, size, in)) - fprintf(stderr, "\nError in reading or end of file.\n"); - - if (!tty_stdio) - printf("%s", str); -} - -static void set_randconfig_seed(void) -{ - unsigned int seed; - char *env; - bool seed_set = false; - - env = getenv("KCONFIG_SEED"); - if (env && *env) { - char *endp; - - seed = strtol(env, &endp, 0); - if (*endp == '\0') - seed_set = true; - } - - if (!seed_set) { - struct timeval now; - - /* - * Use microseconds derived seed, compensate for systems where it may - * be zero. - */ - gettimeofday(&now, NULL); - seed = (now.tv_sec + 1) * (now.tv_usec + 1); - } - - printf("KCONFIG_SEED=0x%X\n", seed); - srand(seed); -} - -static bool randomize_choice_values(struct symbol *csym) -{ - struct property *prop; - struct symbol *sym; - struct expr *e; - int cnt, def; - - /* - * If choice is mod then we may have more items selected - * and if no then no-one. - * In both cases stop. - */ - if (csym->curr.tri != yes) - return false; - - prop = sym_get_choice_prop(csym); - - /* count entries in choice block */ - cnt = 0; - expr_list_for_each_sym(prop->expr, e, sym) - cnt++; - - /* - * find a random value and set it to yes, - * set the rest to no so we have only one set - */ - def = rand() % cnt; - - cnt = 0; - expr_list_for_each_sym(prop->expr, e, sym) { - if (def == cnt++) { - sym->def[S_DEF_USER].tri = yes; - csym->def[S_DEF_USER].val = sym; - } else { - sym->def[S_DEF_USER].tri = no; - } - sym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - sym->flags &= ~SYMBOL_VALID; - } - csym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - csym->flags &= ~SYMBOL_VALID; - - return true; -} - -enum conf_def_mode { - def_default, - def_yes, - def_mod, - def_no, - def_random -}; - -static bool conf_set_all_new_symbols(enum conf_def_mode mode) -{ - struct symbol *sym, *csym; - int i, cnt; - /* - * can't go as the default in switch-case below, otherwise gcc whines - * about -Wmaybe-uninitialized - */ - int pby = 50; /* probability of bool = y */ - int pty = 33; /* probability of tristate = y */ - int ptm = 33; /* probability of tristate = m */ - bool has_changed = false; - - if (mode == def_random) { - int n, p[3]; - char *env = getenv("KCONFIG_PROBABILITY"); - - n = 0; - while (env && *env) { - char *endp; - int tmp = strtol(env, &endp, 10); - - if (tmp >= 0 && tmp <= 100) { - p[n++] = tmp; - } else { - errno = ERANGE; - perror("KCONFIG_PROBABILITY"); - exit(1); - } - env = (*endp == ':') ? endp + 1 : endp; - if (n >= 3) - break; - } - switch (n) { - case 1: - pby = p[0]; - ptm = pby / 2; - pty = pby - ptm; - break; - case 2: - pty = p[0]; - ptm = p[1]; - pby = pty + ptm; - break; - case 3: - pby = p[0]; - pty = p[1]; - ptm = p[2]; - break; - } - - if (pty + ptm > 100) { - errno = ERANGE; - perror("KCONFIG_PROBABILITY"); - exit(1); - } - } - - for_all_symbols(i, sym) { - if (sym_has_value(sym) || sym->flags & SYMBOL_VALID) - continue; - switch (sym_get_type(sym)) { - case S_BOOLEAN: - case S_TRISTATE: - has_changed = true; - switch (mode) { - case def_yes: - sym->def[S_DEF_USER].tri = yes; - break; - case def_mod: - sym->def[S_DEF_USER].tri = mod; - break; - case def_no: - sym->def[S_DEF_USER].tri = no; - break; - case def_random: - sym->def[S_DEF_USER].tri = no; - cnt = rand() % 100; - if (sym->type == S_TRISTATE) { - if (cnt < pty) - sym->def[S_DEF_USER].tri = yes; - else if (cnt < pty + ptm) - sym->def[S_DEF_USER].tri = mod; - } else if (cnt < pby) - sym->def[S_DEF_USER].tri = yes; - break; - default: - continue; - } - if (!(sym_is_choice(sym) && mode == def_random)) - sym->flags |= SYMBOL_DEF_USER; - break; - default: - break; - } - - } - - sym_clear_all_valid(); - - /* - * We have different type of choice blocks. - * If curr.tri equals to mod then we can select several - * choice symbols in one block. - * In this case we do nothing. - * If curr.tri equals yes then only one symbol can be - * selected in a choice block and we set it to yes, - * and the rest to no. - */ - if (mode != def_random) { - for_all_symbols(i, csym) { - if ((sym_is_choice(csym) && !sym_has_value(csym)) || - sym_is_choice_value(csym)) - csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; - } - } - - for_all_symbols(i, csym) { - if (sym_has_value(csym) || !sym_is_choice(csym)) - continue; - - sym_calc_value(csym); - if (mode == def_random) - has_changed |= randomize_choice_values(csym); - else { - set_all_choice_values(csym); - has_changed = true; - } - } - - return has_changed; -} - -static void conf_rewrite_tristates(tristate old_val, tristate new_val) -{ - struct symbol *sym; - int i; - - for_all_symbols(i, sym) { - if (sym_get_type(sym) == S_TRISTATE && - sym->def[S_DEF_USER].tri == old_val) - sym->def[S_DEF_USER].tri = new_val; - } - sym_clear_all_valid(); -} - -static int conf_askvalue(struct symbol *sym, const char *def) -{ - if (!sym_has_value(sym)) - printf("(NEW) "); - - line[0] = '\n'; - line[1] = 0; - - if (!sym_is_changeable(sym)) { - printf("%s\n", def); - line[0] = '\n'; - line[1] = 0; - return 0; - } - - switch (input_mode) { - case oldconfig: - case syncconfig: - if (sym_has_value(sym)) { - printf("%s\n", def); - return 0; - } - /* fall through */ - default: - fflush(stdout); - xfgets(line, sizeof(line), stdin); - break; - } - - return 1; -} - -static int conf_string(struct menu *menu) -{ - struct symbol *sym = menu->sym; - const char *def; - - while (1) { - printf("%*s%s ", indent - 1, "", menu->prompt->text); - printf("(%s) ", sym->name); - def = sym_get_string_value(sym); - if (def) - printf("[%s] ", def); - if (!conf_askvalue(sym, def)) - return 0; - switch (line[0]) { - case '\n': - break; - case '?': - /* print help */ - if (line[1] == '\n') { - print_help(menu); - def = NULL; - break; - } - /* fall through */ - default: - line[strlen(line)-1] = 0; - def = line; - } - if (def && sym_set_string_value(sym, def)) - return 0; - } -} - -static int conf_sym(struct menu *menu) -{ - struct symbol *sym = menu->sym; - tristate oldval, newval; - - while (1) { - printf("%*s%s ", indent - 1, "", menu->prompt->text); - if (sym->name) - printf("(%s) ", sym->name); - putchar('['); - oldval = sym_get_tristate_value(sym); - switch (oldval) { - case no: - putchar('N'); - break; - case mod: - putchar('M'); - break; - case yes: - putchar('Y'); - break; - } - if (oldval != no && sym_tristate_within_range(sym, no)) - printf("/n"); - if (oldval != mod && sym_tristate_within_range(sym, mod)) - printf("/m"); - if (oldval != yes && sym_tristate_within_range(sym, yes)) - printf("/y"); - printf("/?] "); - if (!conf_askvalue(sym, sym_get_string_value(sym))) - return 0; - strip(line); - - switch (line[0]) { - case 'n': - case 'N': - newval = no; - if (!line[1] || !strcmp(&line[1], "o")) - break; - continue; - case 'm': - case 'M': - newval = mod; - if (!line[1]) - break; - continue; - case 'y': - case 'Y': - newval = yes; - if (!line[1] || !strcmp(&line[1], "es")) - break; - continue; - case 0: - newval = oldval; - break; - case '?': - goto help; - default: - continue; - } - if (sym_set_tristate_value(sym, newval)) - return 0; -help: - print_help(menu); - } -} - -static int conf_choice(struct menu *menu) -{ - struct symbol *sym, *def_sym; - struct menu *child; - bool is_new; - - sym = menu->sym; - is_new = !sym_has_value(sym); - if (sym_is_changeable(sym)) { - conf_sym(menu); - sym_calc_value(sym); - switch (sym_get_tristate_value(sym)) { - case no: - return 1; - case mod: - return 0; - case yes: - break; - } - } else { - switch (sym_get_tristate_value(sym)) { - case no: - return 1; - case mod: - printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); - return 0; - case yes: - break; - } - } - - while (1) { - int cnt, def; - - printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); - def_sym = sym_get_choice_value(sym); - cnt = def = 0; - line[0] = 0; - for (child = menu->list; child; child = child->next) { - if (!menu_is_visible(child)) - continue; - if (!child->sym) { - printf("%*c %s\n", indent, '*', menu_get_prompt(child)); - continue; - } - cnt++; - if (child->sym == def_sym) { - def = cnt; - printf("%*c", indent, '>'); - } else - printf("%*c", indent, ' '); - printf(" %d. %s", cnt, menu_get_prompt(child)); - if (child->sym->name) - printf(" (%s)", child->sym->name); - if (!sym_has_value(child->sym)) - printf(" (NEW)"); - printf("\n"); - } - printf("%*schoice", indent - 1, ""); - if (cnt == 1) { - printf("[1]: 1\n"); - goto conf_childs; - } - printf("[1-%d?]: ", cnt); - switch (input_mode) { - case oldconfig: - case syncconfig: - if (!is_new) { - cnt = def; - printf("%d\n", cnt); - break; - } - /* fall through */ - case oldaskconfig: - fflush(stdout); - xfgets(line, sizeof(line), stdin); - strip(line); - if (line[0] == '?') { - print_help(menu); - continue; - } - if (!line[0]) - cnt = def; - else if (isdigit(line[0])) - cnt = atoi(line); - else - continue; - break; - default: - break; - } - - conf_childs: - for (child = menu->list; child; child = child->next) { - if (!child->sym || !menu_is_visible(child)) - continue; - if (!--cnt) - break; - } - if (!child) - continue; - if (line[0] && line[strlen(line) - 1] == '?') { - print_help(child); - continue; - } - sym_set_tristate_value(child->sym, yes); - for (child = child->list; child; child = child->next) { - indent += 2; - conf(child); - indent -= 2; - } - return 1; - } -} - -static void conf(struct menu *menu) -{ - struct symbol *sym; - struct property *prop; - struct menu *child; - - if (!menu_is_visible(menu)) - return; - - sym = menu->sym; - prop = menu->prompt; - if (prop) { - const char *prompt; - - switch (prop->type) { - case P_MENU: - /* - * Except in oldaskconfig mode, we show only menus that - * contain new symbols. - */ - if (input_mode != oldaskconfig && rootEntry != menu) { - check_conf(menu); - return; - } - /* fall through */ - case P_COMMENT: - prompt = menu_get_prompt(menu); - if (prompt) - printf("%*c\n%*c %s\n%*c\n", - indent, '*', - indent, '*', prompt, - indent, '*'); - default: - ; - } - } - - if (!sym) - goto conf_childs; - - if (sym_is_choice(sym)) { - conf_choice(menu); - if (sym->curr.tri != mod) - return; - goto conf_childs; - } - - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - conf_string(menu); - break; - default: - conf_sym(menu); - break; - } - -conf_childs: - if (sym) - indent += 2; - for (child = menu->list; child; child = child->next) - conf(child); - if (sym) - indent -= 2; -} - -static void check_conf(struct menu *menu) -{ - struct symbol *sym; - struct menu *child; - - if (!menu_is_visible(menu)) - return; - - sym = menu->sym; - if (sym && !sym_has_value(sym) && - (sym_is_changeable(sym) || - (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) { - - switch (input_mode) { - case listnewconfig: - if (sym->name) - print_symbol_for_listconfig(sym); - break; - case helpnewconfig: - printf("-----\n"); - print_help(menu); - printf("-----\n"); - break; - default: - if (!conf_cnt++) - printf("*\n* Restart config...\n*\n"); - rootEntry = menu_get_parent_menu(menu); - conf(rootEntry); - break; - } - } - - for (child = menu->list; child; child = child->next) - check_conf(child); -} - -static const struct option long_opts[] = { - {"help", no_argument, NULL, 'h'}, - {"silent", no_argument, NULL, 's'}, - {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig}, - {"oldconfig", no_argument, &input_mode_opt, oldconfig}, - {"syncconfig", no_argument, &input_mode_opt, syncconfig}, - {"defconfig", required_argument, &input_mode_opt, defconfig}, - {"savedefconfig", required_argument, &input_mode_opt, savedefconfig}, - {"allnoconfig", no_argument, &input_mode_opt, allnoconfig}, - {"allyesconfig", no_argument, &input_mode_opt, allyesconfig}, - {"allmodconfig", no_argument, &input_mode_opt, allmodconfig}, - {"alldefconfig", no_argument, &input_mode_opt, alldefconfig}, - {"randconfig", no_argument, &input_mode_opt, randconfig}, - {"listnewconfig", no_argument, &input_mode_opt, listnewconfig}, - {"helpnewconfig", no_argument, &input_mode_opt, helpnewconfig}, - {"olddefconfig", no_argument, &input_mode_opt, olddefconfig}, - {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig}, - {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig}, - {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig}, - {NULL, 0, NULL, 0} -}; - -static void conf_usage(const char *progname) -{ - printf("Usage: %s [options] <kconfig-file>\n", progname); - printf("\n"); - printf("Generic options:\n"); - printf(" -h, --help Print this message and exit.\n"); - printf(" -s, --silent Do not print log.\n"); - printf("\n"); - printf("Mode options:\n"); - printf(" --listnewconfig List new options\n"); - printf(" --helpnewconfig List new options and help text\n"); - printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); - printf(" --oldconfig Update a configuration using a provided .config as base\n"); - printf(" --syncconfig Similar to oldconfig but generates configuration in\n" - " include/{generated/,config/}\n"); - printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n"); - printf(" --defconfig <file> New config with default defined in <file>\n"); - printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); - printf(" --allnoconfig New config where all options are answered with no\n"); - printf(" --allyesconfig New config where all options are answered with yes\n"); - printf(" --allmodconfig New config where all options are answered with mod\n"); - printf(" --alldefconfig New config with all symbols set to default\n"); - printf(" --randconfig New config with random answer to all options\n"); - printf(" --yes2modconfig Change answers from yes to mod if possible\n"); - printf(" --mod2yesconfig Change answers from mod to yes if possible\n"); - printf(" --mod2noconfig Change answers from mod to no if possible\n"); - printf(" (If none of the above is given, --oldaskconfig is the default)\n"); -} - -int main(int ac, char **av) -{ - const char *progname = av[0]; - int opt; - const char *name, *defconfig_file = NULL /* gcc uninit */; - int no_conf_write = 0; - - tty_stdio = isatty(0) && isatty(1); - - while ((opt = getopt_long(ac, av, "hs", long_opts, NULL)) != -1) { - switch (opt) { - case 'h': - conf_usage(progname); - exit(1); - break; - case 's': - conf_set_message_callback(NULL); - break; - case 0: - input_mode = input_mode_opt; - switch (input_mode) { - case syncconfig: - /* - * syncconfig is invoked during the build stage. - * Suppress distracting - * "configuration written to ..." - */ - conf_set_message_callback(NULL); - sync_kconfig = 1; - break; - case defconfig: - case savedefconfig: - defconfig_file = optarg; - break; - case randconfig: - set_randconfig_seed(); - break; - default: - break; - } - default: - break; - } - } - if (ac == optind) { - fprintf(stderr, "%s: Kconfig file missing\n", av[0]); - conf_usage(progname); - exit(1); - } - conf_parse(av[optind]); - //zconfdump(stdout); - - switch (input_mode) { - case defconfig: - if (conf_read(defconfig_file)) { - fprintf(stderr, - "***\n" - "*** Can't find default configuration \"%s\"!\n" - "***\n", - defconfig_file); - exit(1); - } - break; - case savedefconfig: - case syncconfig: - case oldaskconfig: - case oldconfig: - case listnewconfig: - case helpnewconfig: - case olddefconfig: - case yes2modconfig: - case mod2yesconfig: - case mod2noconfig: - conf_read(NULL); - break; - case allnoconfig: - case allyesconfig: - case allmodconfig: - case alldefconfig: - case randconfig: - name = getenv("KCONFIG_ALLCONFIG"); - if (!name) - break; - if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { - if (conf_read_simple(name, S_DEF_USER)) { - fprintf(stderr, - "*** Can't read seed configuration \"%s\"!\n", - name); - exit(1); - } - break; - } - switch (input_mode) { - case allnoconfig: name = "allno.config"; break; - case allyesconfig: name = "allyes.config"; break; - case allmodconfig: name = "allmod.config"; break; - case alldefconfig: name = "alldef.config"; break; - case randconfig: name = "allrandom.config"; break; - default: break; - } - if (conf_read_simple(name, S_DEF_USER) && - conf_read_simple("all.config", S_DEF_USER)) { - fprintf(stderr, - "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n", - name); - exit(1); - } - break; - default: - break; - } - - if (sync_kconfig) { - name = getenv("KCONFIG_NOSILENTUPDATE"); - if (name && *name) { - if (conf_get_changed()) { - fprintf(stderr, - "\n*** The configuration requires explicit update.\n\n"); - return 1; - } - no_conf_write = 1; - } - } - - switch (input_mode) { - case allnoconfig: - conf_set_all_new_symbols(def_no); - break; - case allyesconfig: - conf_set_all_new_symbols(def_yes); - break; - case allmodconfig: - conf_set_all_new_symbols(def_mod); - break; - case alldefconfig: - conf_set_all_new_symbols(def_default); - break; - case randconfig: - /* Really nothing to do in this loop */ - while (conf_set_all_new_symbols(def_random)) ; - break; - case defconfig: - conf_set_all_new_symbols(def_default); - break; - case savedefconfig: - break; - case yes2modconfig: - conf_rewrite_tristates(yes, mod); - break; - case mod2yesconfig: - conf_rewrite_tristates(mod, yes); - break; - case mod2noconfig: - conf_rewrite_tristates(mod, no); - break; - case oldaskconfig: - rootEntry = &rootmenu; - conf(&rootmenu); - input_mode = oldconfig; - /* fall through */ - case oldconfig: - case listnewconfig: - case helpnewconfig: - case syncconfig: - /* Update until a loop caused no more changes */ - do { - conf_cnt = 0; - check_conf(&rootmenu); - } while (conf_cnt); - break; - case olddefconfig: - default: - break; - } - - if (input_mode == savedefconfig) { - if (conf_write_defconfig(defconfig_file)) { - fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n", - defconfig_file); - return 1; - } - } else if (input_mode != listnewconfig && input_mode != helpnewconfig) { - if (!no_conf_write && conf_write(NULL)) { - fprintf(stderr, "\n*** Error during writing of the configuration.\n\n"); - exit(1); - } - - /* - * Create auto.conf if it does not exist. - * This prevents GNU Make 4.1 or older from emitting - * "include/config/auto.conf: No such file or directory" - * in the top-level Makefile - * - * syncconfig always creates or updates auto.conf because it is - * used during the build. - */ - if (conf_write_autoconf(sync_kconfig) && sync_kconfig) { - fprintf(stderr, - "\n*** Error during sync of the configuration.\n\n"); - return 1; - } - } - return 0; -} diff --git a/tools/kconfig/confdata.c b/tools/kconfig/confdata.c deleted file mode 100644 index b7c9f1d..0000000 --- a/tools/kconfig/confdata.c +++ /dev/null @@ -1,1263 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ - -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - -#include "lkc.h" - -/* return true if 'path' exists, false otherwise */ -static bool is_present(const char *path) -{ - struct stat st; - - return !stat(path, &st); -} - -/* return true if 'path' exists and it is a directory, false otherwise */ -static bool is_dir(const char *path) -{ - struct stat st; - - if (stat(path, &st)) - return false; - - return S_ISDIR(st.st_mode); -} - -/* return true if the given two files are the same, false otherwise */ -static bool is_same(const char *file1, const char *file2) -{ - int fd1, fd2; - struct stat st1, st2; - void *map1, *map2; - bool ret = false; - - fd1 = open(file1, O_RDONLY); - if (fd1 < 0) - return ret; - - fd2 = open(file2, O_RDONLY); - if (fd2 < 0) - goto close1; - - ret = fstat(fd1, &st1); - if (ret) - goto close2; - ret = fstat(fd2, &st2); - if (ret) - goto close2; - - if (st1.st_size != st2.st_size) - goto close2; - - map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); - if (map1 == MAP_FAILED) - goto close2; - - map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0); - if (map2 == MAP_FAILED) - goto close2; - - if (bcmp(map1, map2, st1.st_size)) - goto close2; - - ret = true; -close2: - close(fd2); -close1: - close(fd1); - - return ret; -} - -/* - * Create the parent directory of the given path. - * - * For example, if 'include/config/auto.conf' is given, create 'include/config'. - */ -static int make_parent_dir(const char *path) -{ - char tmp[PATH_MAX + 1]; - char *p; - - strncpy(tmp, path, sizeof(tmp)); - tmp[sizeof(tmp) - 1] = 0; - - /* Remove the base name. Just return if nothing is left */ - p = strrchr(tmp, '/'); - if (!p) - return 0; - *(p + 1) = 0; - - /* Just in case it is an absolute path */ - p = tmp; - while (*p == '/') - p++; - - while ((p = strchr(p, '/'))) { - *p = 0; - - /* skip if the directory exists */ - if (!is_dir(tmp) && mkdir(tmp, 0755)) - return -1; - - *p = '/'; - while (*p == '/') - p++; - } - - return 0; -} - -static char depfile_path[PATH_MAX]; -static size_t depfile_prefix_len; - -/* touch depfile for symbol 'name' */ -static int conf_touch_dep(const char *name) -{ - int fd; - - /* check overflow: prefix + name + '\0' must fit in buffer. */ - if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path)) - return -1; - - strcpy(depfile_path + depfile_prefix_len, name); - - fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) - return -1; - close(fd); - - return 0; -} - -static void conf_warning(const char *fmt, ...) - __attribute__ ((format (printf, 1, 2))); - -static void conf_message(const char *fmt, ...) - __attribute__ ((format (printf, 1, 2))); - -static const char *conf_filename; -static int conf_lineno, conf_warnings; - -static void conf_warning(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - conf_warnings++; -} - -static void conf_default_message_callback(const char *s) -{ - printf("#\n# "); - printf("%s", s); - printf("\n#\n"); -} - -static void (*conf_message_callback)(const char *s) = - conf_default_message_callback; -void conf_set_message_callback(void (*fn)(const char *s)) -{ - conf_message_callback = fn; -} - -static void conf_message(const char *fmt, ...) -{ - va_list ap; - char buf[4096]; - - if (!conf_message_callback) - return; - - va_start(ap, fmt); - - vsnprintf(buf, sizeof(buf), fmt, ap); - conf_message_callback(buf); - va_end(ap); -} - -const char *conf_get_configname(void) -{ - char *name = getenv("KCONFIG_CONFIG"); - - return name ? name : ".config"; -} - -static const char *conf_get_autoconfig_name(void) -{ - char *name = getenv("KCONFIG_AUTOCONFIG"); - - return name ? name : "include/config/auto.conf"; -} - -static const char *conf_get_autoheader_name(void) -{ - char *name = getenv("KCONFIG_AUTOHEADER"); - - return name ? name : "include/generated/autoconf.h"; -} - -static const char *conf_get_rustccfg_name(void) -{ - char *name = getenv("KCONFIG_RUSTCCFG"); - - return name ? name : "include/generated/rustc_cfg"; -} - -static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) -{ - char *p2; - - switch (sym->type) { - case S_TRISTATE: - if (p[0] == 'm') { - sym->def[def].tri = mod; - sym->flags |= def_flags; - break; - } - /* fall through */ - case S_BOOLEAN: - if (p[0] == 'y') { - sym->def[def].tri = yes; - sym->flags |= def_flags; - break; - } - if (p[0] == 'n') { - sym->def[def].tri = no; - sym->flags |= def_flags; - break; - } - if (def != S_DEF_AUTO) - conf_warning("symbol value '%s' invalid for %s", - p, sym->name); - return 1; - case S_STRING: - /* No escaping for S_DEF_AUTO (include/config/auto.conf) */ - if (def != S_DEF_AUTO) { - if (*p++ != '"') - break; - for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { - if (*p2 == '"') { - *p2 = 0; - break; - } - memmove(p2, p2 + 1, strlen(p2)); - } - if (!p2) { - conf_warning("invalid string found"); - return 1; - } - } - /* fall through */ - case S_INT: - case S_HEX: - if (sym_string_valid(sym, p)) { - sym->def[def].val = xstrdup(p); - sym->flags |= def_flags; - } else { - if (def != S_DEF_AUTO) - conf_warning("symbol value '%s' invalid for %s", - p, sym->name); - return 1; - } - break; - default: - ; - } - return 0; -} - -#define LINE_GROWTH 16 -static int add_byte(int c, char **lineptr, size_t slen, size_t *n) -{ - char *nline; - size_t new_size = slen + 1; - if (new_size > *n) { - new_size += LINE_GROWTH - 1; - new_size *= 2; - nline = xrealloc(*lineptr, new_size); - if (!nline) - return -1; - - *lineptr = nline; - *n = new_size; - } - - (*lineptr)[slen] = c; - - return 0; -} - -static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) -{ - char *line = *lineptr; - size_t slen = 0; - - for (;;) { - int c = getc(stream); - - switch (c) { - case '\n': - if (add_byte(c, &line, slen, n) < 0) - goto e_out; - slen++; - /* fall through */ - case EOF: - if (add_byte('\0', &line, slen, n) < 0) - goto e_out; - *lineptr = line; - if (slen == 0) - return -1; - return slen; - default: - if (add_byte(c, &line, slen, n) < 0) - goto e_out; - slen++; - } - } - -e_out: - line[slen-1] = '\0'; - *lineptr = line; - return -1; -} - -int conf_read_simple(const char *name, int def) -{ - FILE *in = NULL; - char *line = NULL; - size_t line_asize = 0; - char *p, *p2; - struct symbol *sym; - int i, def_flags; - - if (name) { - in = zconf_fopen(name); - } else { - char *env; - - name = conf_get_configname(); - in = zconf_fopen(name); - if (in) - goto load; - conf_set_changed(true); - - env = getenv("KCONFIG_DEFCONFIG_LIST"); - if (!env) - return 1; - - while (1) { - bool is_last; - - while (isspace(*env)) - env++; - - if (!*env) - break; - - p = env; - while (*p && !isspace(*p)) - p++; - - is_last = (*p == '\0'); - - *p = '\0'; - - in = zconf_fopen(env); - if (in) { - conf_message("using defaults found in %s", - env); - goto load; - } - - if (is_last) - break; - - env = p + 1; - } - } - if (!in) - return 1; - -load: - conf_filename = name; - conf_lineno = 0; - conf_warnings = 0; - - def_flags = SYMBOL_DEF << def; - for_all_symbols(i, sym) { - sym->flags |= SYMBOL_CHANGED; - sym->flags &= ~(def_flags|SYMBOL_VALID); - if (sym_is_choice(sym)) - sym->flags |= def_flags; - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - if (sym->def[def].val) - free(sym->def[def].val); - /* fall through */ - default: - sym->def[def].val = NULL; - sym->def[def].tri = no; - } - } - - while (compat_getline(&line, &line_asize, in) != -1) { - conf_lineno++; - sym = NULL; - if (line[0] == '#') { - if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) - continue; - p = strchr(line + 2 + strlen(CONFIG_), ' '); - if (!p) - continue; - *p++ = 0; - if (strncmp(p, "is not set", 10)) - continue; - if (def == S_DEF_USER) { - sym = sym_find(line + 2 + strlen(CONFIG_)); - if (!sym) { - conf_set_changed(true); - continue; - } - } else { - sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); - if (sym->type == S_UNKNOWN) - sym->type = S_BOOLEAN; - } - if (sym->flags & def_flags) { - conf_warning("override: reassigning to symbol %s", sym->name); - } - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - sym->def[def].tri = no; - sym->flags |= def_flags; - break; - default: - ; - } - } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { - p = strchr(line + strlen(CONFIG_), '='); - if (!p) - continue; - *p++ = 0; - p2 = strchr(p, '\n'); - if (p2) { - *p2-- = 0; - if (*p2 == '\r') - *p2 = 0; - } - - sym = sym_find(line + strlen(CONFIG_)); - if (!sym) { - if (def == S_DEF_AUTO) - /* - * Reading from include/config/auto.conf - * If CONFIG_FOO previously existed in - * auto.conf but it is missing now, - * include/config/FOO must be touched. - */ - conf_touch_dep(line + strlen(CONFIG_)); - else - conf_set_changed(true); - continue; - } - - if (sym->flags & def_flags) { - conf_warning("override: reassigning to symbol %s", sym->name); - } - if (conf_set_sym_val(sym, def, def_flags, p)) - continue; - } else { - if (line[0] != '\r' && line[0] != '\n') - conf_warning("unexpected data: %.*s", - (int)strcspn(line, "\r\n"), line); - - continue; - } - - if (sym && sym_is_choice_value(sym)) { - struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - switch (sym->def[def].tri) { - case no: - break; - case mod: - if (cs->def[def].tri == yes) { - conf_warning("%s creates inconsistent choice state", sym->name); - cs->flags &= ~def_flags; - } - break; - case yes: - if (cs->def[def].tri != no) - conf_warning("override: %s changes choice state", sym->name); - cs->def[def].val = sym; - break; - } - cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); - } - } - free(line); - fclose(in); - return 0; -} - -int conf_read(const char *name) -{ - struct symbol *sym; - int conf_unsaved = 0; - int i; - - conf_set_changed(false); - - if (conf_read_simple(name, S_DEF_USER)) { - sym_calc_value(modules_sym); - return 1; - } - - sym_calc_value(modules_sym); - - for_all_symbols(i, sym) { - sym_calc_value(sym); - if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE)) - continue; - if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { - /* check that calculated value agrees with saved value */ - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym)) - continue; - break; - default: - if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) - continue; - break; - } - } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) - /* no previous value and not saved */ - continue; - conf_unsaved++; - /* maybe print value in verbose mode... */ - } - - for_all_symbols(i, sym) { - if (sym_has_value(sym) && !sym_is_choice_value(sym)) { - /* Reset values of generates values, so they'll appear - * as new, if they should become visible, but that - * doesn't quite work if the Kconfig and the saved - * configuration disagree. - */ - if (sym->visible == no && !conf_unsaved) - sym->flags &= ~SYMBOL_DEF_USER; - switch (sym->type) { - case S_STRING: - case S_INT: - case S_HEX: - /* Reset a string value if it's out of range */ - if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) - break; - sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); - conf_unsaved++; - break; - default: - break; - } - } - } - - if (conf_warnings || conf_unsaved) - conf_set_changed(true); - - return 0; -} - -struct comment_style { - const char *decoration; - const char *prefix; - const char *postfix; -}; - -static const struct comment_style comment_style_pound = { - .decoration = "#", - .prefix = "#", - .postfix = "#", -}; - -static const struct comment_style comment_style_c = { - .decoration = " *", - .prefix = "/*", - .postfix = " */", -}; - -static void conf_write_heading(FILE *fp, const struct comment_style *cs) -{ - if (!cs) - return; - - fprintf(fp, "%s\n", cs->prefix); - - fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n", - cs->decoration); - - fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text); - - fprintf(fp, "%s\n", cs->postfix); -} - -/* The returned pointer must be freed on the caller side */ -static char *escape_string_value(const char *in) -{ - const char *p; - char *out; - size_t len; - - len = strlen(in) + strlen("\"\"") + 1; - - p = in; - while (1) { - p += strcspn(p, "\"\\"); - - if (p[0] == '\0') - break; - - len++; - p++; - } - - out = xmalloc(len); - out[0] = '\0'; - - strcat(out, "\""); - - p = in; - while (1) { - len = strcspn(p, "\"\\"); - strncat(out, p, len); - p += len; - - if (p[0] == '\0') - break; - - strcat(out, "\\"); - strncat(out, p++, 1); - } - - strcat(out, "\""); - - return out; -} - -enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE }; - -static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n, - bool escape_string) -{ - const char *val; - char *escaped = NULL; - - if (sym->type == S_UNKNOWN) - return; - - val = sym_get_string_value(sym); - - if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) && - output_n != OUTPUT_N && *val == 'n') { - if (output_n == OUTPUT_N_AS_UNSET) - fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name); - return; - } - - if (sym->type == S_STRING && escape_string) { - escaped = escape_string_value(val); - val = escaped; - } - - fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val); - - free(escaped); -} - -static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym) -{ - __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true); -} - -static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym) -{ - __print_symbol(fp, sym, OUTPUT_N_NONE, false); -} - -void print_symbol_for_listconfig(struct symbol *sym) -{ - __print_symbol(stdout, sym, OUTPUT_N, true); -} - -static void print_symbol_for_c(FILE *fp, struct symbol *sym) -{ - const char *val; - const char *sym_suffix = ""; - const char *val_prefix = ""; - char *escaped = NULL; - - if (sym->type == S_UNKNOWN) - return; - - val = sym_get_string_value(sym); - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - switch (*val) { - case 'n': - return; - case 'm': - sym_suffix = "_MODULE"; - /* fall through */ - default: - val = "1"; - } - break; - case S_HEX: - if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) - val_prefix = "0x"; - break; - case S_STRING: - escaped = escape_string_value(val); - val = escaped; - default: - break; - } - - fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix, - val_prefix, val); - - free(escaped); -} - -static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym) -{ - const char *val; - const char *val_prefix = ""; - char *val_prefixed = NULL; - size_t val_prefixed_len; - char *escaped = NULL; - - if (sym->type == S_UNKNOWN) - return; - - val = sym_get_string_value(sym); - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - /* - * We do not care about disabled ones, i.e. no need for - * what otherwise are "comments" in other printers. - */ - if (*val == 'n') - return; - - /* - * To have similar functionality to the C macro `IS_ENABLED()` - * we provide an empty `--cfg CONFIG_X` here in both `y` - * and `m` cases. - * - * Then, the common `fprintf()` below will also give us - * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can - * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`. - */ - fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name); - break; - case S_HEX: - if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) - val_prefix = "0x"; - break; - default: - break; - } - - if (strlen(val_prefix) > 0) { - val_prefixed_len = strlen(val) + strlen(val_prefix) + 1; - val_prefixed = xmalloc(val_prefixed_len); - snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val); - val = val_prefixed; - } - - /* All values get escaped: the `--cfg` option only takes strings */ - escaped = escape_string_value(val); - val = escaped; - - fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val); - - free(escaped); - free(val_prefixed); -} - -/* - * Write out a minimal config. - * All values that has default values are skipped as this is redundant. - */ -int conf_write_defconfig(const char *filename) -{ - struct symbol *sym; - struct menu *menu; - FILE *out; - - out = fopen(filename, "w"); - if (!out) - return 1; - - sym_clear_all_valid(); - - /* Traverse all menus to find all relevant symbols */ - menu = rootmenu.list; - - while (menu != NULL) - { - sym = menu->sym; - if (sym == NULL) { - if (!menu_is_visible(menu)) - goto next_menu; - } else if (!sym_is_choice(sym)) { - sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE)) - goto next_menu; - sym->flags &= ~SYMBOL_WRITE; - /* If we cannot change the symbol - skip */ - if (!sym_is_changeable(sym)) - goto next_menu; - /* If symbol equals to default value - skip */ - if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) - goto next_menu; - - /* - * If symbol is a choice value and equals to the - * default for a choice - skip. - * But only if value is bool and equal to "y" and - * choice is not "optional". - * (If choice is "optional" then all values can be "n") - */ - if (sym_is_choice_value(sym)) { - struct symbol *cs; - struct symbol *ds; - - cs = prop_get_symbol(sym_get_choice_prop(sym)); - ds = sym_choice_default(cs); - if (!sym_is_optional(cs) && sym == ds) { - if ((sym->type == S_BOOLEAN) && - sym_get_tristate_value(sym) == yes) - goto next_menu; - } - } - print_symbol_for_dotconfig(out, sym); - } -next_menu: - if (menu->list != NULL) { - menu = menu->list; - } - else if (menu->next != NULL) { - menu = menu->next; - } else { - while ((menu = menu->parent)) { - if (menu->next != NULL) { - menu = menu->next; - break; - } - } - } - } - fclose(out); - return 0; -} - -int conf_write(const char *name) -{ - FILE *out; - struct symbol *sym; - struct menu *menu; - const char *str; - char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1]; - char *env; - int i; - bool need_newline = false; - - if (!name) - name = conf_get_configname(); - - if (!*name) { - fprintf(stderr, "config name is empty\n"); - return -1; - } - - if (is_dir(name)) { - fprintf(stderr, "%s: Is a directory\n", name); - return -1; - } - - if (make_parent_dir(name)) - return -1; - - env = getenv("KCONFIG_OVERWRITECONFIG"); - if (env && *env) { - *tmpname = 0; - out = fopen(name, "w"); - } else { - snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp", - name, (int)getpid()); - out = fopen(tmpname, "w"); - } - if (!out) - return 1; - - conf_write_heading(out, &comment_style_pound); - - if (!conf_get_changed()) - sym_clear_all_valid(); - - menu = rootmenu.list; - while (menu) { - sym = menu->sym; - if (!sym) { - if (!menu_is_visible(menu)) - goto next; - str = menu_get_prompt(menu); - fprintf(out, "\n" - "#\n" - "# %s\n" - "#\n", str); - need_newline = false; - } else if (!(sym->flags & SYMBOL_CHOICE) && - !(sym->flags & SYMBOL_WRITTEN)) { - sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE)) - goto next; - if (need_newline) { - fprintf(out, "\n"); - need_newline = false; - } - sym->flags |= SYMBOL_WRITTEN; - print_symbol_for_dotconfig(out, sym); - } - -next: - if (menu->list) { - menu = menu->list; - continue; - } - -end_check: - if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu && - menu->prompt->type == P_MENU) { - fprintf(out, "# end of %s\n", menu_get_prompt(menu)); - need_newline = true; - } - - if (menu->next) { - menu = menu->next; - } else { - menu = menu->parent; - if (menu) - goto end_check; - } - } - fclose(out); - - for_all_symbols(i, sym) - sym->flags &= ~SYMBOL_WRITTEN; - - if (*tmpname) { - if (is_same(name, tmpname)) { - conf_message("No change to %s", name); - unlink(tmpname); - conf_set_changed(false); - return 0; - } - - snprintf(oldname, sizeof(oldname), "%s.old", name); - rename(name, oldname); - if (rename(tmpname, name)) - return 1; - } - - conf_message("configuration written to %s", name); - - conf_set_changed(false); - - return 0; -} - -/* write a dependency file as used by kbuild to track dependencies */ -static int conf_write_autoconf_cmd(const char *autoconf_name) -{ - char name[PATH_MAX], tmp[PATH_MAX]; - struct file *file; - FILE *out; - int ret; - - ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name); - if (ret >= sizeof(name)) /* check truncation */ - return -1; - - if (make_parent_dir(name)) - return -1; - - ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name); - if (ret >= sizeof(tmp)) /* check truncation */ - return -1; - - out = fopen(tmp, "w"); - if (!out) { - perror("fopen"); - return -1; - } - - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) - fprintf(out, "\t%s \\\n", file->name); - - fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name); - - env_write_dep(out, autoconf_name); - - fprintf(out, "\n$(deps_config): ;\n"); - - fflush(out); - ret = ferror(out); /* error check for all fprintf() calls */ - fclose(out); - if (ret) - return -1; - - if (rename(tmp, name)) { - perror("rename"); - return -1; - } - - return 0; -} - -static int conf_touch_deps(void) -{ - const char *name, *tmp; - struct symbol *sym; - int res, i; - - name = conf_get_autoconfig_name(); - tmp = strrchr(name, '/'); - depfile_prefix_len = tmp ? tmp - name + 1 : 0; - if (depfile_prefix_len + 1 > sizeof(depfile_path)) - return -1; - - strncpy(depfile_path, name, depfile_prefix_len); - depfile_path[depfile_prefix_len] = 0; - - conf_read_simple(name, S_DEF_AUTO); - sym_calc_value(modules_sym); - - for_all_symbols(i, sym) { - sym_calc_value(sym); - if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name) - continue; - if (sym->flags & SYMBOL_WRITE) { - if (sym->flags & SYMBOL_DEF_AUTO) { - /* - * symbol has old and new value, - * so compare them... - */ - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym_get_tristate_value(sym) == - sym->def[S_DEF_AUTO].tri) - continue; - break; - case S_STRING: - case S_HEX: - case S_INT: - if (!strcmp(sym_get_string_value(sym), - sym->def[S_DEF_AUTO].val)) - continue; - break; - default: - break; - } - } else { - /* - * If there is no old value, only 'no' (unset) - * is allowed as new value. - */ - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym_get_tristate_value(sym) == no) - continue; - break; - default: - break; - } - } - } else if (!(sym->flags & SYMBOL_DEF_AUTO)) - /* There is neither an old nor a new value. */ - continue; - /* else - * There is an old value, but no new value ('no' (unset) - * isn't saved in auto.conf, so the old value is always - * different from 'no'). - */ - - res = conf_touch_dep(sym->name); - if (res) - return res; - } - - return 0; -} - -static int __conf_write_autoconf(const char *filename, - void (*print_symbol)(FILE *, struct symbol *), - const struct comment_style *comment_style) -{ - char tmp[PATH_MAX]; - FILE *file; - struct symbol *sym; - int ret, i; - - if (make_parent_dir(filename)) - return -1; - - ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename); - if (ret >= sizeof(tmp)) /* check truncation */ - return -1; - - file = fopen(tmp, "w"); - if (!file) { - perror("fopen"); - return -1; - } - - conf_write_heading(file, comment_style); - - for_all_symbols(i, sym) - if ((sym->flags & SYMBOL_WRITE) && sym->name) - print_symbol(file, sym); - - fflush(file); - /* check possible errors in conf_write_heading() and print_symbol() */ - ret = ferror(file); - fclose(file); - if (ret) - return -1; - - if (rename(tmp, filename)) { - perror("rename"); - return -1; - } - - return 0; -} - -int conf_write_autoconf(int overwrite) -{ - struct symbol *sym; - const char *autoconf_name = conf_get_autoconfig_name(); - int ret, i; - - if (!overwrite && is_present(autoconf_name)) - return 0; - - ret = conf_write_autoconf_cmd(autoconf_name); - if (ret) - return -1; - - if (conf_touch_deps()) - return 1; - - for_all_symbols(i, sym) - sym_calc_value(sym); - - ret = __conf_write_autoconf(conf_get_autoheader_name(), - print_symbol_for_c, - &comment_style_c); - if (ret) - return ret; - - ret = __conf_write_autoconf(conf_get_rustccfg_name(), - print_symbol_for_rustccfg, - NULL); - if (ret) - return ret; - - /* - * Create include/config/auto.conf. This must be the last step because - * Kbuild has a dependency on auto.conf and this marks the successful - * completion of the previous steps. - */ - ret = __conf_write_autoconf(conf_get_autoconfig_name(), - print_symbol_for_autoconf, - &comment_style_pound); - if (ret) - return ret; - - return 0; -} - -static bool conf_changed; -static void (*conf_changed_callback)(void); - -void conf_set_changed(bool val) -{ - if (conf_changed_callback && conf_changed != val) - conf_changed_callback(); - - conf_changed = val; -} - -bool conf_get_changed(void) -{ - return conf_changed; -} - -void conf_set_changed_callback(void (*fn)(void)) -{ - conf_changed_callback = fn; -} - -void set_all_choice_values(struct symbol *csym) -{ - struct property *prop; - struct symbol *sym; - struct expr *e; - - prop = sym_get_choice_prop(csym); - - /* - * Set all non-assinged choice values to no - */ - expr_list_for_each_sym(prop->expr, e, sym) { - if (!sym_has_value(sym)) - sym->def[S_DEF_USER].tri = no; - } - csym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); -} diff --git a/tools/kconfig/expr.c b/tools/kconfig/expr.c deleted file mode 100644 index 81ebf81..0000000 --- a/tools/kconfig/expr.c +++ /dev/null @@ -1,1303 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ - -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "lkc.h" - -#define DEBUG_EXPR 0 - -static struct expr *expr_eliminate_yn(struct expr *e); - -struct expr *expr_alloc_symbol(struct symbol *sym) -{ - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = E_SYMBOL; - e->left.sym = sym; - return e; -} - -struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) -{ - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.expr = ce; - return e; -} - -struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) -{ - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.expr = e1; - e->right.expr = e2; - return e; -} - -struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) -{ - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.sym = s1; - e->right.sym = s2; - return e; -} - -struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) -{ - if (!e1) - return e2; - return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; -} - -struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) -{ - if (!e1) - return e2; - return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; -} - -struct expr *expr_copy(const struct expr *org) -{ - struct expr *e; - - if (!org) - return NULL; - - e = xmalloc(sizeof(*org)); - memcpy(e, org, sizeof(*org)); - switch (org->type) { - case E_SYMBOL: - e->left = org->left; - break; - case E_NOT: - e->left.expr = expr_copy(org->left.expr); - break; - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - e->left.sym = org->left.sym; - e->right.sym = org->right.sym; - break; - case E_AND: - case E_OR: - case E_LIST: - e->left.expr = expr_copy(org->left.expr); - e->right.expr = expr_copy(org->right.expr); - break; - default: - fprintf(stderr, "can't copy type %d\n", e->type); - free(e); - e = NULL; - break; - } - - return e; -} - -void expr_free(struct expr *e) -{ - if (!e) - return; - - switch (e->type) { - case E_SYMBOL: - break; - case E_NOT: - expr_free(e->left.expr); - break; - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - break; - case E_OR: - case E_AND: - expr_free(e->left.expr); - expr_free(e->right.expr); - break; - default: - fprintf(stderr, "how to free type %d?\n", e->type); - break; - } - free(e); -} - -static int trans_count; - -#define e1 (*ep1) -#define e2 (*ep2) - -/* - * expr_eliminate_eq() helper. - * - * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does - * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared - * against all other leaves. Two equal leaves are both replaced with either 'y' - * or 'n' as appropriate for 'type', to be eliminated later. - */ -static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) -{ - /* Recurse down to leaves */ - - if (e1->type == type) { - __expr_eliminate_eq(type, &e1->left.expr, &e2); - __expr_eliminate_eq(type, &e1->right.expr, &e2); - return; - } - if (e2->type == type) { - __expr_eliminate_eq(type, &e1, &e2->left.expr); - __expr_eliminate_eq(type, &e1, &e2->right.expr); - return; - } - - /* e1 and e2 are leaves. Compare them. */ - - if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && - e1->left.sym == e2->left.sym && - (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) - return; - if (!expr_eq(e1, e2)) - return; - - /* e1 and e2 are equal leaves. Prepare them for elimination. */ - - trans_count++; - expr_free(e1); expr_free(e2); - switch (type) { - case E_OR: - e1 = expr_alloc_symbol(&symbol_no); - e2 = expr_alloc_symbol(&symbol_no); - break; - case E_AND: - e1 = expr_alloc_symbol(&symbol_yes); - e2 = expr_alloc_symbol(&symbol_yes); - break; - default: - ; - } -} - -/* - * Rewrites the expressions 'ep1' and 'ep2' to remove operands common to both. - * Example reductions: - * - * ep1: A && B -> ep1: y - * ep2: A && B && C -> ep2: C - * - * ep1: A || B -> ep1: n - * ep2: A || B || C -> ep2: C - * - * ep1: A && (B && FOO) -> ep1: FOO - * ep2: (BAR && B) && A -> ep2: BAR - * - * ep1: A && (B || C) -> ep1: y - * ep2: (C || B) && A -> ep2: y - * - * Comparisons are done between all operands at the same "level" of && or ||. - * For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the - * following operands will be compared: - * - * - 'e1', 'e2 || e3', and 'e4 || e5', against each other - * - e2 against e3 - * - e4 against e5 - * - * Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and - * '(e1 && e2) && e3' are both a single level. - * - * See __expr_eliminate_eq() as well. - */ -void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) -{ - if (!e1 || !e2) - return; - switch (e1->type) { - case E_OR: - case E_AND: - __expr_eliminate_eq(e1->type, ep1, ep2); - default: - ; - } - if (e1->type != e2->type) switch (e2->type) { - case E_OR: - case E_AND: - __expr_eliminate_eq(e2->type, ep1, ep2); - default: - ; - } - e1 = expr_eliminate_yn(e1); - e2 = expr_eliminate_yn(e2); -} - -#undef e1 -#undef e2 - -/* - * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two - * &&/|| expressions are considered equal if every operand in one expression - * equals some operand in the other (operands do not need to appear in the same - * order), recursively. - */ -int expr_eq(struct expr *e1, struct expr *e2) -{ - int res, old_count; - - /* - * A NULL expr is taken to be yes, but there's also a different way to - * represent yes. expr_is_yes() checks for either representation. - */ - if (!e1 || !e2) - return expr_is_yes(e1) && expr_is_yes(e2); - - if (e1->type != e2->type) - return 0; - switch (e1->type) { - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; - case E_SYMBOL: - return e1->left.sym == e2->left.sym; - case E_NOT: - return expr_eq(e1->left.expr, e2->left.expr); - case E_AND: - case E_OR: - e1 = expr_copy(e1); - e2 = expr_copy(e2); - old_count = trans_count; - expr_eliminate_eq(&e1, &e2); - res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && - e1->left.sym == e2->left.sym); - expr_free(e1); - expr_free(e2); - trans_count = old_count; - return res; - case E_LIST: - case E_RANGE: - case E_NONE: - /* panic */; - } - - if (DEBUG_EXPR) { - expr_fprint(e1, stdout); - printf(" = "); - expr_fprint(e2, stdout); - printf(" ?\n"); - } - - return 0; -} - -/* - * Recursively performs the following simplifications in-place (as well as the - * corresponding simplifications with swapped operands): - * - * expr && n -> n - * expr && y -> expr - * expr || n -> expr - * expr || y -> y - * - * Returns the optimized expression. - */ -static struct expr *expr_eliminate_yn(struct expr *e) -{ - struct expr *tmp; - - if (e) switch (e->type) { - case E_AND: - e->left.expr = expr_eliminate_yn(e->left.expr); - e->right.expr = expr_eliminate_yn(e->right.expr); - if (e->left.expr->type == E_SYMBOL) { - if (e->left.expr->left.sym == &symbol_no) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.expr = NULL; - return e; - } else if (e->left.expr->left.sym == &symbol_yes) { - free(e->left.expr); - tmp = e->right.expr; - *e = *(e->right.expr); - free(tmp); - return e; - } - } - if (e->right.expr->type == E_SYMBOL) { - if (e->right.expr->left.sym == &symbol_no) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.expr = NULL; - return e; - } else if (e->right.expr->left.sym == &symbol_yes) { - free(e->right.expr); - tmp = e->left.expr; - *e = *(e->left.expr); - free(tmp); - return e; - } - } - break; - case E_OR: - e->left.expr = expr_eliminate_yn(e->left.expr); - e->right.expr = expr_eliminate_yn(e->right.expr); - if (e->left.expr->type == E_SYMBOL) { - if (e->left.expr->left.sym == &symbol_no) { - free(e->left.expr); - tmp = e->right.expr; - *e = *(e->right.expr); - free(tmp); - return e; - } else if (e->left.expr->left.sym == &symbol_yes) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.expr = NULL; - return e; - } - } - if (e->right.expr->type == E_SYMBOL) { - if (e->right.expr->left.sym == &symbol_no) { - free(e->right.expr); - tmp = e->left.expr; - *e = *(e->left.expr); - free(tmp); - return e; - } else if (e->right.expr->left.sym == &symbol_yes) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.expr = NULL; - return e; - } - } - break; - default: - ; - } - return e; -} - -/* - * bool FOO!=n => FOO - */ -struct expr *expr_trans_bool(struct expr *e) -{ - if (!e) - return NULL; - switch (e->type) { - case E_AND: - case E_OR: - case E_NOT: - e->left.expr = expr_trans_bool(e->left.expr); - e->right.expr = expr_trans_bool(e->right.expr); - break; - case E_UNEQUAL: - // FOO!=n -> FOO - if (e->left.sym->type == S_TRISTATE) { - if (e->right.sym == &symbol_no) { - e->type = E_SYMBOL; - e->right.sym = NULL; - } - } - break; - default: - ; - } - return e; -} - -/* - * e1 || e2 -> ? - */ -static struct expr *expr_join_or(struct expr *e1, struct expr *e2) -{ - struct expr *tmp; - struct symbol *sym1, *sym2; - - if (expr_eq(e1, e2)) - return expr_copy(e1); - if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) - return NULL; - if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) - return NULL; - if (e1->type == E_NOT) { - tmp = e1->left.expr; - if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) - return NULL; - sym1 = tmp->left.sym; - } else - sym1 = e1->left.sym; - if (e2->type == E_NOT) { - if (e2->left.expr->type != E_SYMBOL) - return NULL; - sym2 = e2->left.expr->left.sym; - } else - sym2 = e2->left.sym; - if (sym1 != sym2) - return NULL; - if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) - return NULL; - if (sym1->type == S_TRISTATE) { - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || - (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { - // (a='y') || (a='m') -> (a!='n') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); - } - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { - // (a='y') || (a='n') -> (a!='m') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); - } - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { - // (a='m') || (a='n') -> (a!='y') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); - } - } - if (sym1->type == S_BOOLEAN && sym1 == sym2) { - if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || - (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) - return expr_alloc_symbol(&symbol_yes); - } - - if (DEBUG_EXPR) { - printf("optimize ("); - expr_fprint(e1, stdout); - printf(") || ("); - expr_fprint(e2, stdout); - printf(")?\n"); - } - return NULL; -} - -static struct expr *expr_join_and(struct expr *e1, struct expr *e2) -{ - struct expr *tmp; - struct symbol *sym1, *sym2; - - if (expr_eq(e1, e2)) - return expr_copy(e1); - if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) - return NULL; - if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) - return NULL; - if (e1->type == E_NOT) { - tmp = e1->left.expr; - if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) - return NULL; - sym1 = tmp->left.sym; - } else - sym1 = e1->left.sym; - if (e2->type == E_NOT) { - if (e2->left.expr->type != E_SYMBOL) - return NULL; - sym2 = e2->left.expr->left.sym; - } else - sym2 = e2->left.sym; - if (sym1 != sym2) - return NULL; - if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) - return NULL; - - if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || - (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) - // (a) && (a='y') -> (a='y') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) - // (a) && (a!='n') -> (a) - return expr_alloc_symbol(sym1); - - if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) - // (a) && (a!='m') -> (a='y') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if (sym1->type == S_TRISTATE) { - if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { - // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' - sym2 = e1->right.sym; - if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) - return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) - : expr_alloc_symbol(&symbol_no); - } - if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { - // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' - sym2 = e2->right.sym; - if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) - return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) - : expr_alloc_symbol(&symbol_no); - } - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) - // (a!='y') && (a!='n') -> (a='m') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); - - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || - (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) - // (a!='y') && (a!='m') -> (a='n') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); - - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) - // (a!='m') && (a!='n') -> (a='m') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || - (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || - (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) - return NULL; - } - - if (DEBUG_EXPR) { - printf("optimize ("); - expr_fprint(e1, stdout); - printf(") && ("); - expr_fprint(e2, stdout); - printf(")?\n"); - } - return NULL; -} - -/* - * expr_eliminate_dups() helper. - * - * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does - * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared - * against all other leaves to look for simplifications. - */ -static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) -{ -#define e1 (*ep1) -#define e2 (*ep2) - struct expr *tmp; - - /* Recurse down to leaves */ - - if (e1->type == type) { - expr_eliminate_dups1(type, &e1->left.expr, &e2); - expr_eliminate_dups1(type, &e1->right.expr, &e2); - return; - } - if (e2->type == type) { - expr_eliminate_dups1(type, &e1, &e2->left.expr); - expr_eliminate_dups1(type, &e1, &e2->right.expr); - return; - } - - /* e1 and e2 are leaves. Compare and process them. */ - - if (e1 == e2) - return; - - switch (e1->type) { - case E_OR: case E_AND: - expr_eliminate_dups1(e1->type, &e1, &e1); - default: - ; - } - - switch (type) { - case E_OR: - tmp = expr_join_or(e1, e2); - if (tmp) { - expr_free(e1); expr_free(e2); - e1 = expr_alloc_symbol(&symbol_no); - e2 = tmp; - trans_count++; - } - break; - case E_AND: - tmp = expr_join_and(e1, e2); - if (tmp) { - expr_free(e1); expr_free(e2); - e1 = expr_alloc_symbol(&symbol_yes); - e2 = tmp; - trans_count++; - } - break; - default: - ; - } -#undef e1 -#undef e2 -} - -/* - * Rewrites 'e' in-place to remove ("join") duplicate and other redundant - * operands. - * - * Example simplifications: - * - * A || B || A -> A || B - * A && B && A=y -> A=y && B - * - * Returns the deduplicated expression. - */ -struct expr *expr_eliminate_dups(struct expr *e) -{ - int oldcount; - if (!e) - return e; - - oldcount = trans_count; - while (1) { - trans_count = 0; - switch (e->type) { - case E_OR: case E_AND: - expr_eliminate_dups1(e->type, &e, &e); - default: - ; - } - if (!trans_count) - /* No simplifications done in this pass. We're done */ - break; - e = expr_eliminate_yn(e); - } - trans_count = oldcount; - return e; -} - -/* - * Performs various simplifications involving logical operators and - * comparisons. - * - * Allocates and returns a new expression. - */ -struct expr *expr_transform(struct expr *e) -{ - struct expr *tmp; - - if (!e) - return NULL; - switch (e->type) { - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - case E_SYMBOL: - case E_LIST: - break; - default: - e->left.expr = expr_transform(e->left.expr); - e->right.expr = expr_transform(e->right.expr); - } - - switch (e->type) { - case E_EQUAL: - if (e->left.sym->type != S_BOOLEAN) - break; - if (e->right.sym == &symbol_no) { - e->type = E_NOT; - e->left.expr = expr_alloc_symbol(e->left.sym); - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_mod) { - printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_yes) { - e->type = E_SYMBOL; - e->right.sym = NULL; - break; - } - break; - case E_UNEQUAL: - if (e->left.sym->type != S_BOOLEAN) - break; - if (e->right.sym == &symbol_no) { - e->type = E_SYMBOL; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_mod) { - printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_yes) { - e->type = E_NOT; - e->left.expr = expr_alloc_symbol(e->left.sym); - e->right.sym = NULL; - break; - } - break; - case E_NOT: - switch (e->left.expr->type) { - case E_NOT: - // !!a -> a - tmp = e->left.expr->left.expr; - free(e->left.expr); - free(e); - e = tmp; - e = expr_transform(e); - break; - case E_EQUAL: - case E_UNEQUAL: - // !a='x' -> a!='x' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; - break; - case E_LEQ: - case E_GEQ: - // !a<='x' -> a>'x' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_LEQ ? E_GTH : E_LTH; - break; - case E_LTH: - case E_GTH: - // !a<'x' -> a>='x' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_LTH ? E_GEQ : E_LEQ; - break; - case E_OR: - // !(a || b) -> !a && !b - tmp = e->left.expr; - e->type = E_AND; - e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); - tmp->type = E_NOT; - tmp->right.expr = NULL; - e = expr_transform(e); - break; - case E_AND: - // !(a && b) -> !a || !b - tmp = e->left.expr; - e->type = E_OR; - e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); - tmp->type = E_NOT; - tmp->right.expr = NULL; - e = expr_transform(e); - break; - case E_SYMBOL: - if (e->left.expr->left.sym == &symbol_yes) { - // !'y' -> 'n' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - break; - } - if (e->left.expr->left.sym == &symbol_mod) { - // !'m' -> 'm' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_mod; - break; - } - if (e->left.expr->left.sym == &symbol_no) { - // !'n' -> 'y' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - break; - } - break; - default: - ; - } - break; - default: - ; - } - return e; -} - -int expr_contains_symbol(struct expr *dep, struct symbol *sym) -{ - if (!dep) - return 0; - - switch (dep->type) { - case E_AND: - case E_OR: - return expr_contains_symbol(dep->left.expr, sym) || - expr_contains_symbol(dep->right.expr, sym); - case E_SYMBOL: - return dep->left.sym == sym; - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - return dep->left.sym == sym || - dep->right.sym == sym; - case E_NOT: - return expr_contains_symbol(dep->left.expr, sym); - default: - ; - } - return 0; -} - -bool expr_depends_symbol(struct expr *dep, struct symbol *sym) -{ - if (!dep) - return false; - - switch (dep->type) { - case E_AND: - return expr_depends_symbol(dep->left.expr, sym) || - expr_depends_symbol(dep->right.expr, sym); - case E_SYMBOL: - return dep->left.sym == sym; - case E_EQUAL: - if (dep->left.sym == sym) { - if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) - return true; - } - break; - case E_UNEQUAL: - if (dep->left.sym == sym) { - if (dep->right.sym == &symbol_no) - return true; - } - break; - default: - ; - } - return false; -} - -/* - * Inserts explicit comparisons of type 'type' to symbol 'sym' into the - * expression 'e'. - * - * Examples transformations for type == E_UNEQUAL, sym == &symbol_no: - * - * A -> A!=n - * !A -> A=n - * A && B -> !(A=n || B=n) - * A || B -> !(A=n && B=n) - * A && (B || C) -> !(A=n || (B=n && C=n)) - * - * Allocates and returns a new expression. - */ -struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) -{ - struct expr *e1, *e2; - - if (!e) { - e = expr_alloc_symbol(sym); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - } - switch (e->type) { - case E_AND: - e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); - e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); - if (sym == &symbol_yes) - e = expr_alloc_two(E_AND, e1, e2); - if (sym == &symbol_no) - e = expr_alloc_two(E_OR, e1, e2); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - case E_OR: - e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); - e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); - if (sym == &symbol_yes) - e = expr_alloc_two(E_OR, e1, e2); - if (sym == &symbol_no) - e = expr_alloc_two(E_AND, e1, e2); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - case E_NOT: - return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); - case E_UNEQUAL: - case E_LTH: - case E_LEQ: - case E_GTH: - case E_GEQ: - case E_EQUAL: - if (type == E_EQUAL) { - if (sym == &symbol_yes) - return expr_copy(e); - if (sym == &symbol_mod) - return expr_alloc_symbol(&symbol_no); - if (sym == &symbol_no) - return expr_alloc_one(E_NOT, expr_copy(e)); - } else { - if (sym == &symbol_yes) - return expr_alloc_one(E_NOT, expr_copy(e)); - if (sym == &symbol_mod) - return expr_alloc_symbol(&symbol_yes); - if (sym == &symbol_no) - return expr_copy(e); - } - break; - case E_SYMBOL: - return expr_alloc_comp(type, e->left.sym, sym); - case E_LIST: - case E_RANGE: - case E_NONE: - /* panic */; - } - return NULL; -} - -enum string_value_kind { - k_string, - k_signed, - k_unsigned, -}; - -union string_value { - unsigned long long u; - signed long long s; -}; - -static enum string_value_kind expr_parse_string(const char *str, - enum symbol_type type, - union string_value *val) -{ - char *tail; - enum string_value_kind kind; - - errno = 0; - switch (type) { - case S_BOOLEAN: - case S_TRISTATE: - val->s = !strcmp(str, "n") ? 0 : - !strcmp(str, "m") ? 1 : - !strcmp(str, "y") ? 2 : -1; - return k_signed; - case S_INT: - val->s = strtoll(str, &tail, 10); - kind = k_signed; - break; - case S_HEX: - val->u = strtoull(str, &tail, 16); - kind = k_unsigned; - break; - default: - val->s = strtoll(str, &tail, 0); - kind = k_signed; - break; - } - return !errno && !*tail && tail > str && isxdigit(tail[-1]) - ? kind : k_string; -} - -tristate expr_calc_value(struct expr *e) -{ - tristate val1, val2; - const char *str1, *str2; - enum string_value_kind k1 = k_string, k2 = k_string; - union string_value lval = {}, rval = {}; - int res; - - if (!e) - return yes; - - switch (e->type) { - case E_SYMBOL: - sym_calc_value(e->left.sym); - return e->left.sym->curr.tri; - case E_AND: - val1 = expr_calc_value(e->left.expr); - val2 = expr_calc_value(e->right.expr); - return EXPR_AND(val1, val2); - case E_OR: - val1 = expr_calc_value(e->left.expr); - val2 = expr_calc_value(e->right.expr); - return EXPR_OR(val1, val2); - case E_NOT: - val1 = expr_calc_value(e->left.expr); - return EXPR_NOT(val1); - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - break; - default: - printf("expr_calc_value: %d?\n", e->type); - return no; - } - - sym_calc_value(e->left.sym); - sym_calc_value(e->right.sym); - str1 = sym_get_string_value(e->left.sym); - str2 = sym_get_string_value(e->right.sym); - - if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) { - k1 = expr_parse_string(str1, e->left.sym->type, &lval); - k2 = expr_parse_string(str2, e->right.sym->type, &rval); - } - - if (k1 == k_string || k2 == k_string) - res = strcmp(str1, str2); - else if (k1 == k_unsigned || k2 == k_unsigned) - res = (lval.u > rval.u) - (lval.u < rval.u); - else /* if (k1 == k_signed && k2 == k_signed) */ - res = (lval.s > rval.s) - (lval.s < rval.s); - - switch(e->type) { - case E_EQUAL: - return res ? no : yes; - case E_GEQ: - return res >= 0 ? yes : no; - case E_GTH: - return res > 0 ? yes : no; - case E_LEQ: - return res <= 0 ? yes : no; - case E_LTH: - return res < 0 ? yes : no; - case E_UNEQUAL: - return res ? yes : no; - default: - printf("expr_calc_value: relation %d?\n", e->type); - return no; - } -} - -static int expr_compare_type(enum expr_type t1, enum expr_type t2) -{ - if (t1 == t2) - return 0; - switch (t1) { - case E_LEQ: - case E_LTH: - case E_GEQ: - case E_GTH: - if (t2 == E_EQUAL || t2 == E_UNEQUAL) - return 1; - case E_EQUAL: - case E_UNEQUAL: - if (t2 == E_NOT) - return 1; - case E_NOT: - if (t2 == E_AND) - return 1; - case E_AND: - if (t2 == E_OR) - return 1; - case E_OR: - if (t2 == E_LIST) - return 1; - case E_LIST: - if (t2 == 0) - return 1; - default: - return -1; - } - printf("[%dgt%d?]", t1, t2); - return 0; -} - -void expr_print(struct expr *e, - void (*fn)(void *, struct symbol *, const char *), - void *data, int prevtoken) -{ - if (!e) { - fn(data, NULL, "y"); - return; - } - - if (expr_compare_type(prevtoken, e->type) > 0) - fn(data, NULL, "("); - switch (e->type) { - case E_SYMBOL: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, "<choice>"); - break; - case E_NOT: - fn(data, NULL, "!"); - expr_print(e->left.expr, fn, data, E_NOT); - break; - case E_EQUAL: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, "<choice>"); - fn(data, NULL, "="); - fn(data, e->right.sym, e->right.sym->name); - break; - case E_LEQ: - case E_LTH: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, "<choice>"); - fn(data, NULL, e->type == E_LEQ ? "<=" : "<"); - fn(data, e->right.sym, e->right.sym->name); - break; - case E_GEQ: - case E_GTH: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, "<choice>"); - fn(data, NULL, e->type == E_GEQ ? ">=" : ">"); - fn(data, e->right.sym, e->right.sym->name); - break; - case E_UNEQUAL: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, "<choice>"); - fn(data, NULL, "!="); - fn(data, e->right.sym, e->right.sym->name); - break; - case E_OR: - expr_print(e->left.expr, fn, data, E_OR); - fn(data, NULL, " || "); - expr_print(e->right.expr, fn, data, E_OR); - break; - case E_AND: - expr_print(e->left.expr, fn, data, E_AND); - fn(data, NULL, " && "); - expr_print(e->right.expr, fn, data, E_AND); - break; - case E_LIST: - fn(data, e->right.sym, e->right.sym->name); - if (e->left.expr) { - fn(data, NULL, " ^ "); - expr_print(e->left.expr, fn, data, E_LIST); - } - break; - case E_RANGE: - fn(data, NULL, "["); - fn(data, e->left.sym, e->left.sym->name); - fn(data, NULL, " "); - fn(data, e->right.sym, e->right.sym->name); - fn(data, NULL, "]"); - break; - default: - { - char buf[32]; - sprintf(buf, "<unknown type %d>", e->type); - fn(data, NULL, buf); - break; - } - } - if (expr_compare_type(prevtoken, e->type) > 0) - fn(data, NULL, ")"); -} - -static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) -{ - xfwrite(str, strlen(str), 1, data); -} - -void expr_fprint(struct expr *e, FILE *out) -{ - expr_print(e, expr_print_file_helper, out, E_NONE); -} - -static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) -{ - struct gstr *gs = (struct gstr*)data; - const char *sym_str = NULL; - - if (sym) - sym_str = sym_get_string_value(sym); - - if (gs->max_width) { - unsigned extra_length = strlen(str); - const char *last_cr = strrchr(gs->s, '\n'); - unsigned last_line_length; - - if (sym_str) - extra_length += 4 + strlen(sym_str); - - if (!last_cr) - last_cr = gs->s; - - last_line_length = strlen(gs->s) - (last_cr - gs->s); - - if ((last_line_length + extra_length) > gs->max_width) - str_append(gs, "\\\n"); - } - - str_append(gs, str); - if (sym && sym->type != S_UNKNOWN) - str_printf(gs, " [=%s]", sym_str); -} - -void expr_gstr_print(struct expr *e, struct gstr *gs) -{ - expr_print(e, expr_print_gstr_helper, gs, E_NONE); -} - -/* - * Transform the top level "||" tokens into newlines and prepend each - * line with a minus. This makes expressions much easier to read. - * Suitable for reverse dependency expressions. - */ -static void expr_print_revdep(struct expr *e, - void (*fn)(void *, struct symbol *, const char *), - void *data, tristate pr_type, const char **title) -{ - if (e->type == E_OR) { - expr_print_revdep(e->left.expr, fn, data, pr_type, title); - expr_print_revdep(e->right.expr, fn, data, pr_type, title); - } else if (expr_calc_value(e) == pr_type) { - if (*title) { - fn(data, NULL, *title); - *title = NULL; - } - - fn(data, NULL, " - "); - expr_print(e, fn, data, E_NONE); - fn(data, NULL, "\n"); - } -} - -void expr_gstr_print_revdep(struct expr *e, struct gstr *gs, - tristate pr_type, const char *title) -{ - expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title); -} diff --git a/tools/kconfig/expr.h b/tools/kconfig/expr.h deleted file mode 100644 index 9c9caca..0000000 --- a/tools/kconfig/expr.h +++ /dev/null @@ -1,326 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ - -#ifndef EXPR_H -#define EXPR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <assert.h> -#include <stdio.h> -#include "list.h" -#ifndef __cplusplus -#include <stdbool.h> -#endif - -struct file { - struct file *next; - struct file *parent; - const char *name; - int lineno; -}; - -typedef enum tristate { - no, mod, yes -} tristate; - -enum expr_type { - E_NONE, E_OR, E_AND, E_NOT, - E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ, - E_LIST, E_SYMBOL, E_RANGE -}; - -union expr_data { - struct expr *expr; - struct symbol *sym; -}; - -struct expr { - enum expr_type type; - union expr_data left, right; -}; - -#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) -#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) -#define EXPR_NOT(dep) (2-(dep)) - -#define expr_list_for_each_sym(l, e, s) \ - for (e = (l); e && (s = e->right.sym); e = e->left.expr) - -struct expr_value { - struct expr *expr; - tristate tri; -}; - -struct symbol_value { - void *val; - tristate tri; -}; - -enum symbol_type { - S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING -}; - -/* enum values are used as index to symbol.def[] */ -enum { - S_DEF_USER, /* main user value */ - S_DEF_AUTO, /* values read from auto.conf */ - S_DEF_DEF3, /* Reserved for UI usage */ - S_DEF_DEF4, /* Reserved for UI usage */ - S_DEF_COUNT -}; - -/* - * Represents a configuration symbol. - * - * Choices are represented as a special kind of symbol and have the - * SYMBOL_CHOICE bit set in 'flags'. - */ -struct symbol { - /* The next symbol in the same bucket in the symbol hash table */ - struct symbol *next; - - /* The name of the symbol, e.g. "FOO" for 'config FOO' */ - char *name; - - /* S_BOOLEAN, S_TRISTATE, ... */ - enum symbol_type type; - - /* - * The calculated value of the symbol. The SYMBOL_VALID bit is set in - * 'flags' when this is up to date. Note that this value might differ - * from the user value set in e.g. a .config file, due to visibility. - */ - struct symbol_value curr; - - /* - * Values for the symbol provided from outside. def[S_DEF_USER] holds - * the .config value. - */ - struct symbol_value def[S_DEF_COUNT]; - - /* - * An upper bound on the tristate value the user can set for the symbol - * if it is a boolean or tristate. Calculated from prompt dependencies, - * which also inherit dependencies from enclosing menus, choices, and - * ifs. If 'n', the user value will be ignored. - * - * Symbols lacking prompts always have visibility 'n'. - */ - tristate visible; - - /* SYMBOL_* flags */ - int flags; - - /* List of properties. See prop_type. */ - struct property *prop; - - /* Dependencies from enclosing menus, choices, and ifs */ - struct expr_value dir_dep; - - /* Reverse dependencies through being selected by other symbols */ - struct expr_value rev_dep; - - /* - * "Weak" reverse dependencies through being implied by other symbols - */ - struct expr_value implied; -}; - -#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) - -#define SYMBOL_CONST 0x0001 /* symbol is const */ -#define SYMBOL_CHECK 0x0008 /* used during dependency checking */ -#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ -#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ -#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ -#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ -#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ -#define SYMBOL_CHANGED 0x0400 /* ? */ -#define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */ -#define SYMBOL_NO_WRITE 0x1000 /* Symbol for internal use only; it will not be written */ -#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ -#define SYMBOL_WARNED 0x8000 /* warning has been issued */ - -/* Set when symbol.def[] is used */ -#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ -#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ -#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ -#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ -#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ - -/* choice values need to be set before calculating this symbol value */ -#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 - -#define SYMBOL_MAXLENGTH 256 -#define SYMBOL_HASHSIZE 9973 - -/* A property represent the config options that can be associated - * with a config "symbol". - * Sample: - * config FOO - * default y - * prompt "foo prompt" - * select BAR - * config BAZ - * int "BAZ Value" - * range 1..255 - * - * Please, also check parser.y:print_symbol() when modifying the - * list of property types! - */ -enum prop_type { - P_UNKNOWN, - P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ - P_COMMENT, /* text associated with a comment */ - P_MENU, /* prompt associated with a menu or menuconfig symbol */ - P_DEFAULT, /* default y */ - P_CHOICE, /* choice value */ - P_SELECT, /* select BAR */ - P_IMPLY, /* imply BAR */ - P_RANGE, /* range 7..100 (for a symbol) */ - P_SYMBOL, /* where a symbol is defined */ -}; - -struct property { - struct property *next; /* next property - null if last */ - enum prop_type type; /* type of property */ - const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ - struct expr_value visible; - struct expr *expr; /* the optional conditional part of the property */ - struct menu *menu; /* the menu the property are associated with - * valid for: P_SELECT, P_RANGE, P_CHOICE, - * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ - struct file *file; /* what file was this property defined */ - int lineno; /* what lineno was this property defined */ -}; - -#define for_all_properties(sym, st, tok) \ - for (st = sym->prop; st; st = st->next) \ - if (st->type == (tok)) -#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) -#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) -#define for_all_prompts(sym, st) \ - for (st = sym->prop; st; st = st->next) \ - if (st->text) - -/* - * Represents a node in the menu tree, as seen in e.g. menuconfig (though used - * for all front ends). Each symbol, menu, etc. defined in the Kconfig files - * gets a node. A symbol defined in multiple locations gets one node at each - * location. - */ -struct menu { - /* The next menu node at the same level */ - struct menu *next; - - /* The parent menu node, corresponding to e.g. a menu or choice */ - struct menu *parent; - - /* The first child menu node, for e.g. menus and choices */ - struct menu *list; - - /* - * The symbol associated with the menu node. Choices are implemented as - * a special kind of symbol. NULL for menus, comments, and ifs. - */ - struct symbol *sym; - - /* - * The prompt associated with the node. This holds the prompt for a - * symbol as well as the text for a menu or comment, along with the - * type (P_PROMPT, P_MENU, etc.) - */ - struct property *prompt; - - /* - * 'visible if' dependencies. If more than one is given, they will be - * ANDed together. - */ - struct expr *visibility; - - /* - * Ordinary dependencies from e.g. 'depends on' and 'if', ANDed - * together - */ - struct expr *dep; - - /* MENU_* flags */ - unsigned int flags; - - /* Any help text associated with the node */ - char *help; - - /* The location where the menu node appears in the Kconfig files */ - struct file *file; - int lineno; - - /* For use by front ends that need to store auxiliary data */ - void *data; -}; - -/* - * Set on a menu node when the corresponding symbol changes state in some way. - * Can be checked by front ends. - */ -#define MENU_CHANGED 0x0001 - -#define MENU_ROOT 0x0002 - -struct jump_key { - struct list_head entries; - size_t offset; - struct menu *target; - int index; -}; - -extern struct file *file_list; -extern struct file *current_file; -struct file *lookup_file(const char *name); - -extern struct symbol symbol_yes, symbol_no, symbol_mod; -extern struct symbol *modules_sym; -extern int cdebug; -struct expr *expr_alloc_symbol(struct symbol *sym); -struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); -struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); -struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); -struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); -struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); -struct expr *expr_copy(const struct expr *org); -void expr_free(struct expr *e); -void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); -int expr_eq(struct expr *e1, struct expr *e2); -tristate expr_calc_value(struct expr *e); -struct expr *expr_trans_bool(struct expr *e); -struct expr *expr_eliminate_dups(struct expr *e); -struct expr *expr_transform(struct expr *e); -int expr_contains_symbol(struct expr *dep, struct symbol *sym); -bool expr_depends_symbol(struct expr *dep, struct symbol *sym); -struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); - -void expr_fprint(struct expr *e, FILE *out); -struct gstr; /* forward */ -void expr_gstr_print(struct expr *e, struct gstr *gs); -void expr_gstr_print_revdep(struct expr *e, struct gstr *gs, - tristate pr_type, const char *title); - -static inline int expr_is_yes(struct expr *e) -{ - return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); -} - -static inline int expr_is_no(struct expr *e) -{ - return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); -} - -#ifdef __cplusplus -} -#endif - -#endif /* EXPR_H */ diff --git a/tools/kconfig/internal.h b/tools/kconfig/internal.h deleted file mode 100644 index 2f7298c..0000000 --- a/tools/kconfig/internal.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef INTERNAL_H -#define INTERNAL_H - -struct menu; - -extern struct menu *current_menu, *current_entry; - -#endif /* INTERNAL_H */ diff --git a/tools/kconfig/lexer.l b/tools/kconfig/lexer.l deleted file mode 100644 index cc386e4..0000000 --- a/tools/kconfig/lexer.l +++ /dev/null @@ -1,468 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ -%option nostdinit noyywrap never-interactive full ecs -%option 8bit nodefault yylineno -%x ASSIGN_VAL HELP STRING -%{ - -#include <assert.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "lkc.h" -#include "parser.tab.h" - -#define YY_DECL static int yylex1(void) - -#define START_STRSIZE 16 - -static struct { - struct file *file; - int lineno; -} current_pos; - -static int prev_prev_token = T_EOL; -static int prev_token = T_EOL; -static char *text; -static int text_size, text_asize; - -struct buffer { - struct buffer *parent; - YY_BUFFER_STATE state; -}; - -static struct buffer *current_buf; - -static int last_ts, first_ts; - -static char *expand_token(const char *in, size_t n); -static void append_expanded_string(const char *in); -static void zconf_endhelp(void); -static void zconf_endfile(void); - -static void new_string(void) -{ - text = xmalloc(START_STRSIZE); - text_asize = START_STRSIZE; - text_size = 0; - *text = 0; -} - -static void append_string(const char *str, int size) -{ - int new_size = text_size + size + 1; - if (new_size > text_asize) { - new_size += START_STRSIZE - 1; - new_size &= -START_STRSIZE; - text = xrealloc(text, new_size); - text_asize = new_size; - } - memcpy(text + text_size, str, size); - text_size += size; - text[text_size] = 0; -} - -static void alloc_string(const char *str, int size) -{ - text = xmalloc(size + 1); - memcpy(text, str, size); - text[size] = 0; -} - -static void warn_ignored_character(char chr) -{ - fprintf(stderr, - "%s:%d:warning: ignoring unsupported character '%c'\n", - current_file->name, yylineno, chr); -} -%} - -n [A-Za-z0-9_-] - -%% - char open_quote = 0; - -#.* /* ignore comment */ -[ \t]* /* whitespaces */ -\\\n /* escaped new line */ -\n return T_EOL; -"bool" return T_BOOL; -"choice" return T_CHOICE; -"comment" return T_COMMENT; -"config" return T_CONFIG; -"def_bool" return T_DEF_BOOL; -"def_tristate" return T_DEF_TRISTATE; -"default" return T_DEFAULT; -"depends" return T_DEPENDS; -"endchoice" return T_ENDCHOICE; -"endif" return T_ENDIF; -"endmenu" return T_ENDMENU; -"help" return T_HELP; -"hex" return T_HEX; -"if" return T_IF; -"imply" return T_IMPLY; -"int" return T_INT; -"mainmenu" return T_MAINMENU; -"menu" return T_MENU; -"menuconfig" return T_MENUCONFIG; -"modules" return T_MODULES; -"on" return T_ON; -"optional" return T_OPTIONAL; -"prompt" return T_PROMPT; -"range" return T_RANGE; -"select" return T_SELECT; -"source" return T_SOURCE; -"string" return T_STRING; -"tristate" return T_TRISTATE; -"visible" return T_VISIBLE; -"||" return T_OR; -"&&" return T_AND; -"=" return T_EQUAL; -"!=" return T_UNEQUAL; -"<" return T_LESS; -"<=" return T_LESS_EQUAL; -">" return T_GREATER; -">=" return T_GREATER_EQUAL; -"!" return T_NOT; -"(" return T_OPEN_PAREN; -")" return T_CLOSE_PAREN; -":=" return T_COLON_EQUAL; -"+=" return T_PLUS_EQUAL; -\"|\' { - open_quote = yytext[0]; - new_string(); - BEGIN(STRING); - } -{n}+ { - alloc_string(yytext, yyleng); - yylval.string = text; - return T_WORD; - } -({n}|$)+ { - /* this token includes at least one '$' */ - yylval.string = expand_token(yytext, yyleng); - if (strlen(yylval.string)) - return T_WORD; - free(yylval.string); - } -. warn_ignored_character(*yytext); - -<ASSIGN_VAL>{ - [^[:blank:]\n]+.* { - alloc_string(yytext, yyleng); - yylval.string = text; - return T_ASSIGN_VAL; - } - \n { BEGIN(INITIAL); return T_EOL; } - . -} - -<STRING>{ - "$".* append_expanded_string(yytext); - [^$'"\\\n]+ { - append_string(yytext, yyleng); - } - \\.? { - append_string(yytext + 1, yyleng - 1); - } - \'|\" { - if (open_quote == yytext[0]) { - BEGIN(INITIAL); - yylval.string = text; - return T_WORD_QUOTE; - } else - append_string(yytext, 1); - } - \n { - fprintf(stderr, - "%s:%d:warning: multi-line strings not supported\n", - zconf_curname(), zconf_lineno()); - unput('\n'); - BEGIN(INITIAL); - yylval.string = text; - return T_WORD_QUOTE; - } - <<EOF>> { - BEGIN(INITIAL); - yylval.string = text; - return T_WORD_QUOTE; - } -} - -<HELP>{ - [ \t]+ { - int ts, i; - - ts = 0; - for (i = 0; i < yyleng; i++) { - if (yytext[i] == '\t') - ts = (ts & ~7) + 8; - else - ts++; - } - last_ts = ts; - if (first_ts) { - if (ts < first_ts) { - zconf_endhelp(); - return T_HELPTEXT; - } - ts -= first_ts; - while (ts > 8) { - append_string(" ", 8); - ts -= 8; - } - append_string(" ", ts); - } - } - [ \t]*\n/[^ \t\n] { - zconf_endhelp(); - return T_HELPTEXT; - } - [ \t]*\n { - append_string("\n", 1); - } - [^ \t\n].* { - while (yyleng) { - if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) - break; - yyleng--; - } - append_string(yytext, yyleng); - if (!first_ts) - first_ts = last_ts; - } - <<EOF>> { - zconf_endhelp(); - return T_HELPTEXT; - } -} - -<<EOF>> { - BEGIN(INITIAL); - - if (prev_token != T_EOL && prev_token != T_HELPTEXT) - fprintf(stderr, "%s:%d:warning: no new line at end of file\n", - current_file->name, yylineno); - - if (current_file) { - zconf_endfile(); - return T_EOL; - } - fclose(yyin); - yyterminate(); -} - -%% - -/* second stage lexer */ -int yylex(void) -{ - int token; - -repeat: - token = yylex1(); - - if (prev_token == T_EOL || prev_token == T_HELPTEXT) { - if (token == T_EOL) { - /* Do not pass unneeded T_EOL to the parser. */ - goto repeat; - } else { - /* - * For the parser, update file/lineno at the first token - * of each statement. Generally, \n is a statement - * terminator in Kconfig, but it is not always true - * because \n could be escaped by a backslash. - */ - current_pos.file = current_file; - current_pos.lineno = yylineno; - } - } - - if (prev_prev_token == T_EOL && prev_token == T_WORD && - (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL)) - BEGIN(ASSIGN_VAL); - - prev_prev_token = prev_token; - prev_token = token; - - return token; -} - -static char *expand_token(const char *in, size_t n) -{ - char *out; - int c; - char c2; - const char *rest, *end; - - new_string(); - append_string(in, n); - - /* get the whole line because we do not know the end of token. */ - while ((c = input()) != EOF) { - if (c == '\n') { - unput(c); - break; - } - c2 = c; - append_string(&c2, 1); - } - - rest = text; - out = expand_one_token(&rest); - - /* push back unused characters to the input stream */ - end = rest + strlen(rest); - while (end > rest) - unput(*--end); - - free(text); - - return out; -} - -static void append_expanded_string(const char *str) -{ - const char *end; - char *res; - - str++; - - res = expand_dollar(&str); - - /* push back unused characters to the input stream */ - end = str + strlen(str); - while (end > str) - unput(*--end); - - append_string(res, strlen(res)); - - free(res); -} - -void zconf_starthelp(void) -{ - new_string(); - last_ts = first_ts = 0; - BEGIN(HELP); -} - -static void zconf_endhelp(void) -{ - yylval.string = text; - BEGIN(INITIAL); -} - - -/* - * Try to open specified file with following names: - * ./name - * $(srctree)/name - * The latter is used when srctree is separate from objtree - * when compiling the kernel. - * Return NULL if file is not found. - */ -FILE *zconf_fopen(const char *name) -{ - char *env, fullname[PATH_MAX+1]; - FILE *f; - - f = fopen(name, "r"); - if (!f && name != NULL && name[0] != '/') { - env = getenv(SRCTREE); - if (env) { - snprintf(fullname, sizeof(fullname), - "%s/%s", env, name); - f = fopen(fullname, "r"); - } - } - return f; -} - -void zconf_initscan(const char *name) -{ - yyin = zconf_fopen(name); - if (!yyin) { - fprintf(stderr, "can't find file %s\n", name); - exit(1); - } - - current_buf = xmalloc(sizeof(*current_buf)); - memset(current_buf, 0, sizeof(*current_buf)); - - current_file = file_lookup(name); - yylineno = 1; -} - -void zconf_nextfile(const char *name) -{ - struct file *iter; - struct file *file = file_lookup(name); - struct buffer *buf = xmalloc(sizeof(*buf)); - memset(buf, 0, sizeof(*buf)); - - current_buf->state = YY_CURRENT_BUFFER; - yyin = zconf_fopen(file->name); - if (!yyin) { - fprintf(stderr, "%s:%d: can't open file \"%s\"\n", - zconf_curname(), zconf_lineno(), file->name); - exit(1); - } - yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); - buf->parent = current_buf; - current_buf = buf; - - current_file->lineno = yylineno; - file->parent = current_file; - - for (iter = current_file; iter; iter = iter->parent) { - if (!strcmp(iter->name, file->name)) { - fprintf(stderr, - "Recursive inclusion detected.\n" - "Inclusion path:\n" - " current file : %s\n", file->name); - iter = file; - do { - iter = iter->parent; - fprintf(stderr, " included from: %s:%d\n", - iter->name, iter->lineno - 1); - } while (strcmp(iter->name, file->name)); - exit(1); - } - } - - yylineno = 1; - current_file = file; -} - -static void zconf_endfile(void) -{ - struct buffer *parent; - - current_file = current_file->parent; - if (current_file) - yylineno = current_file->lineno; - - parent = current_buf->parent; - if (parent) { - fclose(yyin); - yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(parent->state); - } - free(current_buf); - current_buf = parent; -} - -int zconf_lineno(void) -{ - return current_pos.lineno; -} - -const char *zconf_curname(void) -{ - return current_pos.file ? current_pos.file->name : "<none>"; -} diff --git a/tools/kconfig/list.h b/tools/kconfig/list.h deleted file mode 100644 index 45cb237..0000000 --- a/tools/kconfig/list.h +++ /dev/null @@ -1,132 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef LIST_H -#define LIST_H - -/* - * Copied from include/linux/... - */ - -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - - -struct list_head { - struct list_head *next, *prev; -}; - - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *_new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = _new; - _new->next = next; - _new->prev = prev; - prev->next = _new; -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *_new, struct list_head *head) -{ - __list_add(_new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head *prev, struct list_head *next) -{ - next->prev = prev; - prev->next = next; -} - -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = (struct list_head*)LIST_POISON1; - entry->prev = (struct list_head*)LIST_POISON2; -} -#endif diff --git a/tools/kconfig/lkc.h b/tools/kconfig/lkc.h deleted file mode 100644 index e7118d6..0000000 --- a/tools/kconfig/lkc.h +++ /dev/null @@ -1,150 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ - -#ifndef LKC_H -#define LKC_H - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> - -#include "expr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include "lkc_proto.h" - -#define SRCTREE "srctree" - -#ifndef CONFIG_ -#define CONFIG_ "CONFIG_" -#endif -static inline const char *CONFIG_prefix(void) -{ - return getenv( "CONFIG_" ) ?: CONFIG_; -} -#undef CONFIG_ -#define CONFIG_ CONFIG_prefix() - -extern int yylineno; -void zconfdump(FILE *out); -void zconf_starthelp(void); -FILE *zconf_fopen(const char *name); -void zconf_initscan(const char *name); -void zconf_nextfile(const char *name); -int zconf_lineno(void); -const char *zconf_curname(void); - -/* confdata.c */ -const char *conf_get_configname(void); -void set_all_choice_values(struct symbol *csym); - -/* confdata.c and expr.c */ -static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) -{ - assert(len != 0); - - if (fwrite(str, len, count, out) != count) - fprintf(stderr, "Error in writing or end of file.\n"); -} - -/* util.c */ -struct file *file_lookup(const char *name); -void *xmalloc(size_t size); -void *xcalloc(size_t nmemb, size_t size); -void *xrealloc(void *p, size_t size); -char *xstrdup(const char *s); -char *xstrndup(const char *s, size_t n); - -/* lexer.l */ -int yylex(void); - -struct gstr { - size_t len; - char *s; - /* - * when max_width is not zero long lines in string s (if any) get - * wrapped not to exceed the max_width value - */ - int max_width; -}; -struct gstr str_new(void); -void str_free(struct gstr *gs); -void str_append(struct gstr *gs, const char *s); -void str_printf(struct gstr *gs, const char *fmt, ...); -char *str_get(struct gstr *gs); - -/* menu.c */ -void _menu_init(void); -void menu_warn(struct menu *menu, const char *fmt, ...); -struct menu *menu_add_menu(void); -void menu_end_menu(void); -void menu_add_entry(struct symbol *sym); -void menu_add_dep(struct expr *dep); -void menu_add_visibility(struct expr *dep); -struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); -void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); -void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); -void menu_finalize(struct menu *parent); -void menu_set_type(int type); - -extern struct menu rootmenu; - -bool menu_is_empty(struct menu *menu); -bool menu_is_visible(struct menu *menu); -bool menu_has_prompt(struct menu *menu); -const char *menu_get_prompt(struct menu *menu); -struct menu *menu_get_parent_menu(struct menu *menu); -bool menu_has_help(struct menu *menu); -const char *menu_get_help(struct menu *menu); -struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); -void menu_get_ext_help(struct menu *menu, struct gstr *help); - -/* symbol.c */ -void sym_clear_all_valid(void); -struct symbol *sym_choice_default(struct symbol *sym); -struct property *sym_get_range_prop(struct symbol *sym); -const char *sym_get_string_default(struct symbol *sym); -struct symbol *sym_check_deps(struct symbol *sym); -struct symbol *prop_get_symbol(struct property *prop); - -static inline tristate sym_get_tristate_value(struct symbol *sym) -{ - return sym->curr.tri; -} - - -static inline struct symbol *sym_get_choice_value(struct symbol *sym) -{ - return (struct symbol *)sym->curr.val; -} - -static inline bool sym_is_choice(struct symbol *sym) -{ - return sym->flags & SYMBOL_CHOICE ? true : false; -} - -static inline bool sym_is_choice_value(struct symbol *sym) -{ - return sym->flags & SYMBOL_CHOICEVAL ? true : false; -} - -static inline bool sym_is_optional(struct symbol *sym) -{ - return sym->flags & SYMBOL_OPTIONAL ? true : false; -} - -static inline bool sym_has_value(struct symbol *sym) -{ - return sym->flags & SYMBOL_DEF_USER ? true : false; -} - -#ifdef __cplusplus -} -#endif - -#endif /* LKC_H */ diff --git a/tools/kconfig/lkc_proto.h b/tools/kconfig/lkc_proto.h deleted file mode 100644 index edd1e61..0000000 --- a/tools/kconfig/lkc_proto.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include <stdarg.h> - -/* confdata.c */ -void conf_parse(const char *name); -int conf_read(const char *name); -int conf_read_simple(const char *name, int); -int conf_write_defconfig(const char *name); -int conf_write(const char *name); -int conf_write_autoconf(int overwrite); -void conf_set_changed(bool val); -bool conf_get_changed(void); -void conf_set_changed_callback(void (*fn)(void)); -void conf_set_message_callback(void (*fn)(const char *s)); - -/* symbol.c */ -extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; - -struct symbol * sym_lookup(const char *name, int flags); -struct symbol * sym_find(const char *name); -void print_symbol_for_listconfig(struct symbol *sym); -struct symbol ** sym_re_search(const char *pattern); -const char * sym_type_name(enum symbol_type type); -void sym_calc_value(struct symbol *sym); -enum symbol_type sym_get_type(struct symbol *sym); -bool sym_tristate_within_range(struct symbol *sym,tristate tri); -bool sym_set_tristate_value(struct symbol *sym,tristate tri); -tristate sym_toggle_tristate_value(struct symbol *sym); -bool sym_string_valid(struct symbol *sym, const char *newval); -bool sym_string_within_range(struct symbol *sym, const char *str); -bool sym_set_string_value(struct symbol *sym, const char *newval); -bool sym_is_changeable(struct symbol *sym); -struct property * sym_get_choice_prop(struct symbol *sym); -const char * sym_get_string_value(struct symbol *sym); - -const char * prop_get_type_name(enum prop_type type); - -/* preprocess.c */ -enum variable_flavor { - VAR_SIMPLE, - VAR_RECURSIVE, - VAR_APPEND, -}; -void env_write_dep(FILE *f, const char *auto_conf_name); -void variable_add(const char *name, const char *value, - enum variable_flavor flavor); -void variable_all_del(void); -char *expand_dollar(const char **str); -char *expand_one_token(const char **str); - -/* expr.c */ -void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); diff --git a/tools/kconfig/lxdialog/BIG.FAT.WARNING b/tools/kconfig/lxdialog/BIG.FAT.WARNING deleted file mode 100644 index 7cb5a7e..0000000 --- a/tools/kconfig/lxdialog/BIG.FAT.WARNING +++ /dev/null @@ -1,4 +0,0 @@ -This is NOT the official version of dialog. This version has been -significantly modified from the original. It is for use by the Linux -kernel configuration script. Please do not bother Savio Lam with -questions about this program. diff --git a/tools/kconfig/lxdialog/checklist.c b/tools/kconfig/lxdialog/checklist.c deleted file mode 100644 index fd161cf..0000000 --- a/tools/kconfig/lxdialog/checklist.c +++ /dev/null @@ -1,319 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * checklist.c -- implements the checklist box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension - * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - */ - -#include "dialog.h" - -static int list_width, check_x, item_x; - -/* - * Print list item - */ -static void print_item(WINDOW * win, int choice, int selected) -{ - int i; - char *list_item = malloc(list_width + 1); - - strncpy(list_item, item_str(), list_width - item_x); - list_item[list_width - item_x] = '\0'; - - /* Clear 'residue' of last item */ - wattrset(win, dlg.menubox.atr); - wmove(win, choice, 0); - for (i = 0; i < list_width; i++) - waddch(win, ' '); - - wmove(win, choice, check_x); - wattrset(win, selected ? dlg.check_selected.atr - : dlg.check.atr); - if (!item_is_tag(':')) - wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' '); - - wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr); - mvwaddch(win, choice, item_x, list_item[0]); - wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); - waddstr(win, list_item + 1); - if (selected) { - wmove(win, choice, check_x + 1); - wrefresh(win); - } - free(list_item); -} - -/* - * Print the scroll indicators. - */ -static void print_arrows(WINDOW * win, int choice, int item_no, int scroll, - int y, int x, int height) -{ - wmove(win, y, x); - - if (scroll > 0) { - wattrset(win, dlg.uarrow.atr); - waddch(win, ACS_UARROW); - waddstr(win, "(-)"); - } else { - wattrset(win, dlg.menubox.atr); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - } - - y = y + height + 1; - wmove(win, y, x); - - if ((height < item_no) && (scroll + choice < item_no - 1)) { - wattrset(win, dlg.darrow.atr); - waddch(win, ACS_DARROW); - waddstr(win, "(+)"); - } else { - wattrset(win, dlg.menubox_border.atr); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - } -} - -/* - * Display the termination buttons - */ -static void print_buttons(WINDOW * dialog, int height, int width, int selected) -{ - int x = width / 2 - 11; - int y = height - 2; - - print_button(dialog, "Select", y, x, selected == 0); - print_button(dialog, " Help ", y, x + 14, selected == 1); - - wmove(dialog, y, x + 1 + 14 * selected); - wrefresh(dialog); -} - -/* - * Display a dialog box with a list of options that can be turned on or off - * in the style of radiolist (only one option turned on at a time). - */ -int dialog_checklist(const char *title, const char *prompt, int height, - int width, int list_height) -{ - int i, x, y, box_x, box_y; - int key = 0, button = 0, choice = 0, scroll = 0, max_choice; - WINDOW *dialog, *list; - - /* which item to highlight */ - item_foreach() { - if (item_is_tag('X')) - choice = item_n(); - if (item_is_selected()) { - choice = item_n(); - break; - } - } - -do_resize: - if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN)) - return -ERRDISPLAYTOOSMALL; - if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN)) - return -ERRDISPLAYTOOSMALL; - - max_choice = MIN(list_height, item_count()); - - /* center dialog box on screen */ - x = (getmaxx(stdscr) - width) / 2; - y = (getmaxy(stdscr) - height) / 2; - - draw_shadow(stdscr, y, x, height, width); - - dialog = newwin(height, width, y, x); - keypad(dialog, TRUE); - - draw_box(dialog, 0, 0, height, width, - dlg.dialog.atr, dlg.border.atr); - wattrset(dialog, dlg.border.atr); - mvwaddch(dialog, height - 3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch(dialog, ACS_HLINE); - wattrset(dialog, dlg.dialog.atr); - waddch(dialog, ACS_RTEE); - - print_title(dialog, title, width); - - wattrset(dialog, dlg.dialog.atr); - print_autowrap(dialog, prompt, width - 2, 1, 3); - - list_width = width - 6; - box_y = height - list_height - 5; - box_x = (width - list_width) / 2 - 1; - - /* create new window for the list */ - list = subwin(dialog, list_height, list_width, y + box_y + 1, - x + box_x + 1); - - keypad(list, TRUE); - - /* draw a box around the list items */ - draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, - dlg.menubox_border.atr, dlg.menubox.atr); - - /* Find length of longest item in order to center checklist */ - check_x = 0; - item_foreach() - check_x = MAX(check_x, strlen(item_str()) + 4); - check_x = MIN(check_x, list_width); - - check_x = (list_width - check_x) / 2; - item_x = check_x + 4; - - if (choice >= list_height) { - scroll = choice - list_height + 1; - choice -= scroll; - } - - /* Print the list */ - for (i = 0; i < max_choice; i++) { - item_set(scroll + i); - print_item(list, i, i == choice); - } - - print_arrows(dialog, choice, item_count(), scroll, - box_y, box_x + check_x + 5, list_height); - - print_buttons(dialog, height, width, 0); - - wnoutrefresh(dialog); - wnoutrefresh(list); - doupdate(); - - while (key != KEY_ESC) { - key = wgetch(dialog); - - for (i = 0; i < max_choice; i++) { - item_set(i + scroll); - if (toupper(key) == toupper(item_str()[0])) - break; - } - - if (i < max_choice || key == KEY_UP || key == KEY_DOWN || - key == '+' || key == '-') { - if (key == KEY_UP || key == '-') { - if (!choice) { - if (!scroll) - continue; - /* Scroll list down */ - if (list_height > 1) { - /* De-highlight current first item */ - item_set(scroll); - print_item(list, 0, FALSE); - scrollok(list, TRUE); - wscrl(list, -1); - scrollok(list, FALSE); - } - scroll--; - item_set(scroll); - print_item(list, 0, TRUE); - print_arrows(dialog, choice, item_count(), - scroll, box_y, box_x + check_x + 5, list_height); - - wnoutrefresh(dialog); - wrefresh(list); - - continue; /* wait for another key press */ - } else - i = choice - 1; - } else if (key == KEY_DOWN || key == '+') { - if (choice == max_choice - 1) { - if (scroll + choice >= item_count() - 1) - continue; - /* Scroll list up */ - if (list_height > 1) { - /* De-highlight current last item before scrolling up */ - item_set(scroll + max_choice - 1); - print_item(list, - max_choice - 1, - FALSE); - scrollok(list, TRUE); - wscrl(list, 1); - scrollok(list, FALSE); - } - scroll++; - item_set(scroll + max_choice - 1); - print_item(list, max_choice - 1, TRUE); - - print_arrows(dialog, choice, item_count(), - scroll, box_y, box_x + check_x + 5, list_height); - - wnoutrefresh(dialog); - wrefresh(list); - - continue; /* wait for another key press */ - } else - i = choice + 1; - } - if (i != choice) { - /* De-highlight current item */ - item_set(scroll + choice); - print_item(list, choice, FALSE); - /* Highlight new item */ - choice = i; - item_set(scroll + choice); - print_item(list, choice, TRUE); - wnoutrefresh(dialog); - wrefresh(list); - } - continue; /* wait for another key press */ - } - switch (key) { - case 'H': - case 'h': - case '?': - button = 1; - /* fall-through */ - case 'S': - case 's': - case ' ': - case '\n': - item_foreach() - item_set_selected(0); - item_set(scroll + choice); - item_set_selected(1); - delwin(list); - delwin(dialog); - return button; - case TAB: - case KEY_LEFT: - case KEY_RIGHT: - button = ((key == KEY_LEFT ? --button : ++button) < 0) - ? 1 : (button > 1 ? 0 : button); - - print_buttons(dialog, height, width, button); - wrefresh(dialog); - break; - case 'X': - case 'x': - key = KEY_ESC; - break; - case KEY_ESC: - key = on_key_esc(dialog); - break; - case KEY_RESIZE: - delwin(list); - delwin(dialog); - on_key_resize(); - goto do_resize; - } - - /* Now, update everything... */ - doupdate(); - } - delwin(list); - delwin(dialog); - return key; /* ESC pressed */ -} diff --git a/tools/kconfig/lxdialog/dialog.h b/tools/kconfig/lxdialog/dialog.h deleted file mode 100644 index 68b565e..0000000 --- a/tools/kconfig/lxdialog/dialog.h +++ /dev/null @@ -1,238 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * dialog.h -- common declarations for all dialog modules - * - * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - */ - -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> - -#ifdef __sun__ -#define CURS_MACROS -#endif -#include <ncurses.h> - -/* - * Colors in ncurses 1.9.9e do not work properly since foreground and - * background colors are OR'd rather than separately masked. This version - * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible - * with standard curses. The simplest fix (to make this work with standard - * curses) uses the wbkgdset() function, not used in the original hack. - * Turn it off if we're building with 1.9.9e, since it just confuses things. - */ -#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE) -#define OLD_NCURSES 1 -#undef wbkgdset -#define wbkgdset(w,p) /*nothing */ -#else -#define OLD_NCURSES 0 -#endif - -#define TR(params) _tracef params - -#define KEY_ESC 27 -#define TAB 9 -#define MAX_LEN 2048 -#define BUF_SIZE (10*1024) -#define MIN(x,y) (x < y ? x : y) -#define MAX(x,y) (x > y ? x : y) - -#ifndef ACS_ULCORNER -#define ACS_ULCORNER '+' -#endif -#ifndef ACS_LLCORNER -#define ACS_LLCORNER '+' -#endif -#ifndef ACS_URCORNER -#define ACS_URCORNER '+' -#endif -#ifndef ACS_LRCORNER -#define ACS_LRCORNER '+' -#endif -#ifndef ACS_HLINE -#define ACS_HLINE '-' -#endif -#ifndef ACS_VLINE -#define ACS_VLINE '|' -#endif -#ifndef ACS_LTEE -#define ACS_LTEE '+' -#endif -#ifndef ACS_RTEE -#define ACS_RTEE '+' -#endif -#ifndef ACS_UARROW -#define ACS_UARROW '^' -#endif -#ifndef ACS_DARROW -#define ACS_DARROW 'v' -#endif - -/* error return codes */ -#define ERRDISPLAYTOOSMALL (KEY_MAX + 1) - -/* - * Color definitions - */ -struct dialog_color { - chtype atr; /* Color attribute */ - int fg; /* foreground */ - int bg; /* background */ - int hl; /* highlight this item */ -}; - -struct subtitle_list { - struct subtitle_list *next; - const char *text; -}; - -struct dialog_info { - const char *backtitle; - struct subtitle_list *subtitles; - struct dialog_color screen; - struct dialog_color shadow; - struct dialog_color dialog; - struct dialog_color title; - struct dialog_color border; - struct dialog_color button_active; - struct dialog_color button_inactive; - struct dialog_color button_key_active; - struct dialog_color button_key_inactive; - struct dialog_color button_label_active; - struct dialog_color button_label_inactive; - struct dialog_color inputbox; - struct dialog_color inputbox_border; - struct dialog_color searchbox; - struct dialog_color searchbox_title; - struct dialog_color searchbox_border; - struct dialog_color position_indicator; - struct dialog_color menubox; - struct dialog_color menubox_border; - struct dialog_color item; - struct dialog_color item_selected; - struct dialog_color tag; - struct dialog_color tag_selected; - struct dialog_color tag_key; - struct dialog_color tag_key_selected; - struct dialog_color check; - struct dialog_color check_selected; - struct dialog_color uarrow; - struct dialog_color darrow; -}; - -/* - * Global variables - */ -extern struct dialog_info dlg; -extern char dialog_input_result[]; -extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */ - -/* - * Function prototypes - */ - -/* item list as used by checklist and menubox */ -void item_reset(void); -void item_make(const char *fmt, ...); -void item_add_str(const char *fmt, ...); -void item_set_tag(char tag); -void item_set_data(void *p); -void item_set_selected(int val); -int item_activate_selected(void); -void *item_data(void); -char item_tag(void); - -/* item list manipulation for lxdialog use */ -#define MAXITEMSTR 200 -struct dialog_item { - char str[MAXITEMSTR]; /* prompt displayed */ - char tag; - void *data; /* pointer to menu item - used by menubox+checklist */ - int selected; /* Set to 1 by dialog_*() function if selected. */ -}; - -/* list of lialog_items */ -struct dialog_list { - struct dialog_item node; - struct dialog_list *next; -}; - -extern struct dialog_list *item_cur; -extern struct dialog_list item_nil; -extern struct dialog_list *item_head; - -int item_count(void); -void item_set(int n); -int item_n(void); -const char *item_str(void); -int item_is_selected(void); -int item_is_tag(char tag); -#define item_foreach() \ - for (item_cur = item_head ? item_head: item_cur; \ - item_cur && (item_cur != &item_nil); item_cur = item_cur->next) - -/* generic key handlers */ -int on_key_esc(WINDOW *win); -int on_key_resize(void); - -/* minimum (re)size values */ -#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */ -#define CHECKLIST_WIDTH_MIN 6 -#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */ -#define INPUTBOX_WIDTH_MIN 2 -#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */ -#define MENUBOX_WIDTH_MIN 65 -#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */ -#define TEXTBOX_WIDTH_MIN 8 -#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */ -#define YESNO_WIDTH_MIN 4 -#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */ -#define WINDOW_WIDTH_MIN 80 - -int init_dialog(const char *backtitle); -void set_dialog_backtitle(const char *backtitle); -void set_dialog_subtitles(struct subtitle_list *subtitles); -void end_dialog(int x, int y); -void attr_clear(WINDOW * win, int height, int width, chtype attr); -void dialog_clear(void); -void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x); -void print_button(WINDOW * win, const char *label, int y, int x, int selected); -void print_title(WINDOW *dialog, const char *title, int width); -void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box, - chtype border); -void draw_shadow(WINDOW * win, int y, int x, int height, int width); - -int first_alpha(const char *string, const char *exempt); -int dialog_yesno(const char *title, const char *prompt, int height, int width); -int dialog_msgbox(const char *title, const char *prompt, int height, - int width, int pause); - - -typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void - *_data); -int dialog_textbox(const char *title, char *tbuf, int initial_height, - int initial_width, int *keys, int *_vscroll, int *_hscroll, - update_text_fn update_text, void *data); -int dialog_menu(const char *title, const char *prompt, - const void *selected, int *s_scroll); -int dialog_checklist(const char *title, const char *prompt, int height, - int width, int list_height); -int dialog_inputbox(const char *title, const char *prompt, int height, - int width, const char *init); - -/* - * This is the base for fictitious keys, which activate - * the buttons. - * - * Mouse-generated keys are the following: - * -- the first 32 are used as numbers, in addition to '0'-'9' - * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o') - * -- uppercase chars are used to invoke the button (M_EVENT + 'O') - */ -#define M_EVENT (KEY_MAX+1) diff --git a/tools/kconfig/lxdialog/inputbox.c b/tools/kconfig/lxdialog/inputbox.c deleted file mode 100644 index 1dcfb28..0000000 --- a/tools/kconfig/lxdialog/inputbox.c +++ /dev/null @@ -1,289 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * inputbox.c -- implements the input box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - */ - -#include "dialog.h" - -char dialog_input_result[MAX_LEN + 1]; - -/* - * Print the termination buttons - */ -static void print_buttons(WINDOW * dialog, int height, int width, int selected) -{ - int x = width / 2 - 11; - int y = height - 2; - - print_button(dialog, " Ok ", y, x, selected == 0); - print_button(dialog, " Help ", y, x + 14, selected == 1); - - wmove(dialog, y, x + 1 + 14 * selected); - wrefresh(dialog); -} - -/* - * Display a dialog box for inputing a string - */ -int dialog_inputbox(const char *title, const char *prompt, int height, int width, - const char *init) -{ - int i, x, y, box_y, box_x, box_width; - int input_x = 0, key = 0, button = -1; - int show_x, len, pos; - char *instr = dialog_input_result; - WINDOW *dialog; - - if (!init) - instr[0] = '\0'; - else - strcpy(instr, init); - -do_resize: - if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN)) - return -ERRDISPLAYTOOSMALL; - if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN)) - return -ERRDISPLAYTOOSMALL; - - /* center dialog box on screen */ - x = (getmaxx(stdscr) - width) / 2; - y = (getmaxy(stdscr) - height) / 2; - - draw_shadow(stdscr, y, x, height, width); - - dialog = newwin(height, width, y, x); - keypad(dialog, TRUE); - - draw_box(dialog, 0, 0, height, width, - dlg.dialog.atr, dlg.border.atr); - wattrset(dialog, dlg.border.atr); - mvwaddch(dialog, height - 3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch(dialog, ACS_HLINE); - wattrset(dialog, dlg.dialog.atr); - waddch(dialog, ACS_RTEE); - - print_title(dialog, title, width); - - wattrset(dialog, dlg.dialog.atr); - print_autowrap(dialog, prompt, width - 2, 1, 3); - - /* Draw the input field box */ - box_width = width - 6; - getyx(dialog, y, x); - box_y = y + 2; - box_x = (width - box_width) / 2; - draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, - dlg.dialog.atr, dlg.border.atr); - - print_buttons(dialog, height, width, 0); - - /* Set up the initial value */ - wmove(dialog, box_y, box_x); - wattrset(dialog, dlg.inputbox.atr); - - len = strlen(instr); - pos = len; - - if (len >= box_width) { - show_x = len - box_width + 1; - input_x = box_width - 1; - for (i = 0; i < box_width - 1; i++) - waddch(dialog, instr[show_x + i]); - } else { - show_x = 0; - input_x = len; - waddstr(dialog, instr); - } - - wmove(dialog, box_y, box_x + input_x); - - wrefresh(dialog); - - while (key != KEY_ESC) { - key = wgetch(dialog); - - if (button == -1) { /* Input box selected */ - switch (key) { - case TAB: - case KEY_UP: - case KEY_DOWN: - break; - case KEY_BACKSPACE: - case 8: /* ^H */ - case 127: /* ^? */ - if (pos) { - wattrset(dialog, dlg.inputbox.atr); - if (input_x == 0) { - show_x--; - } else - input_x--; - - if (pos < len) { - for (i = pos - 1; i < len; i++) { - instr[i] = instr[i+1]; - } - } - - pos--; - len--; - instr[len] = '\0'; - wmove(dialog, box_y, box_x); - for (i = 0; i < box_width; i++) { - if (!instr[show_x + i]) { - waddch(dialog, ' '); - break; - } - waddch(dialog, instr[show_x + i]); - } - wmove(dialog, box_y, input_x + box_x); - wrefresh(dialog); - } - continue; - case KEY_LEFT: - if (pos > 0) { - if (input_x > 0) { - wmove(dialog, box_y, --input_x + box_x); - } else if (input_x == 0) { - show_x--; - wmove(dialog, box_y, box_x); - for (i = 0; i < box_width; i++) { - if (!instr[show_x + i]) { - waddch(dialog, ' '); - break; - } - waddch(dialog, instr[show_x + i]); - } - wmove(dialog, box_y, box_x); - } - pos--; - } - continue; - case KEY_RIGHT: - if (pos < len) { - if (input_x < box_width - 1) { - wmove(dialog, box_y, ++input_x + box_x); - } else if (input_x == box_width - 1) { - show_x++; - wmove(dialog, box_y, box_x); - for (i = 0; i < box_width; i++) { - if (!instr[show_x + i]) { - waddch(dialog, ' '); - break; - } - waddch(dialog, instr[show_x + i]); - } - wmove(dialog, box_y, input_x + box_x); - } - pos++; - } - continue; - default: - if (key < 0x100 && isprint(key)) { - if (len < MAX_LEN) { - wattrset(dialog, dlg.inputbox.atr); - if (pos < len) { - for (i = len; i > pos; i--) - instr[i] = instr[i-1]; - instr[pos] = key; - } else { - instr[len] = key; - } - pos++; - len++; - instr[len] = '\0'; - - if (input_x == box_width - 1) { - show_x++; - } else { - input_x++; - } - - wmove(dialog, box_y, box_x); - for (i = 0; i < box_width; i++) { - if (!instr[show_x + i]) { - waddch(dialog, ' '); - break; - } - waddch(dialog, instr[show_x + i]); - } - wmove(dialog, box_y, input_x + box_x); - wrefresh(dialog); - } else - flash(); /* Alarm user about overflow */ - continue; - } - } - } - switch (key) { - case 'O': - case 'o': - delwin(dialog); - return 0; - case 'H': - case 'h': - delwin(dialog); - return 1; - case KEY_UP: - case KEY_LEFT: - switch (button) { - case -1: - button = 1; /* Indicates "Help" button is selected */ - print_buttons(dialog, height, width, 1); - break; - case 0: - button = -1; /* Indicates input box is selected */ - print_buttons(dialog, height, width, 0); - wmove(dialog, box_y, box_x + input_x); - wrefresh(dialog); - break; - case 1: - button = 0; /* Indicates "OK" button is selected */ - print_buttons(dialog, height, width, 0); - break; - } - break; - case TAB: - case KEY_DOWN: - case KEY_RIGHT: - switch (button) { - case -1: - button = 0; /* Indicates "OK" button is selected */ - print_buttons(dialog, height, width, 0); - break; - case 0: - button = 1; /* Indicates "Help" button is selected */ - print_buttons(dialog, height, width, 1); - break; - case 1: - button = -1; /* Indicates input box is selected */ - print_buttons(dialog, height, width, 0); - wmove(dialog, box_y, box_x + input_x); - wrefresh(dialog); - break; - } - break; - case ' ': - case '\n': - delwin(dialog); - return (button == -1 ? 0 : button); - case 'X': - case 'x': - key = KEY_ESC; - break; - case KEY_ESC: - key = on_key_esc(dialog); - break; - case KEY_RESIZE: - delwin(dialog); - on_key_resize(); - goto do_resize; - } - } - - delwin(dialog); - return KEY_ESC; /* ESC pressed */ -} diff --git a/tools/kconfig/lxdialog/menubox.c b/tools/kconfig/lxdialog/menubox.c deleted file mode 100644 index 58c2f8a..0000000 --- a/tools/kconfig/lxdialog/menubox.c +++ /dev/null @@ -1,424 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * menubox.c -- implements the menu box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) - */ - -/* - * Changes by Clifford Wolf (god@clifford.at) - * - * [ 1998-06-13 ] - * - * *) A bugfix for the Page-Down problem - * - * *) Formerly when I used Page Down and Page Up, the cursor would be set - * to the first position in the menu box. Now lxdialog is a bit - * smarter and works more like other menu systems (just have a look at - * it). - * - * *) Formerly if I selected something my scrolling would be broken because - * lxdialog is re-invoked by the Menuconfig shell script, can't - * remember the last scrolling position, and just sets it so that the - * cursor is at the bottom of the box. Now it writes the temporary file - * lxdialog.scrltmp which contains this information. The file is - * deleted by lxdialog if the user leaves a submenu or enters a new - * one, but it would be nice if Menuconfig could make another "rm -f" - * just to be sure. Just try it out - you will recognise a difference! - * - * [ 1998-06-14 ] - * - * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files - * and menus change their size on the fly. - * - * *) If for some reason the last scrolling position is not saved by - * lxdialog, it sets the scrolling so that the selected item is in the - * middle of the menu box, not at the bottom. - * - * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) - * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. - * This fixes a bug in Menuconfig where using ' ' to descend into menus - * would leave mis-synchronized lxdialog.scrltmp files lying around, - * fscanf would read in 'scroll', and eventually that value would get used. - */ - -#include "dialog.h" - -static int menu_width, item_x; - -/* - * Print menu item - */ -static void do_print_item(WINDOW * win, const char *item, int line_y, - int selected, int hotkey) -{ - int j; - char *menu_item = malloc(menu_width + 1); - - strncpy(menu_item, item, menu_width - item_x); - menu_item[menu_width - item_x] = '\0'; - j = first_alpha(menu_item, "YyNnMmHh"); - - /* Clear 'residue' of last item */ - wattrset(win, dlg.menubox.atr); - wmove(win, line_y, 0); -#if OLD_NCURSES - { - int i; - for (i = 0; i < menu_width; i++) - waddch(win, ' '); - } -#else - wclrtoeol(win); -#endif - wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); - mvwaddstr(win, line_y, item_x, menu_item); - if (hotkey) { - wattrset(win, selected ? dlg.tag_key_selected.atr - : dlg.tag_key.atr); - mvwaddch(win, line_y, item_x + j, menu_item[j]); - } - if (selected) { - wmove(win, line_y, item_x + 1); - } - free(menu_item); - wrefresh(win); -} - -#define print_item(index, choice, selected) \ -do { \ - item_set(index); \ - do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \ -} while (0) - -/* - * Print the scroll indicators. - */ -static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x, - int height) -{ - int cur_y, cur_x; - - getyx(win, cur_y, cur_x); - - wmove(win, y, x); - - if (scroll > 0) { - wattrset(win, dlg.uarrow.atr); - waddch(win, ACS_UARROW); - waddstr(win, "(-)"); - } else { - wattrset(win, dlg.menubox.atr); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - } - - y = y + height + 1; - wmove(win, y, x); - wrefresh(win); - - if ((height < item_no) && (scroll + height < item_no)) { - wattrset(win, dlg.darrow.atr); - waddch(win, ACS_DARROW); - waddstr(win, "(+)"); - } else { - wattrset(win, dlg.menubox_border.atr); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - waddch(win, ACS_HLINE); - } - - wmove(win, cur_y, cur_x); - wrefresh(win); -} - -/* - * Display the termination buttons. - */ -static void print_buttons(WINDOW * win, int height, int width, int selected) -{ - int x = width / 2 - 28; - int y = height - 2; - - print_button(win, "Select", y, x, selected == 0); - print_button(win, " Exit ", y, x + 12, selected == 1); - print_button(win, " Help ", y, x + 24, selected == 2); - print_button(win, " Save ", y, x + 36, selected == 3); - print_button(win, " Load ", y, x + 48, selected == 4); - - wmove(win, y, x + 1 + 12 * selected); - wrefresh(win); -} - -/* scroll up n lines (n may be negative) */ -static void do_scroll(WINDOW *win, int *scroll, int n) -{ - /* Scroll menu up */ - scrollok(win, TRUE); - wscrl(win, n); - scrollok(win, FALSE); - *scroll = *scroll + n; - wrefresh(win); -} - -/* - * Display a menu for choosing among a number of options - */ -int dialog_menu(const char *title, const char *prompt, - const void *selected, int *s_scroll) -{ - int i, j, x, y, box_x, box_y; - int height, width, menu_height; - int key = 0, button = 0, scroll = 0, choice = 0; - int first_item = 0, max_choice; - WINDOW *dialog, *menu; - -do_resize: - height = getmaxy(stdscr); - width = getmaxx(stdscr); - if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN) - return -ERRDISPLAYTOOSMALL; - - height -= 4; - width -= 5; - menu_height = height - 10; - - max_choice = MIN(menu_height, item_count()); - - /* center dialog box on screen */ - x = (getmaxx(stdscr) - width) / 2; - y = (getmaxy(stdscr) - height) / 2; - - draw_shadow(stdscr, y, x, height, width); - - dialog = newwin(height, width, y, x); - keypad(dialog, TRUE); - - draw_box(dialog, 0, 0, height, width, - dlg.dialog.atr, dlg.border.atr); - wattrset(dialog, dlg.border.atr); - mvwaddch(dialog, height - 3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch(dialog, ACS_HLINE); - wattrset(dialog, dlg.dialog.atr); - wbkgdset(dialog, dlg.dialog.atr & A_COLOR); - waddch(dialog, ACS_RTEE); - - print_title(dialog, title, width); - - wattrset(dialog, dlg.dialog.atr); - print_autowrap(dialog, prompt, width - 2, 1, 3); - - menu_width = width - 6; - box_y = height - menu_height - 5; - box_x = (width - menu_width) / 2 - 1; - - /* create new window for the menu */ - menu = subwin(dialog, menu_height, menu_width, - y + box_y + 1, x + box_x + 1); - keypad(menu, TRUE); - - /* draw a box around the menu items */ - draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2, - dlg.menubox_border.atr, dlg.menubox.atr); - - if (menu_width >= 80) - item_x = (menu_width - 70) / 2; - else - item_x = 4; - - /* Set choice to default item */ - item_foreach() - if (selected && (selected == item_data())) - choice = item_n(); - /* get the saved scroll info */ - scroll = *s_scroll; - if ((scroll <= choice) && (scroll + max_choice > choice) && - (scroll >= 0) && (scroll + max_choice <= item_count())) { - first_item = scroll; - choice = choice - scroll; - } else { - scroll = 0; - } - if ((choice >= max_choice)) { - if (choice >= item_count() - max_choice / 2) - scroll = first_item = item_count() - max_choice; - else - scroll = first_item = choice - max_choice / 2; - choice = choice - scroll; - } - - /* Print the menu */ - for (i = 0; i < max_choice; i++) { - print_item(first_item + i, i, i == choice); - } - - wnoutrefresh(menu); - - print_arrows(dialog, item_count(), scroll, - box_y, box_x + item_x + 1, menu_height); - - print_buttons(dialog, height, width, 0); - wmove(menu, choice, item_x + 1); - wrefresh(menu); - - while (key != KEY_ESC) { - key = wgetch(menu); - - if (key < 256 && isalpha(key)) - key = tolower(key); - - if (strchr("ynmh", key)) - i = max_choice; - else { - for (i = choice + 1; i < max_choice; i++) { - item_set(scroll + i); - j = first_alpha(item_str(), "YyNnMmHh"); - if (key == tolower(item_str()[j])) - break; - } - if (i == max_choice) - for (i = 0; i < max_choice; i++) { - item_set(scroll + i); - j = first_alpha(item_str(), "YyNnMmHh"); - if (key == tolower(item_str()[j])) - break; - } - } - - if (item_count() != 0 && - (i < max_choice || - key == KEY_UP || key == KEY_DOWN || - key == '-' || key == '+' || - key == KEY_PPAGE || key == KEY_NPAGE)) { - /* Remove highligt of current item */ - print_item(scroll + choice, choice, FALSE); - - if (key == KEY_UP || key == '-') { - if (choice < 2 && scroll) { - /* Scroll menu down */ - do_scroll(menu, &scroll, -1); - - print_item(scroll, 0, FALSE); - } else - choice = MAX(choice - 1, 0); - - } else if (key == KEY_DOWN || key == '+') { - print_item(scroll+choice, choice, FALSE); - - if ((choice > max_choice - 3) && - (scroll + max_choice < item_count())) { - /* Scroll menu up */ - do_scroll(menu, &scroll, 1); - - print_item(scroll+max_choice - 1, - max_choice - 1, FALSE); - } else - choice = MIN(choice + 1, max_choice - 1); - - } else if (key == KEY_PPAGE) { - scrollok(menu, TRUE); - for (i = 0; (i < max_choice); i++) { - if (scroll > 0) { - do_scroll(menu, &scroll, -1); - print_item(scroll, 0, FALSE); - } else { - if (choice > 0) - choice--; - } - } - - } else if (key == KEY_NPAGE) { - for (i = 0; (i < max_choice); i++) { - if (scroll + max_choice < item_count()) { - do_scroll(menu, &scroll, 1); - print_item(scroll+max_choice-1, - max_choice - 1, FALSE); - } else { - if (choice + 1 < max_choice) - choice++; - } - } - } else - choice = i; - - print_item(scroll + choice, choice, TRUE); - - print_arrows(dialog, item_count(), scroll, - box_y, box_x + item_x + 1, menu_height); - - wnoutrefresh(dialog); - wrefresh(menu); - - continue; /* wait for another key press */ - } - - switch (key) { - case KEY_LEFT: - case TAB: - case KEY_RIGHT: - button = ((key == KEY_LEFT ? --button : ++button) < 0) - ? 4 : (button > 4 ? 0 : button); - - print_buttons(dialog, height, width, button); - wrefresh(menu); - break; - case ' ': - case 's': - case 'y': - case 'n': - case 'm': - case '/': - case 'h': - case '?': - case 'z': - case '\n': - /* save scroll info */ - *s_scroll = scroll; - delwin(menu); - delwin(dialog); - item_set(scroll + choice); - item_set_selected(1); - switch (key) { - case 'h': - case '?': - return 2; - case 's': - case 'y': - return 5; - case 'n': - return 6; - case 'm': - return 7; - case ' ': - return 8; - case '/': - return 9; - case 'z': - return 10; - case '\n': - return button; - } - return 0; - case 'e': - case 'x': - key = KEY_ESC; - break; - case KEY_ESC: - key = on_key_esc(menu); - break; - case KEY_RESIZE: - on_key_resize(); - delwin(menu); - delwin(dialog); - goto do_resize; - } - } - delwin(menu); - delwin(dialog); - return key; /* ESC pressed */ -} diff --git a/tools/kconfig/lxdialog/textbox.c b/tools/kconfig/lxdialog/textbox.c deleted file mode 100644 index 4e339b1..0000000 --- a/tools/kconfig/lxdialog/textbox.c +++ /dev/null @@ -1,395 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * textbox.c -- implements the text box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - */ - -#include "dialog.h" - -static void back_lines(int n); -static void print_page(WINDOW *win, int height, int width, update_text_fn - update_text, void *data); -static void print_line(WINDOW *win, int row, int width); -static char *get_line(void); -static void print_position(WINDOW * win); - -static int hscroll; -static int begin_reached, end_reached, page_length; -static char *buf; -static char *page; - -/* - * refresh window content - */ -static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, - int cur_y, int cur_x, update_text_fn update_text, - void *data) -{ - print_page(box, boxh, boxw, update_text, data); - print_position(dialog); - wmove(dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh(dialog); -} - - -/* - * Display text from a file in a dialog box. - * - * keys is a null-terminated array - * update_text() may not add or remove any '\n' or '\0' in tbuf - */ -int dialog_textbox(const char *title, char *tbuf, int initial_height, - int initial_width, int *keys, int *_vscroll, int *_hscroll, - update_text_fn update_text, void *data) -{ - int i, x, y, cur_x, cur_y, key = 0; - int height, width, boxh, boxw; - WINDOW *dialog, *box; - bool done = false; - - begin_reached = 1; - end_reached = 0; - page_length = 0; - hscroll = 0; - buf = tbuf; - page = buf; /* page is pointer to start of page to be displayed */ - - if (_vscroll && *_vscroll) { - begin_reached = 0; - - for (i = 0; i < *_vscroll; i++) - get_line(); - } - if (_hscroll) - hscroll = *_hscroll; - -do_resize: - getmaxyx(stdscr, height, width); - if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN) - return -ERRDISPLAYTOOSMALL; - if (initial_height != 0) - height = initial_height; - else - if (height > 4) - height -= 4; - else - height = 0; - if (initial_width != 0) - width = initial_width; - else - if (width > 5) - width -= 5; - else - width = 0; - - /* center dialog box on screen */ - x = (getmaxx(stdscr) - width) / 2; - y = (getmaxy(stdscr) - height) / 2; - - draw_shadow(stdscr, y, x, height, width); - - dialog = newwin(height, width, y, x); - keypad(dialog, TRUE); - - /* Create window for box region, used for scrolling text */ - boxh = height - 4; - boxw = width - 2; - box = subwin(dialog, boxh, boxw, y + 1, x + 1); - wattrset(box, dlg.dialog.atr); - wbkgdset(box, dlg.dialog.atr & A_COLOR); - - keypad(box, TRUE); - - /* register the new window, along with its borders */ - draw_box(dialog, 0, 0, height, width, - dlg.dialog.atr, dlg.border.atr); - - wattrset(dialog, dlg.border.atr); - mvwaddch(dialog, height - 3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch(dialog, ACS_HLINE); - wattrset(dialog, dlg.dialog.atr); - wbkgdset(dialog, dlg.dialog.atr & A_COLOR); - waddch(dialog, ACS_RTEE); - - print_title(dialog, title, width); - - print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE); - wnoutrefresh(dialog); - getyx(dialog, cur_y, cur_x); /* Save cursor position */ - - /* Print first page of text */ - attr_clear(box, boxh, boxw, dlg.dialog.atr); - refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text, - data); - - while (!done) { - key = wgetch(dialog); - switch (key) { - case 'E': /* Exit */ - case 'e': - case 'X': - case 'x': - case 'q': - case '\n': - done = true; - break; - case 'g': /* First page */ - case KEY_HOME: - if (!begin_reached) { - begin_reached = 1; - page = buf; - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x, update_text, - data); - } - break; - case 'G': /* Last page */ - case KEY_END: - - end_reached = 1; - /* point to last char in buf */ - page = buf + strlen(buf); - back_lines(boxh); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); - break; - case 'K': /* Previous line */ - case 'k': - case KEY_UP: - if (begin_reached) - break; - - back_lines(page_length + 1); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); - break; - case 'B': /* Previous page */ - case 'b': - case 'u': - case KEY_PPAGE: - if (begin_reached) - break; - back_lines(page_length + boxh); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); - break; - case 'J': /* Next line */ - case 'j': - case KEY_DOWN: - if (end_reached) - break; - - back_lines(page_length - 1); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); - break; - case KEY_NPAGE: /* Next page */ - case ' ': - case 'd': - if (end_reached) - break; - - begin_reached = 0; - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); - break; - case '0': /* Beginning of line */ - case 'H': /* Scroll left */ - case 'h': - case KEY_LEFT: - if (hscroll <= 0) - break; - - if (key == '0') - hscroll = 0; - else - hscroll--; - /* Reprint current page to scroll horizontally */ - back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); - break; - case 'L': /* Scroll right */ - case 'l': - case KEY_RIGHT: - if (hscroll >= MAX_LEN) - break; - hscroll++; - /* Reprint current page to scroll horizontally */ - back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); - break; - case KEY_ESC: - if (on_key_esc(dialog) == KEY_ESC) - done = true; - break; - case KEY_RESIZE: - back_lines(height); - delwin(box); - delwin(dialog); - on_key_resize(); - goto do_resize; - default: - for (i = 0; keys[i]; i++) { - if (key == keys[i]) { - done = true; - break; - } - } - } - } - delwin(box); - delwin(dialog); - if (_vscroll) { - const char *s; - - s = buf; - *_vscroll = 0; - back_lines(page_length); - while (s < page && (s = strchr(s, '\n'))) { - (*_vscroll)++; - s++; - } - } - if (_hscroll) - *_hscroll = hscroll; - return key; -} - -/* - * Go back 'n' lines in text. Called by dialog_textbox(). - * 'page' will be updated to point to the desired line in 'buf'. - */ -static void back_lines(int n) -{ - int i; - - begin_reached = 0; - /* Go back 'n' lines */ - for (i = 0; i < n; i++) { - if (*page == '\0') { - if (end_reached) { - end_reached = 0; - continue; - } - } - if (page == buf) { - begin_reached = 1; - return; - } - page--; - do { - if (page == buf) { - begin_reached = 1; - return; - } - page--; - } while (*page != '\n'); - page++; - } -} - -/* - * Print a new page of text. - */ -static void print_page(WINDOW *win, int height, int width, update_text_fn - update_text, void *data) -{ - int i, passed_end = 0; - - if (update_text) { - char *end; - - for (i = 0; i < height; i++) - get_line(); - end = page; - back_lines(height); - update_text(buf, page - buf, end - buf, data); - } - - page_length = 0; - for (i = 0; i < height; i++) { - print_line(win, i, width); - if (!passed_end) - page_length++; - if (end_reached && !passed_end) - passed_end = 1; - } - wnoutrefresh(win); -} - -/* - * Print a new line of text. - */ -static void print_line(WINDOW * win, int row, int width) -{ - char *line; - - line = get_line(); - line += MIN(strlen(line), hscroll); /* Scroll horizontally */ - wmove(win, row, 0); /* move cursor to correct line */ - waddch(win, ' '); - waddnstr(win, line, MIN(strlen(line), width - 2)); - - /* Clear 'residue' of previous line */ -#if OLD_NCURSES - { - int x = getcurx(win); - int i; - for (i = 0; i < width - x; i++) - waddch(win, ' '); - } -#else - wclrtoeol(win); -#endif -} - -/* - * Return current line of text. Called by dialog_textbox() and print_line(). - * 'page' should point to start of current line before calling, and will be - * updated to point to start of next line. - */ -static char *get_line(void) -{ - int i = 0; - static char line[MAX_LEN + 1]; - - end_reached = 0; - while (*page != '\n') { - if (*page == '\0') { - end_reached = 1; - break; - } else if (i < MAX_LEN) - line[i++] = *(page++); - else { - /* Truncate lines longer than MAX_LEN characters */ - if (i == MAX_LEN) - line[i++] = '\0'; - page++; - } - } - if (i <= MAX_LEN) - line[i] = '\0'; - if (!end_reached) - page++; /* move past '\n' */ - - return line; -} - -/* - * Print current position - */ -static void print_position(WINDOW * win) -{ - int percent; - - wattrset(win, dlg.position_indicator.atr); - wbkgdset(win, dlg.position_indicator.atr & A_COLOR); - percent = (page - buf) * 100 / strlen(buf); - wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); - wprintw(win, "(%3d%%)", percent); -} diff --git a/tools/kconfig/lxdialog/util.c b/tools/kconfig/lxdialog/util.c deleted file mode 100644 index 3f78fb2..0000000 --- a/tools/kconfig/lxdialog/util.c +++ /dev/null @@ -1,700 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * util.c - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - */ - -#include <stdarg.h> - -#include "dialog.h" - -/* Needed in signal handler in mconf.c */ -int saved_x, saved_y; - -struct dialog_info dlg; - -static void set_mono_theme(void) -{ - dlg.screen.atr = A_NORMAL; - dlg.shadow.atr = A_NORMAL; - dlg.dialog.atr = A_NORMAL; - dlg.title.atr = A_BOLD; - dlg.border.atr = A_NORMAL; - dlg.button_active.atr = A_REVERSE; - dlg.button_inactive.atr = A_DIM; - dlg.button_key_active.atr = A_REVERSE; - dlg.button_key_inactive.atr = A_BOLD; - dlg.button_label_active.atr = A_REVERSE; - dlg.button_label_inactive.atr = A_NORMAL; - dlg.inputbox.atr = A_NORMAL; - dlg.inputbox_border.atr = A_NORMAL; - dlg.searchbox.atr = A_NORMAL; - dlg.searchbox_title.atr = A_BOLD; - dlg.searchbox_border.atr = A_NORMAL; - dlg.position_indicator.atr = A_BOLD; - dlg.menubox.atr = A_NORMAL; - dlg.menubox_border.atr = A_NORMAL; - dlg.item.atr = A_NORMAL; - dlg.item_selected.atr = A_REVERSE; - dlg.tag.atr = A_BOLD; - dlg.tag_selected.atr = A_REVERSE; - dlg.tag_key.atr = A_BOLD; - dlg.tag_key_selected.atr = A_REVERSE; - dlg.check.atr = A_BOLD; - dlg.check_selected.atr = A_REVERSE; - dlg.uarrow.atr = A_BOLD; - dlg.darrow.atr = A_BOLD; -} - -#define DLG_COLOR(dialog, f, b, h) \ -do { \ - dlg.dialog.fg = (f); \ - dlg.dialog.bg = (b); \ - dlg.dialog.hl = (h); \ -} while (0) - -static void set_classic_theme(void) -{ - DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true); - DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true); - DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true); - DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true); - DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true); - DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true); - DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false); - DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true); - DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true); - DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true); - DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true); - DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true); - DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true); - DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true); - DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true); - DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true); - DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true); - DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true); - DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true); - DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true); - DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true); -} - -static void set_blackbg_theme(void) -{ - DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true); - DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false); - DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false); - DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false); - DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true); - - DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false); - DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true); - DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false); - DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false); - DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true); - - DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); - - DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true); - DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true); - - DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); - - DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true); - - DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false); - DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false); - - DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false); - DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true); - DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false); - DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true); - - DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true); - - DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false); - DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false); -} - -static void set_bluetitle_theme(void) -{ - set_classic_theme(); - DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true); - DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true); - DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true); - DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true); - DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true); - DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true); - DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true); - -} - -/* - * Select color theme - */ -static int set_theme(const char *theme) -{ - int use_color = 1; - if (!theme) - set_bluetitle_theme(); - else if (strcmp(theme, "classic") == 0) - set_classic_theme(); - else if (strcmp(theme, "bluetitle") == 0) - set_bluetitle_theme(); - else if (strcmp(theme, "blackbg") == 0) - set_blackbg_theme(); - else if (strcmp(theme, "mono") == 0) - use_color = 0; - - return use_color; -} - -static void init_one_color(struct dialog_color *color) -{ - static int pair = 0; - - pair++; - init_pair(pair, color->fg, color->bg); - if (color->hl) - color->atr = A_BOLD | COLOR_PAIR(pair); - else - color->atr = COLOR_PAIR(pair); -} - -static void init_dialog_colors(void) -{ - init_one_color(&dlg.screen); - init_one_color(&dlg.shadow); - init_one_color(&dlg.dialog); - init_one_color(&dlg.title); - init_one_color(&dlg.border); - init_one_color(&dlg.button_active); - init_one_color(&dlg.button_inactive); - init_one_color(&dlg.button_key_active); - init_one_color(&dlg.button_key_inactive); - init_one_color(&dlg.button_label_active); - init_one_color(&dlg.button_label_inactive); - init_one_color(&dlg.inputbox); - init_one_color(&dlg.inputbox_border); - init_one_color(&dlg.searchbox); - init_one_color(&dlg.searchbox_title); - init_one_color(&dlg.searchbox_border); - init_one_color(&dlg.position_indicator); - init_one_color(&dlg.menubox); - init_one_color(&dlg.menubox_border); - init_one_color(&dlg.item); - init_one_color(&dlg.item_selected); - init_one_color(&dlg.tag); - init_one_color(&dlg.tag_selected); - init_one_color(&dlg.tag_key); - init_one_color(&dlg.tag_key_selected); - init_one_color(&dlg.check); - init_one_color(&dlg.check_selected); - init_one_color(&dlg.uarrow); - init_one_color(&dlg.darrow); -} - -/* - * Setup for color display - */ -static void color_setup(const char *theme) -{ - int use_color; - - use_color = set_theme(theme); - if (use_color && has_colors()) { - start_color(); - init_dialog_colors(); - } else - set_mono_theme(); -} - -/* - * Set window to attribute 'attr' - */ -void attr_clear(WINDOW * win, int height, int width, chtype attr) -{ - int i, j; - - wattrset(win, attr); - for (i = 0; i < height; i++) { - wmove(win, i, 0); - for (j = 0; j < width; j++) - waddch(win, ' '); - } - touchwin(win); -} - -void dialog_clear(void) -{ - int lines, columns; - - lines = getmaxy(stdscr); - columns = getmaxx(stdscr); - - attr_clear(stdscr, lines, columns, dlg.screen.atr); - /* Display background title if it exists ... - SLH */ - if (dlg.backtitle != NULL) { - int i, len = 0, skip = 0; - struct subtitle_list *pos; - - wattrset(stdscr, dlg.screen.atr); - mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); - - for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { - /* 3 is for the arrow and spaces */ - len += strlen(pos->text) + 3; - } - - wmove(stdscr, 1, 1); - if (len > columns - 2) { - const char *ellipsis = "[...] "; - waddstr(stdscr, ellipsis); - skip = len - (columns - 2 - strlen(ellipsis)); - } - - for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { - if (skip == 0) - waddch(stdscr, ACS_RARROW); - else - skip--; - - if (skip == 0) - waddch(stdscr, ' '); - else - skip--; - - if (skip < strlen(pos->text)) { - waddstr(stdscr, pos->text + skip); - skip = 0; - } else - skip -= strlen(pos->text); - - if (skip == 0) - waddch(stdscr, ' '); - else - skip--; - } - - for (i = len + 1; i < columns - 1; i++) - waddch(stdscr, ACS_HLINE); - } - wnoutrefresh(stdscr); -} - -/* - * Do some initialization for dialog - */ -int init_dialog(const char *backtitle) -{ - int height, width; - - initscr(); /* Init curses */ - - /* Get current cursor position for signal handler in mconf.c */ - getyx(stdscr, saved_y, saved_x); - - getmaxyx(stdscr, height, width); - if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) { - endwin(); - return -ERRDISPLAYTOOSMALL; - } - - dlg.backtitle = backtitle; - color_setup(getenv("MENUCONFIG_COLOR")); - - keypad(stdscr, TRUE); - cbreak(); - noecho(); - dialog_clear(); - - return 0; -} - -void set_dialog_backtitle(const char *backtitle) -{ - dlg.backtitle = backtitle; -} - -void set_dialog_subtitles(struct subtitle_list *subtitles) -{ - dlg.subtitles = subtitles; -} - -/* - * End using dialog functions. - */ -void end_dialog(int x, int y) -{ - /* move cursor back to original position */ - move(y, x); - refresh(); - endwin(); -} - -/* Print the title of the dialog. Center the title and truncate - * tile if wider than dialog (- 2 chars). - **/ -void print_title(WINDOW *dialog, const char *title, int width) -{ - if (title) { - int tlen = MIN(width - 2, strlen(title)); - wattrset(dialog, dlg.title.atr); - mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); - mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen); - waddch(dialog, ' '); - } -} - -/* - * Print a string of text in a window, automatically wrap around to the - * next line if the string is too long to fit on one line. Newline - * characters '\n' are properly processed. We start on a new line - * if there is no room for at least 4 nonblanks following a double-space. - */ -void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) -{ - int newl, cur_x, cur_y; - int prompt_len, room, wlen; - char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0; - - strcpy(tempstr, prompt); - - prompt_len = strlen(tempstr); - - if (prompt_len <= width - x * 2) { /* If prompt is short */ - wmove(win, y, (width - prompt_len) / 2); - waddstr(win, tempstr); - } else { - cur_x = x; - cur_y = y; - newl = 1; - word = tempstr; - while (word && *word) { - sp = strpbrk(word, "\n "); - if (sp && *sp == '\n') - newline_separator = sp; - - if (sp) - *sp++ = 0; - - /* Wrap to next line if either the word does not fit, - or it is the first word of a new sentence, and it is - short, and the next word does not fit. */ - room = width - cur_x; - wlen = strlen(word); - if (wlen > room || - (newl && wlen < 4 && sp - && wlen + 1 + strlen(sp) > room - && (!(sp2 = strpbrk(sp, "\n ")) - || wlen + 1 + (sp2 - sp) > room))) { - cur_y++; - cur_x = x; - } - wmove(win, cur_y, cur_x); - waddstr(win, word); - getyx(win, cur_y, cur_x); - - /* Move to the next line if the word separator was a newline */ - if (newline_separator) { - cur_y++; - cur_x = x; - newline_separator = 0; - } else - cur_x++; - - if (sp && *sp == ' ') { - cur_x++; /* double space */ - while (*++sp == ' ') ; - newl = 1; - } else - newl = 0; - word = sp; - } - } -} - -/* - * Print a button - */ -void print_button(WINDOW * win, const char *label, int y, int x, int selected) -{ - int i, temp; - - wmove(win, y, x); - wattrset(win, selected ? dlg.button_active.atr - : dlg.button_inactive.atr); - waddstr(win, "<"); - temp = strspn(label, " "); - label += temp; - wattrset(win, selected ? dlg.button_label_active.atr - : dlg.button_label_inactive.atr); - for (i = 0; i < temp; i++) - waddch(win, ' '); - wattrset(win, selected ? dlg.button_key_active.atr - : dlg.button_key_inactive.atr); - waddch(win, label[0]); - wattrset(win, selected ? dlg.button_label_active.atr - : dlg.button_label_inactive.atr); - waddstr(win, (char *)label + 1); - wattrset(win, selected ? dlg.button_active.atr - : dlg.button_inactive.atr); - waddstr(win, ">"); - wmove(win, y, x + temp + 1); -} - -/* - * Draw a rectangular box with line drawing characters - */ -void -draw_box(WINDOW * win, int y, int x, int height, int width, - chtype box, chtype border) -{ - int i, j; - - wattrset(win, 0); - for (i = 0; i < height; i++) { - wmove(win, y + i, x); - for (j = 0; j < width; j++) - if (!i && !j) - waddch(win, border | ACS_ULCORNER); - else if (i == height - 1 && !j) - waddch(win, border | ACS_LLCORNER); - else if (!i && j == width - 1) - waddch(win, box | ACS_URCORNER); - else if (i == height - 1 && j == width - 1) - waddch(win, box | ACS_LRCORNER); - else if (!i) - waddch(win, border | ACS_HLINE); - else if (i == height - 1) - waddch(win, box | ACS_HLINE); - else if (!j) - waddch(win, border | ACS_VLINE); - else if (j == width - 1) - waddch(win, box | ACS_VLINE); - else - waddch(win, box | ' '); - } -} - -/* - * Draw shadows along the right and bottom edge to give a more 3D look - * to the boxes - */ -void draw_shadow(WINDOW * win, int y, int x, int height, int width) -{ - int i; - - if (has_colors()) { /* Whether terminal supports color? */ - wattrset(win, dlg.shadow.atr); - wmove(win, y + height, x + 2); - for (i = 0; i < width; i++) - waddch(win, winch(win) & A_CHARTEXT); - for (i = y + 1; i < y + height + 1; i++) { - wmove(win, i, x + width); - waddch(win, winch(win) & A_CHARTEXT); - waddch(win, winch(win) & A_CHARTEXT); - } - wnoutrefresh(win); - } -} - -/* - * Return the position of the first alphabetic character in a string. - */ -int first_alpha(const char *string, const char *exempt) -{ - int i, in_paren = 0, c; - - for (i = 0; i < strlen(string); i++) { - c = tolower(string[i]); - - if (strchr("<[(", c)) - ++in_paren; - if (strchr(">])", c) && in_paren > 0) - --in_paren; - - if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) - return i; - } - - return 0; -} - -/* - * ncurses uses ESC to detect escaped char sequences. This resutl in - * a small timeout before ESC is actually delivered to the application. - * lxdialog suggest <ESC> <ESC> which is correctly translated to two - * times esc. But then we need to ignore the second esc to avoid stepping - * out one menu too much. Filter away all escaped key sequences since - * keypad(FALSE) turn off ncurses support for escape sequences - and that's - * needed to make notimeout() do as expected. - */ -int on_key_esc(WINDOW *win) -{ - int key; - int key2; - int key3; - - nodelay(win, TRUE); - keypad(win, FALSE); - key = wgetch(win); - key2 = wgetch(win); - do { - key3 = wgetch(win); - } while (key3 != ERR); - nodelay(win, FALSE); - keypad(win, TRUE); - if (key == KEY_ESC && key2 == ERR) - return KEY_ESC; - else if (key != ERR && key != KEY_ESC && key2 == ERR) - ungetch(key); - - return -1; -} - -/* redraw screen in new size */ -int on_key_resize(void) -{ - dialog_clear(); - return KEY_RESIZE; -} - -struct dialog_list *item_cur; -struct dialog_list item_nil; -struct dialog_list *item_head; - -void item_reset(void) -{ - struct dialog_list *p, *next; - - for (p = item_head; p; p = next) { - next = p->next; - free(p); - } - item_head = NULL; - item_cur = &item_nil; -} - -void item_make(const char *fmt, ...) -{ - va_list ap; - struct dialog_list *p = malloc(sizeof(*p)); - - if (item_head) - item_cur->next = p; - else - item_head = p; - item_cur = p; - memset(p, 0, sizeof(*p)); - - va_start(ap, fmt); - vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap); - va_end(ap); -} - -void item_add_str(const char *fmt, ...) -{ - va_list ap; - size_t avail; - - avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); - - va_start(ap, fmt); - vsnprintf(item_cur->node.str + strlen(item_cur->node.str), - avail, fmt, ap); - item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0'; - va_end(ap); -} - -void item_set_tag(char tag) -{ - item_cur->node.tag = tag; -} -void item_set_data(void *ptr) -{ - item_cur->node.data = ptr; -} - -void item_set_selected(int val) -{ - item_cur->node.selected = val; -} - -int item_activate_selected(void) -{ - item_foreach() - if (item_is_selected()) - return 1; - return 0; -} - -void *item_data(void) -{ - return item_cur->node.data; -} - -char item_tag(void) -{ - return item_cur->node.tag; -} - -int item_count(void) -{ - int n = 0; - struct dialog_list *p; - - for (p = item_head; p; p = p->next) - n++; - return n; -} - -void item_set(int n) -{ - int i = 0; - item_foreach() - if (i++ == n) - return; -} - -int item_n(void) -{ - int n = 0; - struct dialog_list *p; - - for (p = item_head; p; p = p->next) { - if (p == item_cur) - return n; - n++; - } - return 0; -} - -const char *item_str(void) -{ - return item_cur->node.str; -} - -int item_is_selected(void) -{ - return (item_cur->node.selected != 0); -} - -int item_is_tag(char tag) -{ - return (item_cur->node.tag == tag); -} diff --git a/tools/kconfig/lxdialog/yesno.c b/tools/kconfig/lxdialog/yesno.c deleted file mode 100644 index bcaac9b..0000000 --- a/tools/kconfig/lxdialog/yesno.c +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * yesno.c -- implements the yes/no box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - */ - -#include "dialog.h" - -/* - * Display termination buttons - */ -static void print_buttons(WINDOW * dialog, int height, int width, int selected) -{ - int x = width / 2 - 10; - int y = height - 2; - - print_button(dialog, " Yes ", y, x, selected == 0); - print_button(dialog, " No ", y, x + 13, selected == 1); - - wmove(dialog, y, x + 1 + 13 * selected); - wrefresh(dialog); -} - -/* - * Display a dialog box with two buttons - Yes and No - */ -int dialog_yesno(const char *title, const char *prompt, int height, int width) -{ - int i, x, y, key = 0, button = 0; - WINDOW *dialog; - -do_resize: - if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN)) - return -ERRDISPLAYTOOSMALL; - if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN)) - return -ERRDISPLAYTOOSMALL; - - /* center dialog box on screen */ - x = (getmaxx(stdscr) - width) / 2; - y = (getmaxy(stdscr) - height) / 2; - - draw_shadow(stdscr, y, x, height, width); - - dialog = newwin(height, width, y, x); - keypad(dialog, TRUE); - - draw_box(dialog, 0, 0, height, width, - dlg.dialog.atr, dlg.border.atr); - wattrset(dialog, dlg.border.atr); - mvwaddch(dialog, height - 3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch(dialog, ACS_HLINE); - wattrset(dialog, dlg.dialog.atr); - waddch(dialog, ACS_RTEE); - - print_title(dialog, title, width); - - wattrset(dialog, dlg.dialog.atr); - print_autowrap(dialog, prompt, width - 2, 1, 3); - - print_buttons(dialog, height, width, 0); - - while (key != KEY_ESC) { - key = wgetch(dialog); - switch (key) { - case 'Y': - case 'y': - delwin(dialog); - return 0; - case 'N': - case 'n': - delwin(dialog); - return 1; - - case TAB: - case KEY_LEFT: - case KEY_RIGHT: - button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); - - print_buttons(dialog, height, width, button); - wrefresh(dialog); - break; - case ' ': - case '\n': - delwin(dialog); - return button; - case KEY_ESC: - key = on_key_esc(dialog); - break; - case KEY_RESIZE: - delwin(dialog); - on_key_resize(); - goto do_resize; - } - } - - delwin(dialog); - return key; /* ESC pressed */ -} diff --git a/tools/kconfig/mconf.c b/tools/kconfig/mconf.c deleted file mode 100644 index e67e0db..0000000 --- a/tools/kconfig/mconf.c +++ /dev/null @@ -1,1042 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - * - * Introduced single menu mode (show all sub-menus in one large tree). - * 2002-11-06 Petr Baudis <pasky@ucw.cz> - * - * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br> - */ - -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <signal.h> -#include <unistd.h> - -#include "lkc.h" -#include "lxdialog/dialog.h" - -#define JUMP_NB 9 - -static const char mconf_readme[] = -"Overview\n" -"--------\n" -"This interface lets you select features and parameters for the build.\n" -"Features can either be built-in, modularized, or ignored. Parameters\n" -"must be entered in as decimal or hexadecimal numbers or text.\n" -"\n" -"Menu items beginning with following braces represent features that\n" -" [ ] can be built in or removed\n" -" < > can be built in, modularized or removed\n" -" { } can be built in or modularized (selected by other feature)\n" -" - - are selected by other feature,\n" -"while *, M or whitespace inside braces means to build in, build as\n" -"a module or to exclude the feature respectively.\n" -"\n" -"To change any of these features, highlight it with the cursor\n" -"keys and press <Y> to build it in, <M> to make it a module or\n" -"<N> to remove it. You may also press the <Space Bar> to cycle\n" -"through the available options (i.e. Y->N->M->Y).\n" -"\n" -"Some additional keyboard hints:\n" -"\n" -"Menus\n" -"----------\n" -"o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n" -" wish to change or the submenu you wish to select and press <Enter>.\n" -" Submenus are designated by \"--->\", empty ones by \"----\".\n" -"\n" -" Shortcut: Press the option's highlighted letter (hotkey).\n" -" Pressing a hotkey more than once will sequence\n" -" through all visible items which use that hotkey.\n" -"\n" -" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n" -" unseen options into view.\n" -"\n" -"o To exit a menu use the cursor keys to highlight the <Exit> button\n" -" and press <ENTER>.\n" -"\n" -" Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n" -" using those letters. You may press a single <ESC>, but\n" -" there is a delayed response which you may find annoying.\n" -"\n" -" Also, the <TAB> and cursor keys will cycle between <Select>,\n" -" <Exit>, <Help>, <Save>, and <Load>.\n" -"\n" -"o To get help with an item, use the cursor keys to highlight <Help>\n" -" and press <ENTER>.\n" -"\n" -" Shortcut: Press <H> or <?>.\n" -"\n" -"o To toggle the display of hidden options, press <Z>.\n" -"\n" -"\n" -"Radiolists (Choice lists)\n" -"-----------\n" -"o Use the cursor keys to select the option you wish to set and press\n" -" <S> or the <SPACE BAR>.\n" -"\n" -" Shortcut: Press the first letter of the option you wish to set then\n" -" press <S> or <SPACE BAR>.\n" -"\n" -"o To see available help for the item, use the cursor keys to highlight\n" -" <Help> and Press <ENTER>.\n" -"\n" -" Shortcut: Press <H> or <?>.\n" -"\n" -" Also, the <TAB> and cursor keys will cycle between <Select> and\n" -" <Help>\n" -"\n" -"\n" -"Data Entry\n" -"-----------\n" -"o Enter the requested information and press <ENTER>\n" -" If you are entering hexadecimal values, it is not necessary to\n" -" add the '0x' prefix to the entry.\n" -"\n" -"o For help, use the <TAB> or cursor keys to highlight the help option\n" -" and press <ENTER>. You can try <TAB><H> as well.\n" -"\n" -"\n" -"Text Box (Help Window)\n" -"--------\n" -"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" -" keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for\n" -" those who are familiar with less and lynx.\n" -"\n" -"o Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n" -"\n" -"\n" -"Alternate Configuration Files\n" -"-----------------------------\n" -"Menuconfig supports the use of alternate configuration files for\n" -"those who, for various reasons, find it necessary to switch\n" -"between different configurations.\n" -"\n" -"The <Save> button will let you save the current configuration to\n" -"a file of your choosing. Use the <Load> button to load a previously\n" -"saved alternate configuration.\n" -"\n" -"Even if you don't use alternate configuration files, but you find\n" -"during a Menuconfig session that you have completely messed up your\n" -"settings, you may use the <Load> button to restore your previously\n" -"saved settings from \".config\" without restarting Menuconfig.\n" -"\n" -"Other information\n" -"-----------------\n" -"If you use Menuconfig in an XTERM window, make sure you have your\n" -"$TERM variable set to point to an xterm definition which supports\n" -"color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n" -"not display correctly in an RXVT window because rxvt displays only one\n" -"intensity of color, bright.\n" -"\n" -"Menuconfig will display larger menus on screens or xterms which are\n" -"set to display more than the standard 25 row by 80 column geometry.\n" -"In order for this to work, the \"stty size\" command must be able to\n" -"display the screen's current row and column geometry. I STRONGLY\n" -"RECOMMEND that you make sure you do NOT have the shell variables\n" -"LINES and COLUMNS exported into your environment. Some distributions\n" -"export those variables via /etc/profile. Some ncurses programs can\n" -"become confused when those variables (LINES & COLUMNS) don't reflect\n" -"the true screen size.\n" -"\n" -"Optional personality available\n" -"------------------------------\n" -"If you prefer to have all of the options listed in a single menu,\n" -"rather than the default multimenu hierarchy, run the menuconfig with\n" -"MENUCONFIG_MODE environment variable set to single_menu. Example:\n" -"\n" -"make MENUCONFIG_MODE=single_menu menuconfig\n" -"\n" -"<Enter> will then unroll the appropriate category, or enfold it if it\n" -"is already unrolled.\n" -"\n" -"Note that this mode can eventually be a little more CPU expensive\n" -"(especially with a larger number of unrolled categories) than the\n" -"default mode.\n" -"\n" - -"Search\n" -"-------\n" -"Pressing the forward-slash (/) anywhere brings up a search dialog box.\n" -"\n" - -"Different color themes available\n" -"--------------------------------\n" -"It is possible to select different color themes using the variable\n" -"MENUCONFIG_COLOR. To select a theme use:\n" -"\n" -"make MENUCONFIG_COLOR=<theme> menuconfig\n" -"\n" -"Available themes are\n" -" mono => selects colors suitable for monochrome displays\n" -" blackbg => selects a color scheme with black background\n" -" classic => theme with blue background. The classic look\n" -" bluetitle => an LCD friendly version of classic. (default)\n" -"\n", -menu_instructions[] = - "Arrow keys navigate the menu. " - "<Enter> selects submenus ---> (or empty submenus ----). " - "Highlighted letters are hotkeys. " - "Pressing <Y> includes, <N> excludes, <M> modularizes features. " - "Press <Esc><Esc> to exit, <?> for Help, </> for Search. " - "Legend: [*] built-in [ ] excluded <M> module < > module capable", -radiolist_instructions[] = - "Use the arrow keys to navigate this window or " - "press the hotkey of the item you wish to select " - "followed by the <SPACE BAR>. " - "Press <?> for additional information about this option.", -inputbox_instructions_int[] = - "Please enter a decimal value. " - "Fractions will not be accepted. " - "Use the <TAB> key to move from the input field to the buttons below it.", -inputbox_instructions_hex[] = - "Please enter a hexadecimal value. " - "Use the <TAB> key to move from the input field to the buttons below it.", -inputbox_instructions_string[] = - "Please enter a string value. " - "Use the <TAB> key to move from the input field to the buttons below it.", -setmod_text[] = - "This feature depends on another which has been configured as a module.\n" - "As a result, this feature will be built as a module.", -load_config_text[] = - "Enter the name of the configuration file you wish to load. " - "Accept the name shown to restore the configuration you " - "last retrieved. Leave blank to abort.", -load_config_help[] = - "\n" - "For various reasons, one may wish to keep several different\n" - "configurations available on a single machine.\n" - "\n" - "If you have saved a previous configuration in a file other than the\n" - "default one, entering its name here will allow you to modify that\n" - "configuration.\n" - "\n" - "If you are uncertain, then you have probably never used alternate\n" - "configuration files. You should therefore leave this blank to abort.\n", -save_config_text[] = - "Enter a filename to which this configuration should be saved " - "as an alternate. Leave blank to abort.", -save_config_help[] = - "\n" - "For various reasons, one may wish to keep different configurations\n" - "available on a single machine.\n" - "\n" - "Entering a file name here will allow you to later retrieve, modify\n" - "and use the current configuration as an alternate to whatever\n" - "configuration options you have selected at that time.\n" - "\n" - "If you are uncertain what all this means then you should probably\n" - "leave this blank.\n", -search_help[] = - "\n" - "Search for symbols and display their relations.\n" - "Regular expressions are allowed.\n" - "Example: search for \"^FOO\"\n" - "Result:\n" - "-----------------------------------------------------------------\n" - "Symbol: FOO [=m]\n" - "Type : tristate\n" - "Prompt: Foo bus is used to drive the bar HW\n" - " Location:\n" - " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" - " -> PCI support (PCI [=y])\n" - "(1) -> PCI access mode (<choice> [=y])\n" - " Defined at drivers/pci/Kconfig:47\n" - " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" - " Selects: LIBCRC32\n" - " Selected by: BAR [=n]\n" - "-----------------------------------------------------------------\n" - "o The line 'Type:' shows the type of the configuration option for\n" - " this symbol (bool, tristate, string, ...)\n" - "o The line 'Prompt:' shows the text used in the menu structure for\n" - " this symbol\n" - "o The 'Defined at' line tells at what file / line number the symbol\n" - " is defined\n" - "o The 'Depends on:' line tells what symbols need to be defined for\n" - " this symbol to be visible in the menu (selectable)\n" - "o The 'Location:' lines tells where in the menu structure this symbol\n" - " is located\n" - " A location followed by a [=y] indicates that this is a\n" - " selectable menu item - and the current value is displayed inside\n" - " brackets.\n" - " Press the key in the (#) prefix to jump directly to that\n" - " location. You will be returned to the current search results\n" - " after exiting this new menu.\n" - "o The 'Selects:' line tells what symbols will be automatically\n" - " selected if this symbol is selected (y or m)\n" - "o The 'Selected by' line tells what symbol has selected this symbol\n" - "\n" - "Only relevant lines are shown.\n" - "\n\n" - "Search examples:\n" - "Examples: USB => find all symbols containing USB\n" - " ^USB => find all symbols starting with USB\n" - " USB$ => find all symbols ending with USB\n" - "\n"; - -static int indent; -static struct menu *current_menu; -static int child_count; -static int single_menu_mode; -static int show_all_options; -static int save_and_exit; -static int silent; - -static void conf(struct menu *menu, struct menu *active_menu); -static void conf_choice(struct menu *menu); -static void conf_string(struct menu *menu); -static void conf_load(void); -static void conf_save(void); -static int show_textbox_ext(const char *title, char *text, int r, int c, - int *keys, int *vscroll, int *hscroll, - update_text_fn update_text, void *data); -static void show_textbox(const char *title, const char *text, int r, int c); -static void show_helptext(const char *title, const char *text); -static void show_help(struct menu *menu); - -static char filename[PATH_MAX+1]; -static void set_config_filename(const char *config_filename) -{ - static char menu_backtitle[PATH_MAX+128]; - - snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s", - config_filename, rootmenu.prompt->text); - set_dialog_backtitle(menu_backtitle); - - snprintf(filename, sizeof(filename), "%s", config_filename); -} - -struct subtitle_part { - struct list_head entries; - const char *text; -}; -static LIST_HEAD(trail); - -static struct subtitle_list *subtitles; -static void set_subtitle(void) -{ - struct subtitle_part *sp; - struct subtitle_list *pos, *tmp; - - for (pos = subtitles; pos != NULL; pos = tmp) { - tmp = pos->next; - free(pos); - } - - subtitles = NULL; - list_for_each_entry(sp, &trail, entries) { - if (sp->text) { - if (pos) { - pos->next = xcalloc(1, sizeof(*pos)); - pos = pos->next; - } else { - subtitles = pos = xcalloc(1, sizeof(*pos)); - } - pos->text = sp->text; - } - } - - set_dialog_subtitles(subtitles); -} - -static void reset_subtitle(void) -{ - struct subtitle_list *pos, *tmp; - - for (pos = subtitles; pos != NULL; pos = tmp) { - tmp = pos->next; - free(pos); - } - subtitles = NULL; - set_dialog_subtitles(subtitles); -} - -struct search_data { - struct list_head *head; - struct menu **targets; - int *keys; -}; - -static void update_text(char *buf, size_t start, size_t end, void *_data) -{ - struct search_data *data = _data; - struct jump_key *pos; - int k = 0; - - list_for_each_entry(pos, data->head, entries) { - if (pos->offset >= start && pos->offset < end) { - char header[4]; - - if (k < JUMP_NB) { - int key = '0' + (pos->index % JUMP_NB) + 1; - - sprintf(header, "(%c)", key); - data->keys[k] = key; - data->targets[k] = pos->target; - k++; - } else { - sprintf(header, " "); - } - - memcpy(buf + pos->offset, header, sizeof(header) - 1); - } - } - data->keys[k] = 0; -} - -static void search_conf(void) -{ - struct symbol **sym_arr; - struct gstr res; - struct gstr title; - char *dialog_input; - int dres, vscroll = 0, hscroll = 0; - bool again; - struct gstr sttext; - struct subtitle_part stpart; - - title = str_new(); - str_printf( &title, "Enter (sub)string or regexp to search for " - "(with or without \"%s\")", CONFIG_); - -again: - dialog_clear(); - dres = dialog_inputbox("Search Configuration Parameter", - str_get(&title), - 10, 75, ""); - switch (dres) { - case 0: - break; - case 1: - show_helptext("Search Configuration", search_help); - goto again; - default: - str_free(&title); - return; - } - - /* strip the prefix if necessary */ - dialog_input = dialog_input_result; - if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) - dialog_input += strlen(CONFIG_); - - sttext = str_new(); - str_printf(&sttext, "Search (%s)", dialog_input_result); - stpart.text = str_get(&sttext); - list_add_tail(&stpart.entries, &trail); - - sym_arr = sym_re_search(dialog_input); - do { - LIST_HEAD(head); - struct menu *targets[JUMP_NB]; - int keys[JUMP_NB + 1], i; - struct search_data data = { - .head = &head, - .targets = targets, - .keys = keys, - }; - struct jump_key *pos, *tmp; - - res = get_relations_str(sym_arr, &head); - set_subtitle(); - dres = show_textbox_ext("Search Results", str_get(&res), 0, 0, - keys, &vscroll, &hscroll, &update_text, - &data); - again = false; - for (i = 0; i < JUMP_NB && keys[i]; i++) - if (dres == keys[i]) { - conf(targets[i]->parent, targets[i]); - again = true; - } - str_free(&res); - list_for_each_entry_safe(pos, tmp, &head, entries) - free(pos); - } while (again); - free(sym_arr); - str_free(&title); - list_del(trail.prev); - str_free(&sttext); -} - -static void build_conf(struct menu *menu) -{ - struct symbol *sym; - struct property *prop; - struct menu *child; - int type, tmp, doint = 2; - tristate val; - char ch; - bool visible; - - /* - * note: menu_is_visible() has side effect that it will - * recalc the value of the symbol. - */ - visible = menu_is_visible(menu); - if (show_all_options && !menu_has_prompt(menu)) - return; - else if (!show_all_options && !visible) - return; - - sym = menu->sym; - prop = menu->prompt; - if (!sym) { - if (prop && menu != current_menu) { - const char *prompt = menu_get_prompt(menu); - switch (prop->type) { - case P_MENU: - child_count++; - if (single_menu_mode) { - item_make("%s%*c%s", - menu->data ? "-->" : "++>", - indent + 1, ' ', prompt); - } else - item_make(" %*c%s %s", - indent + 1, ' ', prompt, - menu_is_empty(menu) ? "----" : "--->"); - item_set_tag('m'); - item_set_data(menu); - if (single_menu_mode && menu->data) - goto conf_childs; - return; - case P_COMMENT: - if (prompt) { - child_count++; - item_make(" %*c*** %s ***", indent + 1, ' ', prompt); - item_set_tag(':'); - item_set_data(menu); - } - break; - default: - if (prompt) { - child_count++; - item_make("---%*c%s", indent + 1, ' ', prompt); - item_set_tag(':'); - item_set_data(menu); - } - } - } else - doint = 0; - goto conf_childs; - } - - type = sym_get_type(sym); - if (sym_is_choice(sym)) { - struct symbol *def_sym = sym_get_choice_value(sym); - struct menu *def_menu = NULL; - - child_count++; - for (child = menu->list; child; child = child->next) { - if (menu_is_visible(child) && child->sym == def_sym) - def_menu = child; - } - - val = sym_get_tristate_value(sym); - if (sym_is_changeable(sym)) { - switch (type) { - case S_BOOLEAN: - item_make("[%c]", val == no ? ' ' : '*'); - break; - case S_TRISTATE: - switch (val) { - case yes: ch = '*'; break; - case mod: ch = 'M'; break; - default: ch = ' '; break; - } - item_make("<%c>", ch); - break; - } - item_set_tag('t'); - item_set_data(menu); - } else { - item_make(" "); - item_set_tag(def_menu ? 't' : ':'); - item_set_data(menu); - } - - item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); - if (val == yes) { - if (def_menu) { - item_add_str(" (%s)", menu_get_prompt(def_menu)); - item_add_str(" --->"); - if (def_menu->list) { - indent += 2; - build_conf(def_menu); - indent -= 2; - } - } - return; - } - } else { - if (menu == current_menu) { - item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu)); - item_set_tag(':'); - item_set_data(menu); - goto conf_childs; - } - child_count++; - val = sym_get_tristate_value(sym); - if (sym_is_choice_value(sym) && val == yes) { - item_make(" "); - item_set_tag(':'); - item_set_data(menu); - } else { - switch (type) { - case S_BOOLEAN: - if (sym_is_changeable(sym)) - item_make("[%c]", val == no ? ' ' : '*'); - else - item_make("-%c-", val == no ? ' ' : '*'); - item_set_tag('t'); - item_set_data(menu); - break; - case S_TRISTATE: - switch (val) { - case yes: ch = '*'; break; - case mod: ch = 'M'; break; - default: ch = ' '; break; - } - if (sym_is_changeable(sym)) { - if (sym->rev_dep.tri == mod) - item_make("{%c}", ch); - else - item_make("<%c>", ch); - } else - item_make("-%c-", ch); - item_set_tag('t'); - item_set_data(menu); - break; - default: - tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ - item_make("(%s)", sym_get_string_value(sym)); - tmp = indent - tmp + 4; - if (tmp < 0) - tmp = 0; - item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu), - (sym_has_value(sym) || !sym_is_changeable(sym)) ? - "" : " (NEW)"); - item_set_tag('s'); - item_set_data(menu); - goto conf_childs; - } - } - item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), - (sym_has_value(sym) || !sym_is_changeable(sym)) ? - "" : " (NEW)"); - if (menu->prompt->type == P_MENU) { - item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); - return; - } - } - -conf_childs: - indent += doint; - for (child = menu->list; child; child = child->next) - build_conf(child); - indent -= doint; -} - -static void conf(struct menu *menu, struct menu *active_menu) -{ - struct menu *submenu; - const char *prompt = menu_get_prompt(menu); - struct subtitle_part stpart; - struct symbol *sym; - int res; - int s_scroll = 0; - - if (menu != &rootmenu) - stpart.text = menu_get_prompt(menu); - else - stpart.text = NULL; - list_add_tail(&stpart.entries, &trail); - - while (1) { - item_reset(); - current_menu = menu; - build_conf(menu); - if (!child_count) - break; - set_subtitle(); - dialog_clear(); - res = dialog_menu(prompt ? prompt : "Main Menu", - menu_instructions, - active_menu, &s_scroll); - if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) - break; - if (item_count() != 0) { - if (!item_activate_selected()) - continue; - if (!item_tag()) - continue; - } - submenu = item_data(); - active_menu = item_data(); - if (submenu) - sym = submenu->sym; - else - sym = NULL; - - switch (res) { - case 0: - switch (item_tag()) { - case 'm': - if (single_menu_mode) - submenu->data = (void *) (long) !submenu->data; - else - conf(submenu, NULL); - break; - case 't': - if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) - conf_choice(submenu); - else if (submenu->prompt->type == P_MENU) - conf(submenu, NULL); - break; - case 's': - conf_string(submenu); - break; - } - break; - case 2: - if (sym) - show_help(submenu); - else { - reset_subtitle(); - show_helptext("README", mconf_readme); - } - break; - case 3: - reset_subtitle(); - conf_save(); - break; - case 4: - reset_subtitle(); - conf_load(); - break; - case 5: - if (item_is_tag('t')) { - if (sym_set_tristate_value(sym, yes)) - break; - if (sym_set_tristate_value(sym, mod)) - show_textbox(NULL, setmod_text, 6, 74); - } - break; - case 6: - if (item_is_tag('t')) - sym_set_tristate_value(sym, no); - break; - case 7: - if (item_is_tag('t')) - sym_set_tristate_value(sym, mod); - break; - case 8: - if (item_is_tag('t')) - sym_toggle_tristate_value(sym); - else if (item_is_tag('m')) - conf(submenu, NULL); - break; - case 9: - search_conf(); - break; - case 10: - show_all_options = !show_all_options; - break; - } - } - - list_del(trail.prev); -} - -static int show_textbox_ext(const char *title, char *text, int r, int c, int - *keys, int *vscroll, int *hscroll, update_text_fn - update_text, void *data) -{ - dialog_clear(); - return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, - update_text, data); -} - -static void show_textbox(const char *title, const char *text, int r, int c) -{ - show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, - NULL, NULL); -} - -static void show_helptext(const char *title, const char *text) -{ - show_textbox(title, text, 0, 0); -} - -static void conf_message_callback(const char *s) -{ - if (save_and_exit) { - if (!silent) - printf("%s", s); - } else { - show_textbox(NULL, s, 6, 60); - } -} - -static void show_help(struct menu *menu) -{ - struct gstr help = str_new(); - - help.max_width = getmaxx(stdscr) - 10; - menu_get_ext_help(menu, &help); - - show_helptext(menu_get_prompt(menu), str_get(&help)); - str_free(&help); -} - -static void conf_choice(struct menu *menu) -{ - const char *prompt = menu_get_prompt(menu); - struct menu *child; - struct symbol *active; - - active = sym_get_choice_value(menu->sym); - while (1) { - int res; - int selected; - item_reset(); - - current_menu = menu; - for (child = menu->list; child; child = child->next) { - if (!menu_is_visible(child)) - continue; - if (child->sym) - item_make("%s", menu_get_prompt(child)); - else { - item_make("*** %s ***", menu_get_prompt(child)); - item_set_tag(':'); - } - item_set_data(child); - if (child->sym == active) - item_set_selected(1); - if (child->sym == sym_get_choice_value(menu->sym)) - item_set_tag('X'); - } - dialog_clear(); - res = dialog_checklist(prompt ? prompt : "Main Menu", - radiolist_instructions, - MENUBOX_HEIGTH_MIN, - MENUBOX_WIDTH_MIN, - CHECKLIST_HEIGTH_MIN); - selected = item_activate_selected(); - switch (res) { - case 0: - if (selected) { - child = item_data(); - if (!child->sym) - break; - - sym_set_tristate_value(child->sym, yes); - } - return; - case 1: - if (selected) { - child = item_data(); - show_help(child); - active = child->sym; - } else - show_help(menu); - break; - case KEY_ESC: - return; - case -ERRDISPLAYTOOSMALL: - return; - } - } -} - -static void conf_string(struct menu *menu) -{ - const char *prompt = menu_get_prompt(menu); - - while (1) { - int res; - const char *heading; - - switch (sym_get_type(menu->sym)) { - case S_INT: - heading = inputbox_instructions_int; - break; - case S_HEX: - heading = inputbox_instructions_hex; - break; - case S_STRING: - heading = inputbox_instructions_string; - break; - default: - heading = "Internal mconf error!"; - } - dialog_clear(); - res = dialog_inputbox(prompt ? prompt : "Main Menu", - heading, 10, 75, - sym_get_string_value(menu->sym)); - switch (res) { - case 0: - if (sym_set_string_value(menu->sym, dialog_input_result)) - return; - show_textbox(NULL, "You have made an invalid entry.", 5, 43); - break; - case 1: - show_help(menu); - break; - case KEY_ESC: - return; - } - } -} - -static void conf_load(void) -{ - - while (1) { - int res; - dialog_clear(); - res = dialog_inputbox(NULL, load_config_text, - 11, 55, filename); - switch(res) { - case 0: - if (!dialog_input_result[0]) - return; - if (!conf_read(dialog_input_result)) { - set_config_filename(dialog_input_result); - conf_set_changed(true); - return; - } - show_textbox(NULL, "File does not exist!", 5, 38); - break; - case 1: - show_helptext("Load Alternate Configuration", load_config_help); - break; - case KEY_ESC: - return; - } - } -} - -static void conf_save(void) -{ - while (1) { - int res; - dialog_clear(); - res = dialog_inputbox(NULL, save_config_text, - 11, 55, filename); - switch(res) { - case 0: - if (!dialog_input_result[0]) - return; - if (!conf_write(dialog_input_result)) { - set_config_filename(dialog_input_result); - return; - } - show_textbox(NULL, "Can't create file!", 5, 60); - break; - case 1: - show_helptext("Save Alternate Configuration", save_config_help); - break; - case KEY_ESC: - return; - } - } -} - -static int handle_exit(void) -{ - int res; - - save_and_exit = 1; - reset_subtitle(); - dialog_clear(); - if (conf_get_changed()) - res = dialog_yesno(NULL, - "Do you wish to save your new configuration?\n" - "(Press <ESC><ESC> to continue kernel configuration.)", - 6, 60); - else - res = -1; - - end_dialog(saved_x, saved_y); - - switch (res) { - case 0: - if (conf_write(filename)) { - fprintf(stderr, "\n\n" - "Error while writing of the configuration.\n" - "Your configuration changes were NOT saved." - "\n\n"); - return 1; - } - conf_write_autoconf(0); - /* fall through */ - case -1: - if (!silent) - printf("\n\n" - "*** End of the configuration.\n" - "*** Execute 'make' to start the build or try 'make help'." - "\n\n"); - res = 0; - break; - default: - if (!silent) - fprintf(stderr, "\n\n" - "Your configuration changes were NOT saved." - "\n\n"); - if (res != KEY_ESC) - res = 0; - } - - return res; -} - -static void sig_handler(int signo) -{ - exit(handle_exit()); -} - -int main(int ac, char **av) -{ - char *mode; - int res; - - signal(SIGINT, sig_handler); - - if (ac > 1 && strcmp(av[1], "-s") == 0) { - silent = 1; - /* Silence conf_read() until the real callback is set up */ - conf_set_message_callback(NULL); - av++; - } - conf_parse(av[1]); - conf_read(NULL); - - mode = getenv("MENUCONFIG_MODE"); - if (mode) { - if (!strcasecmp(mode, "single_menu")) - single_menu_mode = 1; - } - - if (init_dialog(NULL)) { - fprintf(stderr, "Your display is too small to run Menuconfig!\n"); - fprintf(stderr, "It must be at least 19 lines by 80 columns.\n"); - return 1; - } - - set_config_filename(conf_get_configname()); - conf_set_message_callback(conf_message_callback); - do { - conf(&rootmenu, NULL); - res = handle_exit(); - } while (res == KEY_ESC); - - return res; -} diff --git a/tools/kconfig/menu.c b/tools/kconfig/menu.c deleted file mode 100644 index b90fff8..0000000 --- a/tools/kconfig/menu.c +++ /dev/null @@ -1,859 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ - -#include <ctype.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> - -#include "lkc.h" -#include "internal.h" - -static const char nohelp_text[] = "There is no help available for this option."; - -struct menu rootmenu; -static struct menu **last_entry_ptr; - -struct file *file_list; -struct file *current_file; - -void menu_warn(struct menu *menu, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); -} - -static void prop_warn(struct property *prop, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); -} - -void _menu_init(void) -{ - current_entry = current_menu = &rootmenu; - last_entry_ptr = &rootmenu.list; -} - -void menu_add_entry(struct symbol *sym) -{ - struct menu *menu; - - menu = xmalloc(sizeof(*menu)); - memset(menu, 0, sizeof(*menu)); - menu->sym = sym; - menu->parent = current_menu; - menu->file = current_file; - menu->lineno = zconf_lineno(); - - *last_entry_ptr = menu; - last_entry_ptr = &menu->next; - current_entry = menu; - if (sym) - menu_add_symbol(P_SYMBOL, sym, NULL); -} - -struct menu *menu_add_menu(void) -{ - last_entry_ptr = ¤t_entry->list; - current_menu = current_entry; - return current_menu; -} - -void menu_end_menu(void) -{ - last_entry_ptr = ¤t_menu->next; - current_menu = current_menu->parent; -} - -/* - * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running - * without modules - */ -static struct expr *rewrite_m(struct expr *e) -{ - if (!e) - return e; - - switch (e->type) { - case E_NOT: - e->left.expr = rewrite_m(e->left.expr); - break; - case E_OR: - case E_AND: - e->left.expr = rewrite_m(e->left.expr); - e->right.expr = rewrite_m(e->right.expr); - break; - case E_SYMBOL: - /* change 'm' into 'm' && MODULES */ - if (e->left.sym == &symbol_mod) - return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); - break; - default: - break; - } - return e; -} - -void menu_add_dep(struct expr *dep) -{ - current_entry->dep = expr_alloc_and(current_entry->dep, dep); -} - -void menu_set_type(int type) -{ - struct symbol *sym = current_entry->sym; - - if (sym->type == type) - return; - if (sym->type == S_UNKNOWN) { - sym->type = type; - return; - } - menu_warn(current_entry, - "ignoring type redefinition of '%s' from '%s' to '%s'", - sym->name ? sym->name : "<choice>", - sym_type_name(sym->type), sym_type_name(type)); -} - -static struct property *menu_add_prop(enum prop_type type, struct expr *expr, - struct expr *dep) -{ - struct property *prop; - - prop = xmalloc(sizeof(*prop)); - memset(prop, 0, sizeof(*prop)); - prop->type = type; - prop->file = current_file; - prop->lineno = zconf_lineno(); - prop->menu = current_entry; - prop->expr = expr; - prop->visible.expr = dep; - - /* append property to the prop list of symbol */ - if (current_entry->sym) { - struct property **propp; - - for (propp = ¤t_entry->sym->prop; - *propp; - propp = &(*propp)->next) - ; - *propp = prop; - } - - return prop; -} - -struct property *menu_add_prompt(enum prop_type type, char *prompt, - struct expr *dep) -{ - struct property *prop = menu_add_prop(type, NULL, dep); - - if (isspace(*prompt)) { - prop_warn(prop, "leading whitespace ignored"); - while (isspace(*prompt)) - prompt++; - } - if (current_entry->prompt) - prop_warn(prop, "prompt redefined"); - - /* Apply all upper menus' visibilities to actual prompts. */ - if (type == P_PROMPT) { - struct menu *menu = current_entry; - - while ((menu = menu->parent) != NULL) { - struct expr *dup_expr; - - if (!menu->visibility) - continue; - /* - * Do not add a reference to the menu's visibility - * expression but use a copy of it. Otherwise the - * expression reduction functions will modify - * expressions that have multiple references which - * can cause unwanted side effects. - */ - dup_expr = expr_copy(menu->visibility); - - prop->visible.expr = expr_alloc_and(prop->visible.expr, - dup_expr); - } - } - - current_entry->prompt = prop; - prop->text = prompt; - - return prop; -} - -void menu_add_visibility(struct expr *expr) -{ - current_entry->visibility = expr_alloc_and(current_entry->visibility, - expr); -} - -void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) -{ - menu_add_prop(type, expr, dep); -} - -void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) -{ - menu_add_prop(type, expr_alloc_symbol(sym), dep); -} - -static int menu_validate_number(struct symbol *sym, struct symbol *sym2) -{ - return sym2->type == S_INT || sym2->type == S_HEX || - (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); -} - -static void sym_check_prop(struct symbol *sym) -{ - struct property *prop; - struct symbol *sym2; - char *use; - - for (prop = sym->prop; prop; prop = prop->next) { - switch (prop->type) { - case P_DEFAULT: - if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && - prop->expr->type != E_SYMBOL) - prop_warn(prop, - "default for config symbol '%s'" - " must be a single symbol", sym->name); - if (prop->expr->type != E_SYMBOL) - break; - sym2 = prop_get_symbol(prop); - if (sym->type == S_HEX || sym->type == S_INT) { - if (!menu_validate_number(sym, sym2)) - prop_warn(prop, - "'%s': number is invalid", - sym->name); - } - if (sym_is_choice(sym)) { - struct property *choice_prop = - sym_get_choice_prop(sym2); - - if (!choice_prop || - prop_get_symbol(choice_prop) != sym) - prop_warn(prop, - "choice default symbol '%s' is not contained in the choice", - sym2->name); - } - break; - case P_SELECT: - case P_IMPLY: - use = prop->type == P_SELECT ? "select" : "imply"; - sym2 = prop_get_symbol(prop); - if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) - prop_warn(prop, - "config symbol '%s' uses %s, but is " - "not bool or tristate", sym->name, use); - else if (sym2->type != S_UNKNOWN && - sym2->type != S_BOOLEAN && - sym2->type != S_TRISTATE) - prop_warn(prop, - "'%s' has wrong type. '%s' only " - "accept arguments of bool and " - "tristate type", sym2->name, use); - break; - case P_RANGE: - if (sym->type != S_INT && sym->type != S_HEX) - prop_warn(prop, "range is only allowed " - "for int or hex symbols"); - if (!menu_validate_number(sym, prop->expr->left.sym) || - !menu_validate_number(sym, prop->expr->right.sym)) - prop_warn(prop, "range is invalid"); - break; - default: - ; - } - } -} - -void menu_finalize(struct menu *parent) -{ - struct menu *menu, *last_menu; - struct symbol *sym; - struct property *prop; - struct expr *parentdep, *basedep, *dep, *dep2, **ep; - - sym = parent->sym; - if (parent->list) { - /* - * This menu node has children. We (recursively) process them - * and propagate parent dependencies before moving on. - */ - - if (sym && sym_is_choice(sym)) { - if (sym->type == S_UNKNOWN) { - /* find the first choice value to find out choice type */ - current_entry = parent; - for (menu = parent->list; menu; menu = menu->next) { - if (menu->sym && menu->sym->type != S_UNKNOWN) { - menu_set_type(menu->sym->type); - break; - } - } - } - /* set the type of the remaining choice values */ - for (menu = parent->list; menu; menu = menu->next) { - current_entry = menu; - if (menu->sym && menu->sym->type == S_UNKNOWN) - menu_set_type(sym->type); - } - - /* - * Use the choice itself as the parent dependency of - * the contained items. This turns the mode of the - * choice into an upper bound on the visibility of the - * choice value symbols. - */ - parentdep = expr_alloc_symbol(sym); - } else { - /* Menu node for 'menu', 'if' */ - parentdep = parent->dep; - } - - /* For each child menu node... */ - for (menu = parent->list; menu; menu = menu->next) { - /* - * Propagate parent dependencies to the child menu - * node, also rewriting and simplifying expressions - */ - basedep = rewrite_m(menu->dep); - basedep = expr_transform(basedep); - basedep = expr_alloc_and(expr_copy(parentdep), basedep); - basedep = expr_eliminate_dups(basedep); - menu->dep = basedep; - - if (menu->sym) - /* - * Note: For symbols, all prompts are included - * too in the symbol's own property list - */ - prop = menu->sym->prop; - else - /* - * For non-symbol menu nodes, we just need to - * handle the prompt - */ - prop = menu->prompt; - - /* For each property... */ - for (; prop; prop = prop->next) { - if (prop->menu != menu) - /* - * Two possibilities: - * - * 1. The property lacks dependencies - * and so isn't location-specific, - * e.g. an 'option' - * - * 2. The property belongs to a symbol - * defined in multiple locations and - * is from some other location. It - * will be handled there in that - * case. - * - * Skip the property. - */ - continue; - - /* - * Propagate parent dependencies to the - * property's condition, rewriting and - * simplifying expressions at the same time - */ - dep = rewrite_m(prop->visible.expr); - dep = expr_transform(dep); - dep = expr_alloc_and(expr_copy(basedep), dep); - dep = expr_eliminate_dups(dep); - if (menu->sym && menu->sym->type != S_TRISTATE) - dep = expr_trans_bool(dep); - prop->visible.expr = dep; - - /* - * Handle selects and implies, which modify the - * dependencies of the selected/implied symbol - */ - if (prop->type == P_SELECT) { - struct symbol *es = prop_get_symbol(prop); - es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, - expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); - } else if (prop->type == P_IMPLY) { - struct symbol *es = prop_get_symbol(prop); - es->implied.expr = expr_alloc_or(es->implied.expr, - expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); - } - } - } - - if (sym && sym_is_choice(sym)) - expr_free(parentdep); - - /* - * Recursively process children in the same fashion before - * moving on - */ - for (menu = parent->list; menu; menu = menu->next) - menu_finalize(menu); - } else if (sym) { - /* - * Automatic submenu creation. If sym is a symbol and A, B, C, - * ... are consecutive items (symbols, menus, ifs, etc.) that - * all depend on sym, then the following menu structure is - * created: - * - * sym - * +-A - * +-B - * +-C - * ... - * - * This also works recursively, giving the following structure - * if A is a symbol and B depends on A: - * - * sym - * +-A - * | +-B - * +-C - * ... - */ - - basedep = parent->prompt ? parent->prompt->visible.expr : NULL; - basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); - basedep = expr_eliminate_dups(expr_transform(basedep)); - - /* Examine consecutive elements after sym */ - last_menu = NULL; - for (menu = parent->next; menu; menu = menu->next) { - dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; - if (!expr_contains_symbol(dep, sym)) - /* No dependency, quit */ - break; - if (expr_depends_symbol(dep, sym)) - /* Absolute dependency, put in submenu */ - goto next; - - /* - * Also consider it a dependency on sym if our - * dependencies contain sym and are a "superset" of - * sym's dependencies, e.g. '(sym || Q) && R' when sym - * depends on R. - * - * Note that 'R' might be from an enclosing menu or if, - * making this a more common case than it might seem. - */ - dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); - dep = expr_eliminate_dups(expr_transform(dep)); - dep2 = expr_copy(basedep); - expr_eliminate_eq(&dep, &dep2); - expr_free(dep); - if (!expr_is_yes(dep2)) { - /* Not superset, quit */ - expr_free(dep2); - break; - } - /* Superset, put in submenu */ - expr_free(dep2); - next: - menu_finalize(menu); - menu->parent = parent; - last_menu = menu; - } - expr_free(basedep); - if (last_menu) { - parent->list = parent->next; - parent->next = last_menu->next; - last_menu->next = NULL; - } - - sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep); - } - for (menu = parent->list; menu; menu = menu->next) { - if (sym && sym_is_choice(sym) && - menu->sym && !sym_is_choice_value(menu->sym)) { - current_entry = menu; - menu->sym->flags |= SYMBOL_CHOICEVAL; - if (!menu->prompt) - menu_warn(menu, "choice value must have a prompt"); - for (prop = menu->sym->prop; prop; prop = prop->next) { - if (prop->type == P_DEFAULT) - prop_warn(prop, "defaults for choice " - "values not supported"); - if (prop->menu == menu) - continue; - if (prop->type == P_PROMPT && - prop->menu->parent->sym != sym) - prop_warn(prop, "choice value used outside its choice group"); - } - /* Non-tristate choice values of tristate choices must - * depend on the choice being set to Y. The choice - * values' dependencies were propagated to their - * properties above, so the change here must be re- - * propagated. - */ - if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { - basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); - menu->dep = expr_alloc_and(basedep, menu->dep); - for (prop = menu->sym->prop; prop; prop = prop->next) { - if (prop->menu != menu) - continue; - prop->visible.expr = expr_alloc_and(expr_copy(basedep), - prop->visible.expr); - } - } - menu_add_symbol(P_CHOICE, sym, NULL); - prop = sym_get_choice_prop(sym); - for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) - ; - *ep = expr_alloc_one(E_LIST, NULL); - (*ep)->right.sym = menu->sym; - } - - /* - * This code serves two purposes: - * - * (1) Flattening 'if' blocks, which do not specify a submenu - * and only add dependencies. - * - * (Automatic submenu creation might still create a submenu - * from an 'if' before this code runs.) - * - * (2) "Undoing" any automatic submenus created earlier below - * promptless symbols. - * - * Before: - * - * A - * if ... (or promptless symbol) - * +-B - * +-C - * D - * - * After: - * - * A - * if ... (or promptless symbol) - * B - * C - * D - */ - if (menu->list && (!menu->prompt || !menu->prompt->text)) { - for (last_menu = menu->list; ; last_menu = last_menu->next) { - last_menu->parent = parent; - if (!last_menu->next) - break; - } - last_menu->next = menu->next; - menu->next = menu->list; - menu->list = NULL; - } - } - - if (sym && !(sym->flags & SYMBOL_WARNED)) { - if (sym->type == S_UNKNOWN) - menu_warn(parent, "config symbol defined without type"); - - if (sym_is_choice(sym) && !parent->prompt) - menu_warn(parent, "choice must have a prompt"); - - /* Check properties connected to this symbol */ - sym_check_prop(sym); - sym->flags |= SYMBOL_WARNED; - } - - /* - * For non-optional choices, add a reverse dependency (corresponding to - * a select) of '<visibility> && m'. This prevents the user from - * setting the choice mode to 'n' when the choice is visible. - * - * This would also work for non-choice symbols, but only non-optional - * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented - * as a type of symbol. - */ - if (sym && !sym_is_optional(sym) && parent->prompt) { - sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, - expr_alloc_and(parent->prompt->visible.expr, - expr_alloc_symbol(&symbol_mod))); - } -} - -bool menu_has_prompt(struct menu *menu) -{ - if (!menu->prompt) - return false; - return true; -} - -/* - * Determine if a menu is empty. - * A menu is considered empty if it contains no or only - * invisible entries. - */ -bool menu_is_empty(struct menu *menu) -{ - struct menu *child; - - for (child = menu->list; child; child = child->next) { - if (menu_is_visible(child)) - return(false); - } - return(true); -} - -bool menu_is_visible(struct menu *menu) -{ - struct menu *child; - struct symbol *sym; - tristate visible; - - if (!menu->prompt) - return false; - - if (menu->visibility) { - if (expr_calc_value(menu->visibility) == no) - return false; - } - - sym = menu->sym; - if (sym) { - sym_calc_value(sym); - visible = menu->prompt->visible.tri; - } else - visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); - - if (visible != no) - return true; - - if (!sym || sym_get_tristate_value(menu->sym) == no) - return false; - - for (child = menu->list; child; child = child->next) { - if (menu_is_visible(child)) { - if (sym) - sym->flags |= SYMBOL_DEF_USER; - return true; - } - } - - return false; -} - -const char *menu_get_prompt(struct menu *menu) -{ - if (menu->prompt) - return menu->prompt->text; - else if (menu->sym) - return menu->sym->name; - return NULL; -} - -struct menu *menu_get_parent_menu(struct menu *menu) -{ - enum prop_type type; - - for (; menu != &rootmenu; menu = menu->parent) { - type = menu->prompt ? menu->prompt->type : 0; - if (type == P_MENU) - break; - } - return menu; -} - -bool menu_has_help(struct menu *menu) -{ - return menu->help != NULL; -} - -const char *menu_get_help(struct menu *menu) -{ - if (menu->help) - return menu->help; - else - return ""; -} - -static void get_def_str(struct gstr *r, struct menu *menu) -{ - str_printf(r, "Defined at %s:%d\n", - menu->file->name, menu->lineno); -} - -static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix) -{ - if (!expr_is_yes(expr)) { - str_append(r, prefix); - expr_gstr_print(expr, r); - str_append(r, "\n"); - } -} - -static void get_prompt_str(struct gstr *r, struct property *prop, - struct list_head *head) -{ - int i, j; - struct menu *submenu[8], *menu, *location = NULL; - struct jump_key *jump = NULL; - - str_printf(r, " Prompt: %s\n", prop->text); - - get_dep_str(r, prop->menu->dep, " Depends on: "); - /* - * Most prompts in Linux have visibility that exactly matches their - * dependencies. For these, we print only the dependencies to improve - * readability. However, prompts with inline "if" expressions and - * prompts with a parent that has a "visible if" expression have - * differing dependencies and visibility. In these rare cases, we - * print both. - */ - if (!expr_eq(prop->menu->dep, prop->visible.expr)) - get_dep_str(r, prop->visible.expr, " Visible if: "); - - menu = prop->menu; - for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { - submenu[i++] = menu; - if (location == NULL && menu_is_visible(menu)) - location = menu; - } - if (head && location) { - jump = xmalloc(sizeof(struct jump_key)); - - jump->target = location; - - if (list_empty(head)) - jump->index = 0; - else - jump->index = list_entry(head->prev, struct jump_key, - entries)->index + 1; - - list_add_tail(&jump->entries, head); - } - - str_printf(r, " Location:\n"); - for (j = 4; --i >= 0; j += 2) { - menu = submenu[i]; - if (jump && menu == location) - jump->offset = strlen(r->s); - str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu)); - if (menu->sym) { - str_printf(r, " (%s [=%s])", menu->sym->name ? - menu->sym->name : "<choice>", - sym_get_string_value(menu->sym)); - } - str_append(r, "\n"); - } -} - -static void get_symbol_props_str(struct gstr *r, struct symbol *sym, - enum prop_type tok, const char *prefix) -{ - bool hit = false; - struct property *prop; - - for_all_properties(sym, prop, tok) { - if (!hit) { - str_append(r, prefix); - hit = true; - } else - str_printf(r, " && "); - expr_gstr_print(prop->expr, r); - } - if (hit) - str_append(r, "\n"); -} - -/* - * head is optional and may be NULL - */ -static void get_symbol_str(struct gstr *r, struct symbol *sym, - struct list_head *head) -{ - struct property *prop; - - if (sym && sym->name) { - str_printf(r, "Symbol: %s [=%s]\n", sym->name, - sym_get_string_value(sym)); - str_printf(r, "Type : %s\n", sym_type_name(sym->type)); - if (sym->type == S_INT || sym->type == S_HEX) { - prop = sym_get_range_prop(sym); - if (prop) { - str_printf(r, "Range : "); - expr_gstr_print(prop->expr, r); - str_append(r, "\n"); - } - } - } - - /* Print the definitions with prompts before the ones without */ - for_all_properties(sym, prop, P_SYMBOL) { - if (prop->menu->prompt) { - get_def_str(r, prop->menu); - get_prompt_str(r, prop->menu->prompt, head); - } - } - - for_all_properties(sym, prop, P_SYMBOL) { - if (!prop->menu->prompt) { - get_def_str(r, prop->menu); - get_dep_str(r, prop->menu->dep, " Depends on: "); - } - } - - get_symbol_props_str(r, sym, P_SELECT, "Selects: "); - if (sym->rev_dep.expr) { - expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n"); - expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n"); - expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n"); - } - - get_symbol_props_str(r, sym, P_IMPLY, "Implies: "); - if (sym->implied.expr) { - expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n"); - expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n"); - expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n"); - } - - str_append(r, "\n\n"); -} - -struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head) -{ - struct symbol *sym; - struct gstr res = str_new(); - int i; - - for (i = 0; sym_arr && (sym = sym_arr[i]); i++) - get_symbol_str(&res, sym, head); - if (!i) - str_append(&res, "No matches found.\n"); - return res; -} - - -void menu_get_ext_help(struct menu *menu, struct gstr *help) -{ - struct symbol *sym = menu->sym; - const char *help_text = nohelp_text; - - if (menu_has_help(menu)) { - if (sym->name) - str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); - help_text = menu_get_help(menu); - } - str_printf(help, "%s\n", help_text); - if (sym) - get_symbol_str(help, sym, NULL); -} diff --git a/tools/kconfig/parser.y b/tools/kconfig/parser.y deleted file mode 100644 index 2af7ce4..0000000 --- a/tools/kconfig/parser.y +++ /dev/null @@ -1,716 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ -%{ - -#include <ctype.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> - -#include "lkc.h" -#include "internal.h" - -#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) - -#define PRINTD 0x0001 -#define DEBUG_PARSE 0x0002 - -int cdebug = PRINTD; - -static void yyerror(const char *err); -static void zconfprint(const char *err, ...); -static void zconf_error(const char *err, ...); -static bool zconf_endtoken(const char *tokenname, - const char *expected_tokenname); - -struct symbol *symbol_hash[SYMBOL_HASHSIZE]; - -struct menu *current_menu, *current_entry; - -%} - -%union -{ - char *string; - struct symbol *symbol; - struct expr *expr; - struct menu *menu; - enum symbol_type type; - enum variable_flavor flavor; -} - -%token <string> T_HELPTEXT -%token <string> T_WORD -%token <string> T_WORD_QUOTE -%token T_BOOL -%token T_CHOICE -%token T_CLOSE_PAREN -%token T_COLON_EQUAL -%token T_COMMENT -%token T_CONFIG -%token T_DEFAULT -%token T_DEF_BOOL -%token T_DEF_TRISTATE -%token T_DEPENDS -%token T_ENDCHOICE -%token T_ENDIF -%token T_ENDMENU -%token T_HELP -%token T_HEX -%token T_IF -%token T_IMPLY -%token T_INT -%token T_MAINMENU -%token T_MENU -%token T_MENUCONFIG -%token T_MODULES -%token T_ON -%token T_OPEN_PAREN -%token T_OPTIONAL -%token T_PLUS_EQUAL -%token T_PROMPT -%token T_RANGE -%token T_SELECT -%token T_SOURCE -%token T_STRING -%token T_TRISTATE -%token T_VISIBLE -%token T_EOL -%token <string> T_ASSIGN_VAL - -%left T_OR -%left T_AND -%left T_EQUAL T_UNEQUAL -%left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL -%nonassoc T_NOT - -%type <symbol> nonconst_symbol -%type <symbol> symbol -%type <type> type logic_type default -%type <expr> expr -%type <expr> if_expr -%type <string> end -%type <menu> if_entry menu_entry choice_entry -%type <string> word_opt assign_val -%type <flavor> assign_op - -%destructor { - fprintf(stderr, "%s:%d: missing end statement for this entry\n", - $$->file->name, $$->lineno); - if (current_menu == $$) - menu_end_menu(); -} if_entry menu_entry choice_entry - -%% -input: mainmenu_stmt stmt_list | stmt_list; - -/* mainmenu entry */ - -mainmenu_stmt: T_MAINMENU T_WORD_QUOTE T_EOL -{ - menu_add_prompt(P_MENU, $2, NULL); -}; - -stmt_list: - /* empty */ - | stmt_list assignment_stmt - | stmt_list choice_stmt - | stmt_list comment_stmt - | stmt_list config_stmt - | stmt_list if_stmt - | stmt_list menu_stmt - | stmt_list menuconfig_stmt - | stmt_list source_stmt - | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } - | stmt_list error T_EOL { zconf_error("invalid statement"); } -; - -stmt_list_in_choice: - /* empty */ - | stmt_list_in_choice comment_stmt - | stmt_list_in_choice config_stmt - | stmt_list_in_choice if_stmt_in_choice - | stmt_list_in_choice error T_EOL { zconf_error("invalid statement"); } -; - -/* config/menuconfig entry */ - -config_entry_start: T_CONFIG nonconst_symbol T_EOL -{ - $2->flags |= SYMBOL_OPTIONAL; - menu_add_entry($2); - printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name); -}; - -config_stmt: config_entry_start config_option_list -{ - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); -}; - -menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL -{ - $2->flags |= SYMBOL_OPTIONAL; - menu_add_entry($2); - printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name); -}; - -menuconfig_stmt: menuconfig_entry_start config_option_list -{ - if (current_entry->prompt) - current_entry->prompt->type = P_MENU; - else - zconfprint("warning: menuconfig statement without prompt"); - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); -}; - -config_option_list: - /* empty */ - | config_option_list config_option - | config_option_list depends - | config_option_list help -; - -config_option: type prompt_stmt_opt T_EOL -{ - menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), - $1); -}; - -config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL -{ - menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); -}; - -config_option: default expr if_expr T_EOL -{ - menu_add_expr(P_DEFAULT, $2, $3); - if ($1 != S_UNKNOWN) - menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:default(%u)\n", - zconf_curname(), zconf_lineno(), - $1); -}; - -config_option: T_SELECT nonconst_symbol if_expr T_EOL -{ - menu_add_symbol(P_SELECT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_IMPLY nonconst_symbol if_expr T_EOL -{ - menu_add_symbol(P_IMPLY, $2, $3); - printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_RANGE symbol symbol if_expr T_EOL -{ - menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); - printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_MODULES T_EOL -{ - if (modules_sym) - zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'", - current_entry->sym->name, modules_sym->name); - modules_sym = current_entry->sym; -}; - -/* choice entry */ - -choice: T_CHOICE word_opt T_EOL -{ - struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); - sym->flags |= SYMBOL_NO_WRITE; - menu_add_entry(sym); - menu_add_expr(P_CHOICE, NULL, NULL); - free($2); - printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); -}; - -choice_entry: choice choice_option_list -{ - $$ = menu_add_menu(); -}; - -choice_end: end -{ - if (zconf_endtoken($1, "choice")) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); - } -}; - -choice_stmt: choice_entry stmt_list_in_choice choice_end -; - -choice_option_list: - /* empty */ - | choice_option_list choice_option - | choice_option_list depends - | choice_option_list help -; - -choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL -{ - menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); -}; - -choice_option: logic_type prompt_stmt_opt T_EOL -{ - menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), $1); -}; - -choice_option: T_OPTIONAL T_EOL -{ - current_entry->sym->flags |= SYMBOL_OPTIONAL; - printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); -}; - -choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL -{ - menu_add_symbol(P_DEFAULT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:default\n", - zconf_curname(), zconf_lineno()); -}; - -type: - logic_type - | T_INT { $$ = S_INT; } - | T_HEX { $$ = S_HEX; } - | T_STRING { $$ = S_STRING; } - -logic_type: - T_BOOL { $$ = S_BOOLEAN; } - | T_TRISTATE { $$ = S_TRISTATE; } - -default: - T_DEFAULT { $$ = S_UNKNOWN; } - | T_DEF_BOOL { $$ = S_BOOLEAN; } - | T_DEF_TRISTATE { $$ = S_TRISTATE; } - -/* if entry */ - -if_entry: T_IF expr T_EOL -{ - printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); - menu_add_entry(NULL); - menu_add_dep($2); - $$ = menu_add_menu(); -}; - -if_end: end -{ - if (zconf_endtoken($1, "if")) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); - } -}; - -if_stmt: if_entry stmt_list if_end -; - -if_stmt_in_choice: if_entry stmt_list_in_choice if_end -; - -/* menu entry */ - -menu: T_MENU T_WORD_QUOTE T_EOL -{ - menu_add_entry(NULL); - menu_add_prompt(P_MENU, $2, NULL); - printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); -}; - -menu_entry: menu menu_option_list -{ - $$ = menu_add_menu(); -}; - -menu_end: end -{ - if (zconf_endtoken($1, "menu")) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); - } -}; - -menu_stmt: menu_entry stmt_list menu_end -; - -menu_option_list: - /* empty */ - | menu_option_list visible - | menu_option_list depends -; - -source_stmt: T_SOURCE T_WORD_QUOTE T_EOL -{ - printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); - zconf_nextfile($2); - free($2); -}; - -/* comment entry */ - -comment: T_COMMENT T_WORD_QUOTE T_EOL -{ - menu_add_entry(NULL); - menu_add_prompt(P_COMMENT, $2, NULL); - printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); -}; - -comment_stmt: comment comment_option_list -; - -comment_option_list: - /* empty */ - | comment_option_list depends -; - -/* help option */ - -help_start: T_HELP T_EOL -{ - printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); - zconf_starthelp(); -}; - -help: help_start T_HELPTEXT -{ - if (current_entry->help) { - free(current_entry->help); - zconfprint("warning: '%s' defined with more than one help text -- only the last one will be used", - current_entry->sym->name ?: "<choice>"); - } - - /* Is the help text empty or all whitespace? */ - if ($2[strspn($2, " \f\n\r\t\v")] == '\0') - zconfprint("warning: '%s' defined with blank help text", - current_entry->sym->name ?: "<choice>"); - - current_entry->help = $2; -}; - -/* depends option */ - -depends: T_DEPENDS T_ON expr T_EOL -{ - menu_add_dep($3); - printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); -}; - -/* visibility option */ -visible: T_VISIBLE if_expr T_EOL -{ - menu_add_visibility($2); -}; - -/* prompt statement */ - -prompt_stmt_opt: - /* empty */ - | T_WORD_QUOTE if_expr -{ - menu_add_prompt(P_PROMPT, $1, $2); -}; - -end: T_ENDMENU T_EOL { $$ = "menu"; } - | T_ENDCHOICE T_EOL { $$ = "choice"; } - | T_ENDIF T_EOL { $$ = "if"; } -; - -if_expr: /* empty */ { $$ = NULL; } - | T_IF expr { $$ = $2; } -; - -expr: symbol { $$ = expr_alloc_symbol($1); } - | symbol T_LESS symbol { $$ = expr_alloc_comp(E_LTH, $1, $3); } - | symbol T_LESS_EQUAL symbol { $$ = expr_alloc_comp(E_LEQ, $1, $3); } - | symbol T_GREATER symbol { $$ = expr_alloc_comp(E_GTH, $1, $3); } - | symbol T_GREATER_EQUAL symbol { $$ = expr_alloc_comp(E_GEQ, $1, $3); } - | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } - | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } - | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } - | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } - | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } - | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } -; - -/* For symbol definitions, selects, etc., where quotes are not accepted */ -nonconst_symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }; - -symbol: nonconst_symbol - | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } -; - -word_opt: /* empty */ { $$ = NULL; } - | T_WORD - -/* assignment statement */ - -assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); } - -assign_op: - T_EQUAL { $$ = VAR_RECURSIVE; } - | T_COLON_EQUAL { $$ = VAR_SIMPLE; } - | T_PLUS_EQUAL { $$ = VAR_APPEND; } -; - -assign_val: - /* empty */ { $$ = xstrdup(""); }; - | T_ASSIGN_VAL -; - -%% - -void conf_parse(const char *name) -{ - struct symbol *sym; - int i; - - zconf_initscan(name); - - _menu_init(); - - if (getenv("ZCONF_DEBUG")) - yydebug = 1; - yyparse(); - - /* Variables are expanded in the parse phase. We can free them here. */ - variable_all_del(); - - if (yynerrs) - exit(1); - if (!modules_sym) - modules_sym = sym_find( "n" ); - - if (!menu_has_prompt(&rootmenu)) { - current_entry = &rootmenu; - menu_add_prompt(P_MENU, "Main menu", NULL); - } - - menu_finalize(&rootmenu); - for_all_symbols(i, sym) { - if (sym_check_deps(sym)) - yynerrs++; - } - if (yynerrs) - exit(1); - conf_set_changed(true); -} - -static bool zconf_endtoken(const char *tokenname, - const char *expected_tokenname) -{ - if (strcmp(tokenname, expected_tokenname)) { - zconf_error("unexpected '%s' within %s block", - tokenname, expected_tokenname); - yynerrs++; - return false; - } - if (current_menu->file != current_file) { - zconf_error("'%s' in different file than '%s'", - tokenname, expected_tokenname); - fprintf(stderr, "%s:%d: location of the '%s'\n", - current_menu->file->name, current_menu->lineno, - expected_tokenname); - yynerrs++; - return false; - } - return true; -} - -static void zconfprint(const char *err, ...) -{ - va_list ap; - - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); - va_start(ap, err); - vfprintf(stderr, err, ap); - va_end(ap); - fprintf(stderr, "\n"); -} - -static void zconf_error(const char *err, ...) -{ - va_list ap; - - yynerrs++; - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); - va_start(ap, err); - vfprintf(stderr, err, ap); - va_end(ap); - fprintf(stderr, "\n"); -} - -static void yyerror(const char *err) -{ - fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); -} - -static void print_quoted_string(FILE *out, const char *str) -{ - const char *p; - int len; - - putc('"', out); - while ((p = strchr(str, '"'))) { - len = p - str; - if (len) - fprintf(out, "%.*s", len, str); - fputs("\\\"", out); - str = p + 1; - } - fputs(str, out); - putc('"', out); -} - -static void print_symbol(FILE *out, struct menu *menu) -{ - struct symbol *sym = menu->sym; - struct property *prop; - - if (sym_is_choice(sym)) - fprintf(out, "\nchoice\n"); - else - fprintf(out, "\nconfig %s\n", sym->name); - switch (sym->type) { - case S_BOOLEAN: - fputs(" bool\n", out); - break; - case S_TRISTATE: - fputs(" tristate\n", out); - break; - case S_STRING: - fputs(" string\n", out); - break; - case S_INT: - fputs(" integer\n", out); - break; - case S_HEX: - fputs(" hex\n", out); - break; - default: - fputs(" ???\n", out); - break; - } - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->menu != menu) - continue; - switch (prop->type) { - case P_PROMPT: - fputs(" prompt ", out); - print_quoted_string(out, prop->text); - if (!expr_is_yes(prop->visible.expr)) { - fputs(" if ", out); - expr_fprint(prop->visible.expr, out); - } - fputc('\n', out); - break; - case P_DEFAULT: - fputs( " default ", out); - expr_fprint(prop->expr, out); - if (!expr_is_yes(prop->visible.expr)) { - fputs(" if ", out); - expr_fprint(prop->visible.expr, out); - } - fputc('\n', out); - break; - case P_CHOICE: - fputs(" #choice value\n", out); - break; - case P_SELECT: - fputs( " select ", out); - expr_fprint(prop->expr, out); - fputc('\n', out); - break; - case P_IMPLY: - fputs( " imply ", out); - expr_fprint(prop->expr, out); - fputc('\n', out); - break; - case P_RANGE: - fputs( " range ", out); - expr_fprint(prop->expr, out); - fputc('\n', out); - break; - case P_MENU: - fputs( " menu ", out); - print_quoted_string(out, prop->text); - fputc('\n', out); - break; - case P_SYMBOL: - fputs( " symbol ", out); - fprintf(out, "%s\n", prop->menu->sym->name); - break; - default: - fprintf(out, " unknown prop %d!\n", prop->type); - break; - } - } - if (menu->help) { - int len = strlen(menu->help); - while (menu->help[--len] == '\n') - menu->help[len] = 0; - fprintf(out, " help\n%s\n", menu->help); - } -} - -void zconfdump(FILE *out) -{ - struct property *prop; - struct symbol *sym; - struct menu *menu; - - menu = rootmenu.list; - while (menu) { - if ((sym = menu->sym)) - print_symbol(out, menu); - else if ((prop = menu->prompt)) { - switch (prop->type) { - case P_COMMENT: - fputs("\ncomment ", out); - print_quoted_string(out, prop->text); - fputs("\n", out); - break; - case P_MENU: - fputs("\nmenu ", out); - print_quoted_string(out, prop->text); - fputs("\n", out); - break; - default: - ; - } - if (!expr_is_yes(prop->visible.expr)) { - fputs(" depends ", out); - expr_fprint(prop->visible.expr, out); - fputc('\n', out); - } - } - - if (menu->list) - menu = menu->list; - else if (menu->next) - menu = menu->next; - else while ((menu = menu->parent)) { - if (menu->prompt && menu->prompt->type == P_MENU) - fputs("\nendmenu\n", out); - if (menu->next) { - menu = menu->next; - break; - } - } - } -} diff --git a/tools/kconfig/preprocess.c b/tools/kconfig/preprocess.c deleted file mode 100644 index 748da57..0000000 --- a/tools/kconfig/preprocess.c +++ /dev/null @@ -1,574 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com> - -#include <ctype.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "list.h" -#include "lkc.h" - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -static char *expand_string_with_args(const char *in, int argc, char *argv[]); -static char *expand_string(const char *in); - -static void __attribute__((noreturn)) pperror(const char *format, ...) -{ - va_list ap; - - fprintf(stderr, "%s:%d: ", current_file->name, yylineno); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - fprintf(stderr, "\n"); - - exit(1); -} - -/* - * Environment variables - */ -static LIST_HEAD(env_list); - -struct env { - char *name; - char *value; - struct list_head node; -}; - -static void env_add(const char *name, const char *value) -{ - struct env *e; - - e = xmalloc(sizeof(*e)); - e->name = xstrdup(name); - e->value = xstrdup(value); - - list_add_tail(&e->node, &env_list); -} - -static void env_del(struct env *e) -{ - list_del(&e->node); - free(e->name); - free(e->value); - free(e); -} - -/* The returned pointer must be freed when done */ -static char *env_expand(const char *name) -{ - struct env *e; - const char *value; - - if (!*name) - return NULL; - - list_for_each_entry(e, &env_list, node) { - if (!strcmp(name, e->name)) - return xstrdup(e->value); - } - - value = getenv(name); - if (!value) - return NULL; - - /* - * We need to remember all referenced environment variables. - * They will be written out to include/config/auto.conf.cmd - */ - env_add(name, value); - - return xstrdup(value); -} - -void env_write_dep(FILE *f, const char *autoconfig_name) -{ - struct env *e, *tmp; - - list_for_each_entry_safe(e, tmp, &env_list, node) { - fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value); - fprintf(f, "%s: FORCE\n", autoconfig_name); - fprintf(f, "endif\n"); - env_del(e); - } -} - -/* - * Built-in functions - */ -struct function { - const char *name; - unsigned int min_args; - unsigned int max_args; - char *(*func)(int argc, char *argv[]); -}; - -static char *do_error_if(int argc, char *argv[]) -{ - if (!strcmp(argv[0], "y")) - pperror("%s", argv[1]); - - return xstrdup(""); -} - -static char *do_filename(int argc, char *argv[]) -{ - return xstrdup(current_file->name); -} - -static char *do_info(int argc, char *argv[]) -{ - printf("%s\n", argv[0]); - - return xstrdup(""); -} - -static char *do_lineno(int argc, char *argv[]) -{ - char buf[16]; - - sprintf(buf, "%d", yylineno); - - return xstrdup(buf); -} - -static char *do_shell(int argc, char *argv[]) -{ - FILE *p; - char buf[4096]; - char *cmd; - size_t nread; - int i; - - cmd = argv[0]; - - p = popen(cmd, "r"); - if (!p) { - perror(cmd); - exit(1); - } - - nread = fread(buf, 1, sizeof(buf), p); - if (nread == sizeof(buf)) - nread--; - - /* remove trailing new lines */ - while (nread > 0 && buf[nread - 1] == '\n') - nread--; - - buf[nread] = 0; - - /* replace a new line with a space */ - for (i = 0; i < nread; i++) { - if (buf[i] == '\n') - buf[i] = ' '; - } - - if (pclose(p) == -1) { - perror(cmd); - exit(1); - } - - return xstrdup(buf); -} - -static char *do_warning_if(int argc, char *argv[]) -{ - if (!strcmp(argv[0], "y")) - fprintf(stderr, "%s:%d: %s\n", - current_file->name, yylineno, argv[1]); - - return xstrdup(""); -} - -static const struct function function_table[] = { - /* Name MIN MAX Function */ - { "error-if", 2, 2, do_error_if }, - { "filename", 0, 0, do_filename }, - { "info", 1, 1, do_info }, - { "lineno", 0, 0, do_lineno }, - { "shell", 1, 1, do_shell }, - { "warning-if", 2, 2, do_warning_if }, -}; - -#define FUNCTION_MAX_ARGS 16 - -static char *function_expand(const char *name, int argc, char *argv[]) -{ - const struct function *f; - int i; - - for (i = 0; i < ARRAY_SIZE(function_table); i++) { - f = &function_table[i]; - if (strcmp(f->name, name)) - continue; - - if (argc < f->min_args) - pperror("too few function arguments passed to '%s'", - name); - - if (argc > f->max_args) - pperror("too many function arguments passed to '%s'", - name); - - return f->func(argc, argv); - } - - return NULL; -} - -/* - * Variables (and user-defined functions) - */ -static LIST_HEAD(variable_list); - -struct variable { - char *name; - char *value; - enum variable_flavor flavor; - int exp_count; - struct list_head node; -}; - -static struct variable *variable_lookup(const char *name) -{ - struct variable *v; - - list_for_each_entry(v, &variable_list, node) { - if (!strcmp(name, v->name)) - return v; - } - - return NULL; -} - -static char *variable_expand(const char *name, int argc, char *argv[]) -{ - struct variable *v; - char *res; - - v = variable_lookup(name); - if (!v) - return NULL; - - if (argc == 0 && v->exp_count) - pperror("Recursive variable '%s' references itself (eventually)", - name); - - if (v->exp_count > 1000) - pperror("Too deep recursive expansion"); - - v->exp_count++; - - if (v->flavor == VAR_RECURSIVE) - res = expand_string_with_args(v->value, argc, argv); - else - res = xstrdup(v->value); - - v->exp_count--; - - return res; -} - -void variable_add(const char *name, const char *value, - enum variable_flavor flavor) -{ - struct variable *v; - char *new_value; - bool append = false; - - v = variable_lookup(name); - if (v) { - /* For defined variables, += inherits the existing flavor */ - if (flavor == VAR_APPEND) { - flavor = v->flavor; - append = true; - } else { - free(v->value); - } - } else { - /* For undefined variables, += assumes the recursive flavor */ - if (flavor == VAR_APPEND) - flavor = VAR_RECURSIVE; - - v = xmalloc(sizeof(*v)); - v->name = xstrdup(name); - v->exp_count = 0; - list_add_tail(&v->node, &variable_list); - } - - v->flavor = flavor; - - if (flavor == VAR_SIMPLE) - new_value = expand_string(value); - else - new_value = xstrdup(value); - - if (append) { - v->value = xrealloc(v->value, - strlen(v->value) + strlen(new_value) + 2); - strcat(v->value, " "); - strcat(v->value, new_value); - free(new_value); - } else { - v->value = new_value; - } -} - -static void variable_del(struct variable *v) -{ - list_del(&v->node); - free(v->name); - free(v->value); - free(v); -} - -void variable_all_del(void) -{ - struct variable *v, *tmp; - - list_for_each_entry_safe(v, tmp, &variable_list, node) - variable_del(v); -} - -/* - * Evaluate a clause with arguments. argc/argv are arguments from the upper - * function call. - * - * Returned string must be freed when done - */ -static char *eval_clause(const char *str, size_t len, int argc, char *argv[]) -{ - char *tmp, *name, *res, *endptr, *prev, *p; - int new_argc = 0; - char *new_argv[FUNCTION_MAX_ARGS]; - int nest = 0; - int i; - unsigned long n; - - tmp = xstrndup(str, len); - - /* - * If variable name is '1', '2', etc. It is generally an argument - * from a user-function call (i.e. local-scope variable). If not - * available, then look-up global-scope variables. - */ - n = strtoul(tmp, &endptr, 10); - if (!*endptr && n > 0 && n <= argc) { - res = xstrdup(argv[n - 1]); - goto free_tmp; - } - - prev = p = tmp; - - /* - * Split into tokens - * The function name and arguments are separated by a comma. - * For example, if the function call is like this: - * $(foo,$(x),$(y)) - * - * The input string for this helper should be: - * foo,$(x),$(y) - * - * and split into: - * new_argv[0] = 'foo' - * new_argv[1] = '$(x)' - * new_argv[2] = '$(y)' - */ - while (*p) { - if (nest == 0 && *p == ',') { - *p = 0; - if (new_argc >= FUNCTION_MAX_ARGS) - pperror("too many function arguments"); - new_argv[new_argc++] = prev; - prev = p + 1; - } else if (*p == '(') { - nest++; - } else if (*p == ')') { - nest--; - } - - p++; - } - new_argv[new_argc++] = prev; - - /* - * Shift arguments - * new_argv[0] represents a function name or a variable name. Put it - * into 'name', then shift the rest of the arguments. This simplifies - * 'const' handling. - */ - name = expand_string_with_args(new_argv[0], argc, argv); - new_argc--; - for (i = 0; i < new_argc; i++) - new_argv[i] = expand_string_with_args(new_argv[i + 1], - argc, argv); - - /* Search for variables */ - res = variable_expand(name, new_argc, new_argv); - if (res) - goto free; - - /* Look for built-in functions */ - res = function_expand(name, new_argc, new_argv); - if (res) - goto free; - - /* Last, try environment variable */ - if (new_argc == 0) { - res = env_expand(name); - if (res) - goto free; - } - - res = xstrdup(""); -free: - for (i = 0; i < new_argc; i++) - free(new_argv[i]); - free(name); -free_tmp: - free(tmp); - - return res; -} - -/* - * Expand a string that follows '$' - * - * For example, if the input string is - * ($(FOO)$($(BAR)))$(BAZ) - * this helper evaluates - * $($(FOO)$($(BAR))) - * and returns a new string containing the expansion (note that the string is - * recursively expanded), also advancing 'str' to point to the next character - * after the corresponding closing parenthesis, in this case, *str will be - * $(BAR) - */ -static char *expand_dollar_with_args(const char **str, int argc, char *argv[]) -{ - const char *p = *str; - const char *q; - int nest = 0; - - /* - * In Kconfig, variable/function references always start with "$(". - * Neither single-letter variables as in $A nor curly braces as in ${CC} - * are supported. '$' not followed by '(' loses its special meaning. - */ - if (*p != '(') { - *str = p; - return xstrdup("$"); - } - - p++; - q = p; - while (*q) { - if (*q == '(') { - nest++; - } else if (*q == ')') { - if (nest-- == 0) - break; - } - q++; - } - - if (!*q) - pperror("unterminated reference to '%s': missing ')'", p); - - /* Advance 'str' to after the expanded initial portion of the string */ - *str = q + 1; - - return eval_clause(p, q - p, argc, argv); -} - -char *expand_dollar(const char **str) -{ - return expand_dollar_with_args(str, 0, NULL); -} - -static char *__expand_string(const char **str, bool (*is_end)(char c), - int argc, char *argv[]) -{ - const char *in, *p; - char *expansion, *out; - size_t in_len, out_len; - - out = xmalloc(1); - *out = 0; - out_len = 1; - - p = in = *str; - - while (1) { - if (*p == '$') { - in_len = p - in; - p++; - expansion = expand_dollar_with_args(&p, argc, argv); - out_len += in_len + strlen(expansion); - out = xrealloc(out, out_len); - strncat(out, in, in_len); - strcat(out, expansion); - free(expansion); - in = p; - continue; - } - - if (is_end(*p)) - break; - - p++; - } - - in_len = p - in; - out_len += in_len; - out = xrealloc(out, out_len); - strncat(out, in, in_len); - - /* Advance 'str' to the end character */ - *str = p; - - return out; -} - -static bool is_end_of_str(char c) -{ - return !c; -} - -/* - * Expand variables and functions in the given string. Undefined variables - * expand to an empty string. - * The returned string must be freed when done. - */ -static char *expand_string_with_args(const char *in, int argc, char *argv[]) -{ - return __expand_string(&in, is_end_of_str, argc, argv); -} - -static char *expand_string(const char *in) -{ - return expand_string_with_args(in, 0, NULL); -} - -static bool is_end_of_token(char c) -{ - return !(isalnum(c) || c == '_' || c == '-'); -} - -/* - * Expand variables in a token. The parsing stops when a token separater - * (in most cases, it is a whitespace) is encountered. 'str' is updated to - * point to the next character. - * - * The returned string must be freed when done. - */ -char *expand_one_token(const char **str) -{ - return __expand_string(str, is_end_of_token, 0, NULL); -} diff --git a/tools/kconfig/symbol.c b/tools/kconfig/symbol.c deleted file mode 100644 index 0572330..0000000 --- a/tools/kconfig/symbol.c +++ /dev/null @@ -1,1270 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - */ - -#include <sys/types.h> -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <regex.h> - -#include "lkc.h" - -struct symbol symbol_yes = { - .name = "y", - .curr = { "y", yes }, - .flags = SYMBOL_CONST|SYMBOL_VALID, -}; - -struct symbol symbol_mod = { - .name = "m", - .curr = { "m", mod }, - .flags = SYMBOL_CONST|SYMBOL_VALID, -}; - -struct symbol symbol_no = { - .name = "n", - .curr = { "n", no }, - .flags = SYMBOL_CONST|SYMBOL_VALID, -}; - -static struct symbol symbol_empty = { - .name = "", - .curr = { "", no }, - .flags = SYMBOL_VALID, -}; - -struct symbol *modules_sym; -static tristate modules_val; - -enum symbol_type sym_get_type(struct symbol *sym) -{ - enum symbol_type type = sym->type; - - if (type == S_TRISTATE) { - if (sym_is_choice_value(sym) && sym->visible == yes) - type = S_BOOLEAN; - else if (modules_val == no) - type = S_BOOLEAN; - } - return type; -} - -const char *sym_type_name(enum symbol_type type) -{ - switch (type) { - case S_BOOLEAN: - return "bool"; - case S_TRISTATE: - return "tristate"; - case S_INT: - return "integer"; - case S_HEX: - return "hex"; - case S_STRING: - return "string"; - case S_UNKNOWN: - return "unknown"; - } - return "???"; -} - -struct property *sym_get_choice_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_choices(sym, prop) - return prop; - return NULL; -} - -static struct property *sym_get_default_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_defaults(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri != no) - return prop; - } - return NULL; -} - -struct property *sym_get_range_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_properties(sym, prop, P_RANGE) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri != no) - return prop; - } - return NULL; -} - -static long long sym_get_range_val(struct symbol *sym, int base) -{ - sym_calc_value(sym); - switch (sym->type) { - case S_INT: - base = 10; - break; - case S_HEX: - base = 16; - break; - default: - break; - } - return strtoll(sym->curr.val, NULL, base); -} - -static void sym_validate_range(struct symbol *sym) -{ - struct property *prop; - int base; - long long val, val2; - char str[64]; - - switch (sym->type) { - case S_INT: - base = 10; - break; - case S_HEX: - base = 16; - break; - default: - return; - } - prop = sym_get_range_prop(sym); - if (!prop) - return; - val = strtoll(sym->curr.val, NULL, base); - val2 = sym_get_range_val(prop->expr->left.sym, base); - if (val >= val2) { - val2 = sym_get_range_val(prop->expr->right.sym, base); - if (val <= val2) - return; - } - if (sym->type == S_INT) - sprintf(str, "%lld", val2); - else - sprintf(str, "0x%llx", val2); - sym->curr.val = xstrdup(str); -} - -static void sym_set_changed(struct symbol *sym) -{ - struct property *prop; - - sym->flags |= SYMBOL_CHANGED; - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->menu) - prop->menu->flags |= MENU_CHANGED; - } -} - -static void sym_set_all_changed(void) -{ - struct symbol *sym; - int i; - - for_all_symbols(i, sym) - sym_set_changed(sym); -} - -static void sym_calc_visibility(struct symbol *sym) -{ - struct property *prop; - struct symbol *choice_sym = NULL; - tristate tri; - - /* any prompt visible? */ - tri = no; - - if (sym_is_choice_value(sym)) - choice_sym = prop_get_symbol(sym_get_choice_prop(sym)); - - for_all_prompts(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - /* - * Tristate choice_values with visibility 'mod' are - * not visible if the corresponding choice's value is - * 'yes'. - */ - if (choice_sym && sym->type == S_TRISTATE && - prop->visible.tri == mod && choice_sym->curr.tri == yes) - prop->visible.tri = no; - - tri = EXPR_OR(tri, prop->visible.tri); - } - if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) - tri = yes; - if (sym->visible != tri) { - sym->visible = tri; - sym_set_changed(sym); - } - if (sym_is_choice_value(sym)) - return; - /* defaulting to "yes" if no explicit "depends on" are given */ - tri = yes; - if (sym->dir_dep.expr) - tri = expr_calc_value(sym->dir_dep.expr); - if (tri == mod && sym_get_type(sym) == S_BOOLEAN) - tri = yes; - if (sym->dir_dep.tri != tri) { - sym->dir_dep.tri = tri; - sym_set_changed(sym); - } - tri = no; - if (sym->rev_dep.expr) - tri = expr_calc_value(sym->rev_dep.expr); - if (tri == mod && sym_get_type(sym) == S_BOOLEAN) - tri = yes; - if (sym->rev_dep.tri != tri) { - sym->rev_dep.tri = tri; - sym_set_changed(sym); - } - tri = no; - if (sym->implied.expr) - tri = expr_calc_value(sym->implied.expr); - if (tri == mod && sym_get_type(sym) == S_BOOLEAN) - tri = yes; - if (sym->implied.tri != tri) { - sym->implied.tri = tri; - sym_set_changed(sym); - } -} - -/* - * Find the default symbol for a choice. - * First try the default values for the choice symbol - * Next locate the first visible choice value - * Return NULL if none was found - */ -struct symbol *sym_choice_default(struct symbol *sym) -{ - struct symbol *def_sym; - struct property *prop; - struct expr *e; - - /* any of the defaults visible? */ - for_all_defaults(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri == no) - continue; - def_sym = prop_get_symbol(prop); - if (def_sym->visible != no) - return def_sym; - } - - /* just get the first visible value */ - prop = sym_get_choice_prop(sym); - expr_list_for_each_sym(prop->expr, e, def_sym) - if (def_sym->visible != no) - return def_sym; - - /* failed to locate any defaults */ - return NULL; -} - -static struct symbol *sym_calc_choice(struct symbol *sym) -{ - struct symbol *def_sym; - struct property *prop; - struct expr *e; - int flags; - - /* first calculate all choice values' visibilities */ - flags = sym->flags; - prop = sym_get_choice_prop(sym); - expr_list_for_each_sym(prop->expr, e, def_sym) { - sym_calc_visibility(def_sym); - if (def_sym->visible != no) - flags &= def_sym->flags; - } - - sym->flags &= flags | ~SYMBOL_DEF_USER; - - /* is the user choice visible? */ - def_sym = sym->def[S_DEF_USER].val; - if (def_sym && def_sym->visible != no) - return def_sym; - - def_sym = sym_choice_default(sym); - - if (def_sym == NULL) - /* no choice? reset tristate value */ - sym->curr.tri = no; - - return def_sym; -} - -static void sym_warn_unmet_dep(struct symbol *sym) -{ - struct gstr gs = str_new(); - - str_printf(&gs, - "\nWARNING: unmet direct dependencies detected for %s\n", - sym->name); - str_printf(&gs, - " Depends on [%c]: ", - sym->dir_dep.tri == mod ? 'm' : 'n'); - expr_gstr_print(sym->dir_dep.expr, &gs); - str_printf(&gs, "\n"); - - expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes, - " Selected by [y]:\n"); - expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod, - " Selected by [m]:\n"); - - fputs(str_get(&gs), stderr); -} - -void sym_calc_value(struct symbol *sym) -{ - struct symbol_value newval, oldval; - struct property *prop; - struct expr *e; - - if (!sym) - return; - - if (sym->flags & SYMBOL_VALID) - return; - - if (sym_is_choice_value(sym) && - sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { - sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; - prop = sym_get_choice_prop(sym); - sym_calc_value(prop_get_symbol(prop)); - } - - sym->flags |= SYMBOL_VALID; - - oldval = sym->curr; - - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - newval = symbol_empty.curr; - break; - case S_BOOLEAN: - case S_TRISTATE: - newval = symbol_no.curr; - break; - default: - sym->curr.val = sym->name; - sym->curr.tri = no; - return; - } - sym->flags &= ~SYMBOL_WRITE; - - sym_calc_visibility(sym); - - if (sym->visible != no) - sym->flags |= SYMBOL_WRITE; - - /* set default if recursively called */ - sym->curr = newval; - - switch (sym_get_type(sym)) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym_is_choice_value(sym) && sym->visible == yes) { - prop = sym_get_choice_prop(sym); - newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; - } else { - if (sym->visible != no) { - /* if the symbol is visible use the user value - * if available, otherwise try the default value - */ - if (sym_has_value(sym)) { - newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, - sym->visible); - goto calc_newval; - } - } - if (sym->rev_dep.tri != no) - sym->flags |= SYMBOL_WRITE; - if (!sym_is_choice(sym)) { - prop = sym_get_default_prop(sym); - if (prop) { - newval.tri = EXPR_AND(expr_calc_value(prop->expr), - prop->visible.tri); - if (newval.tri != no) - sym->flags |= SYMBOL_WRITE; - } - if (sym->implied.tri != no) { - sym->flags |= SYMBOL_WRITE; - newval.tri = EXPR_OR(newval.tri, sym->implied.tri); - newval.tri = EXPR_AND(newval.tri, - sym->dir_dep.tri); - } - } - calc_newval: - if (sym->dir_dep.tri < sym->rev_dep.tri) - sym_warn_unmet_dep(sym); - newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); - } - if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) - newval.tri = yes; - break; - case S_STRING: - case S_HEX: - case S_INT: - if (sym->visible != no && sym_has_value(sym)) { - newval.val = sym->def[S_DEF_USER].val; - break; - } - prop = sym_get_default_prop(sym); - if (prop) { - struct symbol *ds = prop_get_symbol(prop); - if (ds) { - sym->flags |= SYMBOL_WRITE; - sym_calc_value(ds); - newval.val = ds->curr.val; - } - } - break; - default: - ; - } - - sym->curr = newval; - if (sym_is_choice(sym) && newval.tri == yes) - sym->curr.val = sym_calc_choice(sym); - sym_validate_range(sym); - - if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { - sym_set_changed(sym); - if (modules_sym == sym) { - sym_set_all_changed(); - modules_val = modules_sym->curr.tri; - } - } - - if (sym_is_choice(sym)) { - struct symbol *choice_sym; - - prop = sym_get_choice_prop(sym); - expr_list_for_each_sym(prop->expr, e, choice_sym) { - if ((sym->flags & SYMBOL_WRITE) && - choice_sym->visible != no) - choice_sym->flags |= SYMBOL_WRITE; - if (sym->flags & SYMBOL_CHANGED) - sym_set_changed(choice_sym); - } - } - - if (sym->flags & SYMBOL_NO_WRITE) - sym->flags &= ~SYMBOL_WRITE; - - if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) - set_all_choice_values(sym); -} - -void sym_clear_all_valid(void) -{ - struct symbol *sym; - int i; - - for_all_symbols(i, sym) - sym->flags &= ~SYMBOL_VALID; - conf_set_changed(true); - sym_calc_value(modules_sym); -} - -bool sym_tristate_within_range(struct symbol *sym, tristate val) -{ - int type = sym_get_type(sym); - - if (sym->visible == no) - return false; - - if (type != S_BOOLEAN && type != S_TRISTATE) - return false; - - if (type == S_BOOLEAN && val == mod) - return false; - if (sym->visible <= sym->rev_dep.tri) - return false; - if (sym_is_choice_value(sym) && sym->visible == yes) - return val == yes; - return val >= sym->rev_dep.tri && val <= sym->visible; -} - -bool sym_set_tristate_value(struct symbol *sym, tristate val) -{ - tristate oldval = sym_get_tristate_value(sym); - - if (oldval != val && !sym_tristate_within_range(sym, val)) - return false; - - if (!(sym->flags & SYMBOL_DEF_USER)) { - sym->flags |= SYMBOL_DEF_USER; - sym_set_changed(sym); - } - /* - * setting a choice value also resets the new flag of the choice - * symbol and all other choice values. - */ - if (sym_is_choice_value(sym) && val == yes) { - struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - struct property *prop; - struct expr *e; - - cs->def[S_DEF_USER].val = sym; - cs->flags |= SYMBOL_DEF_USER; - prop = sym_get_choice_prop(cs); - for (e = prop->expr; e; e = e->left.expr) { - if (e->right.sym->visible != no) - e->right.sym->flags |= SYMBOL_DEF_USER; - } - } - - sym->def[S_DEF_USER].tri = val; - if (oldval != val) - sym_clear_all_valid(); - - return true; -} - -tristate sym_toggle_tristate_value(struct symbol *sym) -{ - tristate oldval, newval; - - oldval = newval = sym_get_tristate_value(sym); - do { - switch (newval) { - case no: - newval = mod; - break; - case mod: - newval = yes; - break; - case yes: - newval = no; - break; - } - if (sym_set_tristate_value(sym, newval)) - break; - } while (oldval != newval); - return newval; -} - -bool sym_string_valid(struct symbol *sym, const char *str) -{ - signed char ch; - - switch (sym->type) { - case S_STRING: - return true; - case S_INT: - ch = *str++; - if (ch == '-') - ch = *str++; - if (!isdigit(ch)) - return false; - if (ch == '0' && *str != 0) - return false; - while ((ch = *str++)) { - if (!isdigit(ch)) - return false; - } - return true; - case S_HEX: - if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) - str += 2; - ch = *str++; - do { - if (!isxdigit(ch)) - return false; - } while ((ch = *str++)); - return true; - case S_BOOLEAN: - case S_TRISTATE: - switch (str[0]) { - case 'y': case 'Y': - case 'm': case 'M': - case 'n': case 'N': - return true; - } - return false; - default: - return false; - } -} - -bool sym_string_within_range(struct symbol *sym, const char *str) -{ - struct property *prop; - long long val; - - switch (sym->type) { - case S_STRING: - return sym_string_valid(sym, str); - case S_INT: - if (!sym_string_valid(sym, str)) - return false; - prop = sym_get_range_prop(sym); - if (!prop) - return true; - val = strtoll(str, NULL, 10); - return val >= sym_get_range_val(prop->expr->left.sym, 10) && - val <= sym_get_range_val(prop->expr->right.sym, 10); - case S_HEX: - if (!sym_string_valid(sym, str)) - return false; - prop = sym_get_range_prop(sym); - if (!prop) - return true; - val = strtoll(str, NULL, 16); - return val >= sym_get_range_val(prop->expr->left.sym, 16) && - val <= sym_get_range_val(prop->expr->right.sym, 16); - case S_BOOLEAN: - case S_TRISTATE: - switch (str[0]) { - case 'y': case 'Y': - return sym_tristate_within_range(sym, yes); - case 'm': case 'M': - return sym_tristate_within_range(sym, mod); - case 'n': case 'N': - return sym_tristate_within_range(sym, no); - } - return false; - default: - return false; - } -} - -bool sym_set_string_value(struct symbol *sym, const char *newval) -{ - const char *oldval; - char *val; - int size; - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - switch (newval[0]) { - case 'y': case 'Y': - return sym_set_tristate_value(sym, yes); - case 'm': case 'M': - return sym_set_tristate_value(sym, mod); - case 'n': case 'N': - return sym_set_tristate_value(sym, no); - } - return false; - default: - ; - } - - if (!sym_string_within_range(sym, newval)) - return false; - - if (!(sym->flags & SYMBOL_DEF_USER)) { - sym->flags |= SYMBOL_DEF_USER; - sym_set_changed(sym); - } - - oldval = sym->def[S_DEF_USER].val; - size = strlen(newval) + 1; - if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { - size += 2; - sym->def[S_DEF_USER].val = val = xmalloc(size); - *val++ = '0'; - *val++ = 'x'; - } else if (!oldval || strcmp(oldval, newval)) - sym->def[S_DEF_USER].val = val = xmalloc(size); - else - return true; - - strcpy(val, newval); - free((void *)oldval); - sym_clear_all_valid(); - - return true; -} - -/* - * Find the default value associated to a symbol. - * For tristate symbol handle the modules=n case - * in which case "m" becomes "y". - * If the symbol does not have any default then fallback - * to the fixed default values. - */ -const char *sym_get_string_default(struct symbol *sym) -{ - struct property *prop; - struct symbol *ds; - const char *str; - tristate val; - - sym_calc_visibility(sym); - sym_calc_value(modules_sym); - val = symbol_no.curr.tri; - str = symbol_empty.curr.val; - - /* If symbol has a default value look it up */ - prop = sym_get_default_prop(sym); - if (prop != NULL) { - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - /* The visibility may limit the value from yes => mod */ - val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); - break; - default: - /* - * The following fails to handle the situation - * where a default value is further limited by - * the valid range. - */ - ds = prop_get_symbol(prop); - if (ds != NULL) { - sym_calc_value(ds); - str = (const char *)ds->curr.val; - } - } - } - - /* Handle select statements */ - val = EXPR_OR(val, sym->rev_dep.tri); - - /* transpose mod to yes if modules are not enabled */ - if (val == mod) - if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) - val = yes; - - /* transpose mod to yes if type is bool */ - if (sym->type == S_BOOLEAN && val == mod) - val = yes; - - /* adjust the default value if this symbol is implied by another */ - if (val < sym->implied.tri) - val = sym->implied.tri; - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - switch (val) { - case no: return "n"; - case mod: return "m"; - case yes: return "y"; - } - case S_INT: - case S_HEX: - return str; - case S_STRING: - return str; - case S_UNKNOWN: - break; - } - return ""; -} - -const char *sym_get_string_value(struct symbol *sym) -{ - tristate val; - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - val = sym_get_tristate_value(sym); - switch (val) { - case no: - return "n"; - case mod: - sym_calc_value(modules_sym); - return (modules_sym->curr.tri == no) ? "n" : "m"; - case yes: - return "y"; - } - break; - default: - ; - } - return (const char *)sym->curr.val; -} - -bool sym_is_changeable(struct symbol *sym) -{ - return sym->visible > sym->rev_dep.tri; -} - -static unsigned strhash(const char *s) -{ - /* fnv32 hash */ - unsigned hash = 2166136261U; - for (; *s; s++) - hash = (hash ^ *s) * 0x01000193; - return hash; -} - -struct symbol *sym_lookup(const char *name, int flags) -{ - struct symbol *symbol; - char *new_name; - int hash; - - if (name) { - if (name[0] && !name[1]) { - switch (name[0]) { - case 'y': return &symbol_yes; - case 'm': return &symbol_mod; - case 'n': return &symbol_no; - } - } - hash = strhash(name) % SYMBOL_HASHSIZE; - - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (symbol->name && - !strcmp(symbol->name, name) && - (flags ? symbol->flags & flags - : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) - return symbol; - } - new_name = xstrdup(name); - } else { - new_name = NULL; - hash = 0; - } - - symbol = xmalloc(sizeof(*symbol)); - memset(symbol, 0, sizeof(*symbol)); - symbol->name = new_name; - symbol->type = S_UNKNOWN; - symbol->flags = flags; - - symbol->next = symbol_hash[hash]; - symbol_hash[hash] = symbol; - - return symbol; -} - -struct symbol *sym_find(const char *name) -{ - struct symbol *symbol = NULL; - int hash = 0; - - if (!name) - return NULL; - - if (name[0] && !name[1]) { - switch (name[0]) { - case 'y': return &symbol_yes; - case 'm': return &symbol_mod; - case 'n': return &symbol_no; - } - } - hash = strhash(name) % SYMBOL_HASHSIZE; - - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (symbol->name && - !strcmp(symbol->name, name) && - !(symbol->flags & SYMBOL_CONST)) - break; - } - - return symbol; -} - -struct sym_match { - struct symbol *sym; - off_t so, eo; -}; - -/* Compare matched symbols as thus: - * - first, symbols that match exactly - * - then, alphabetical sort - */ -static int sym_rel_comp(const void *sym1, const void *sym2) -{ - const struct sym_match *s1 = sym1; - const struct sym_match *s2 = sym2; - int exact1, exact2; - - /* Exact match: - * - if matched length on symbol s1 is the length of that symbol, - * then this symbol should come first; - * - if matched length on symbol s2 is the length of that symbol, - * then this symbol should come first. - * Note: since the search can be a regexp, both symbols may match - * exactly; if this is the case, we can't decide which comes first, - * and we fallback to sorting alphabetically. - */ - exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); - exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); - if (exact1 && !exact2) - return -1; - if (!exact1 && exact2) - return 1; - - /* As a fallback, sort symbols alphabetically */ - return strcmp(s1->sym->name, s2->sym->name); -} - -struct symbol **sym_re_search(const char *pattern) -{ - struct symbol *sym, **sym_arr = NULL; - struct sym_match *sym_match_arr = NULL; - int i, cnt, size; - regex_t re; - regmatch_t match[1]; - - cnt = size = 0; - /* Skip if empty */ - if (strlen(pattern) == 0) - return NULL; - if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) - return NULL; - - for_all_symbols(i, sym) { - if (sym->flags & SYMBOL_CONST || !sym->name) - continue; - if (regexec(&re, sym->name, 1, match, 0)) - continue; - if (cnt >= size) { - void *tmp; - size += 16; - tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); - if (!tmp) - goto sym_re_search_free; - sym_match_arr = tmp; - } - sym_calc_value(sym); - /* As regexec returned 0, we know we have a match, so - * we can use match[0].rm_[se]o without further checks - */ - sym_match_arr[cnt].so = match[0].rm_so; - sym_match_arr[cnt].eo = match[0].rm_eo; - sym_match_arr[cnt++].sym = sym; - } - if (sym_match_arr) { - qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); - sym_arr = malloc((cnt+1) * sizeof(struct symbol *)); - if (!sym_arr) - goto sym_re_search_free; - for (i = 0; i < cnt; i++) - sym_arr[i] = sym_match_arr[i].sym; - sym_arr[cnt] = NULL; - } -sym_re_search_free: - /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ - free(sym_match_arr); - regfree(&re); - - return sym_arr; -} - -/* - * When we check for recursive dependencies we use a stack to save - * current state so we can print out relevant info to user. - * The entries are located on the call stack so no need to free memory. - * Note insert() remove() must always match to properly clear the stack. - */ -static struct dep_stack { - struct dep_stack *prev, *next; - struct symbol *sym; - struct property *prop; - struct expr **expr; -} *check_top; - -static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) -{ - memset(stack, 0, sizeof(*stack)); - if (check_top) - check_top->next = stack; - stack->prev = check_top; - stack->sym = sym; - check_top = stack; -} - -static void dep_stack_remove(void) -{ - check_top = check_top->prev; - if (check_top) - check_top->next = NULL; -} - -/* - * Called when we have detected a recursive dependency. - * check_top point to the top of the stact so we use - * the ->prev pointer to locate the bottom of the stack. - */ -static void sym_check_print_recursive(struct symbol *last_sym) -{ - struct dep_stack *stack; - struct symbol *sym, *next_sym; - struct menu *menu = NULL; - struct property *prop; - struct dep_stack cv_stack; - - if (sym_is_choice_value(last_sym)) { - dep_stack_insert(&cv_stack, last_sym); - last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); - } - - for (stack = check_top; stack != NULL; stack = stack->prev) - if (stack->sym == last_sym) - break; - if (!stack) { - fprintf(stderr, "unexpected recursive dependency error\n"); - return; - } - - for (; stack; stack = stack->next) { - sym = stack->sym; - next_sym = stack->next ? stack->next->sym : last_sym; - prop = stack->prop; - if (prop == NULL) - prop = stack->sym->prop; - - /* for choice values find the menu entry (used below) */ - if (sym_is_choice(sym) || sym_is_choice_value(sym)) { - for (prop = sym->prop; prop; prop = prop->next) { - menu = prop->menu; - if (prop->menu) - break; - } - } - if (stack->sym == last_sym) - fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", - prop->file->name, prop->lineno); - - if (sym_is_choice(sym)) { - fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", - menu->file->name, menu->lineno, - sym->name ? sym->name : "<choice>", - next_sym->name ? next_sym->name : "<choice>"); - } else if (sym_is_choice_value(sym)) { - fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", - menu->file->name, menu->lineno, - sym->name ? sym->name : "<choice>", - next_sym->name ? next_sym->name : "<choice>"); - } else if (stack->expr == &sym->dir_dep.expr) { - fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "<choice>", - next_sym->name ? next_sym->name : "<choice>"); - } else if (stack->expr == &sym->rev_dep.expr) { - fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "<choice>", - next_sym->name ? next_sym->name : "<choice>"); - } else if (stack->expr == &sym->implied.expr) { - fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "<choice>", - next_sym->name ? next_sym->name : "<choice>"); - } else if (stack->expr) { - fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "<choice>", - prop_get_type_name(prop->type), - next_sym->name ? next_sym->name : "<choice>"); - } else { - fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "<choice>", - prop_get_type_name(prop->type), - next_sym->name ? next_sym->name : "<choice>"); - } - } - - fprintf(stderr, - "For a resolution refer to Documentation/kbuild/kconfig-language.rst\n" - "subsection \"Kconfig recursive dependency limitations\"\n" - "\n"); - - if (check_top == &cv_stack) - dep_stack_remove(); -} - -static struct symbol *sym_check_expr_deps(struct expr *e) -{ - struct symbol *sym; - - if (!e) - return NULL; - switch (e->type) { - case E_OR: - case E_AND: - sym = sym_check_expr_deps(e->left.expr); - if (sym) - return sym; - return sym_check_expr_deps(e->right.expr); - case E_NOT: - return sym_check_expr_deps(e->left.expr); - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - sym = sym_check_deps(e->left.sym); - if (sym) - return sym; - return sym_check_deps(e->right.sym); - case E_SYMBOL: - return sym_check_deps(e->left.sym); - default: - break; - } - fprintf(stderr, "Oops! How to check %d?\n", e->type); - return NULL; -} - -/* return NULL when dependencies are OK */ -static struct symbol *sym_check_sym_deps(struct symbol *sym) -{ - struct symbol *sym2; - struct property *prop; - struct dep_stack stack; - - dep_stack_insert(&stack, sym); - - stack.expr = &sym->dir_dep.expr; - sym2 = sym_check_expr_deps(sym->dir_dep.expr); - if (sym2) - goto out; - - stack.expr = &sym->rev_dep.expr; - sym2 = sym_check_expr_deps(sym->rev_dep.expr); - if (sym2) - goto out; - - stack.expr = &sym->implied.expr; - sym2 = sym_check_expr_deps(sym->implied.expr); - if (sym2) - goto out; - - stack.expr = NULL; - - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->type == P_CHOICE || prop->type == P_SELECT || - prop->type == P_IMPLY) - continue; - stack.prop = prop; - sym2 = sym_check_expr_deps(prop->visible.expr); - if (sym2) - break; - if (prop->type != P_DEFAULT || sym_is_choice(sym)) - continue; - stack.expr = &prop->expr; - sym2 = sym_check_expr_deps(prop->expr); - if (sym2) - break; - stack.expr = NULL; - } - -out: - dep_stack_remove(); - - return sym2; -} - -static struct symbol *sym_check_choice_deps(struct symbol *choice) -{ - struct symbol *sym, *sym2; - struct property *prop; - struct expr *e; - struct dep_stack stack; - - dep_stack_insert(&stack, choice); - - prop = sym_get_choice_prop(choice); - expr_list_for_each_sym(prop->expr, e, sym) - sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); - - choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); - sym2 = sym_check_sym_deps(choice); - choice->flags &= ~SYMBOL_CHECK; - if (sym2) - goto out; - - expr_list_for_each_sym(prop->expr, e, sym) { - sym2 = sym_check_sym_deps(sym); - if (sym2) - break; - } -out: - expr_list_for_each_sym(prop->expr, e, sym) - sym->flags &= ~SYMBOL_CHECK; - - if (sym2 && sym_is_choice_value(sym2) && - prop_get_symbol(sym_get_choice_prop(sym2)) == choice) - sym2 = choice; - - dep_stack_remove(); - - return sym2; -} - -struct symbol *sym_check_deps(struct symbol *sym) -{ - struct symbol *sym2; - struct property *prop; - - if (sym->flags & SYMBOL_CHECK) { - sym_check_print_recursive(sym); - return sym; - } - if (sym->flags & SYMBOL_CHECKED) - return NULL; - - if (sym_is_choice_value(sym)) { - struct dep_stack stack; - - /* for choice groups start the check with main choice symbol */ - dep_stack_insert(&stack, sym); - prop = sym_get_choice_prop(sym); - sym2 = sym_check_deps(prop_get_symbol(prop)); - dep_stack_remove(); - } else if (sym_is_choice(sym)) { - sym2 = sym_check_choice_deps(sym); - } else { - sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); - sym2 = sym_check_sym_deps(sym); - sym->flags &= ~SYMBOL_CHECK; - } - - return sym2; -} - -struct symbol *prop_get_symbol(struct property *prop) -{ - if (prop->expr && (prop->expr->type == E_SYMBOL || - prop->expr->type == E_LIST)) - return prop->expr->left.sym; - return NULL; -} - -const char *prop_get_type_name(enum prop_type type) -{ - switch (type) { - case P_PROMPT: - return "prompt"; - case P_COMMENT: - return "comment"; - case P_MENU: - return "menu"; - case P_DEFAULT: - return "default"; - case P_CHOICE: - return "choice"; - case P_SELECT: - return "select"; - case P_IMPLY: - return "imply"; - case P_RANGE: - return "range"; - case P_SYMBOL: - return "symbol"; - case P_UNKNOWN: - break; - } - return "unknown"; -} diff --git a/tools/kconfig/util.c b/tools/kconfig/util.c deleted file mode 100644 index b78f114..0000000 --- a/tools/kconfig/util.c +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org> - * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org> - */ - -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include "lkc.h" - -/* file already present in list? If not add it */ -struct file *file_lookup(const char *name) -{ - struct file *file; - - for (file = file_list; file; file = file->next) { - if (!strcmp(name, file->name)) { - return file; - } - } - - file = xmalloc(sizeof(*file)); - memset(file, 0, sizeof(*file)); - file->name = xstrdup(name); - file->next = file_list; - file_list = file; - return file; -} - -/* Allocate initial growable string */ -struct gstr str_new(void) -{ - struct gstr gs; - gs.s = xmalloc(sizeof(char) * 64); - gs.len = 64; - gs.max_width = 0; - strcpy(gs.s, "\0"); - return gs; -} - -/* Free storage for growable string */ -void str_free(struct gstr *gs) -{ - if (gs->s) - free(gs->s); - gs->s = NULL; - gs->len = 0; -} - -/* Append to growable string */ -void str_append(struct gstr *gs, const char *s) -{ - size_t l; - if (s) { - l = strlen(gs->s) + strlen(s) + 1; - if (l > gs->len) { - gs->s = xrealloc(gs->s, l); - gs->len = l; - } - strcat(gs->s, s); - } -} - -/* Append printf formatted string to growable string */ -void str_printf(struct gstr *gs, const char *fmt, ...) -{ - va_list ap; - char s[10000]; /* big enough... */ - va_start(ap, fmt); - vsnprintf(s, sizeof(s), fmt, ap); - str_append(gs, s); - va_end(ap); -} - -/* Retrieve value of growable string */ -char *str_get(struct gstr *gs) -{ - return gs->s; -} - -void *xmalloc(size_t size) -{ - void *p = malloc(size); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -void *xcalloc(size_t nmemb, size_t size) -{ - void *p = calloc(nmemb, size); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -void *xrealloc(void *p, size_t size) -{ - p = realloc(p, size); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -char *xstrdup(const char *s) -{ - char *p; - - p = strdup(s); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -char *xstrndup(const char *s, size_t n) -{ - char *p; - - p = strndup(s, n); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} diff --git a/tools/make_iso.bzl b/tools/make_iso.bzl new file mode 100644 index 0000000..5ff20f5 --- /dev/null +++ b/tools/make_iso.bzl @@ -0,0 +1,41 @@ +def make_iso(**kwargs): + _make_iso( + image = "{name}.iso".format(**kwargs), + **kwargs + ) + +def _make_iso_impl(ctx): + inputs = [] + outputs = [] + args = ctx.actions.args() + + args.add("-c", ctx.file.bootloader.path) + inputs.append(ctx.file.bootloader) + args.add("-k", ctx.file.kernel.path) + inputs.append(ctx.file.kernel) + + args.add("-o", ctx.outputs.image.path) + outputs.append(ctx.outputs.image) + + ctx.actions.run( + inputs = inputs, + outputs = outputs, + arguments = [args], + executable = ctx.executable._generator, + progress_message = "Generating ISO image %s" % ctx.label.name, + ) + +_make_iso = rule( + attrs = { + "bootloader": attr.label(allow_single_file = True), + "kernel": attr.label(allow_single_file = True), + "image": attr.output(), + "_generator": attr.label( + default = Label(":make_iso"), + executable = True, + allow_files = True, + cfg = "exec", + ), + }, + implementation = _make_iso_impl, +) diff --git a/tools/make_iso.py b/tools/make_iso.py new file mode 100755 index 0000000..7cb4506 --- /dev/null +++ b/tools/make_iso.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 + +from subprocess import run +import argparse +import os +import shutil +import hashlib + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('-k', '--kernel', required=True, help='path to kernel binary') + parser.add_argument('-c', '--config', required=True, help='path to bootloader config') + parser.add_argument('-o', '--output', required=True, help='path for output image') + + parser.add_argument('--prefix-dir', default='isodir', help='prefix dir') + parser.add_argument('--boot-dir', default='boot/grub', help='bootloader dir') + parser.add_argument('--kernel-dir', default='boot/glitch', help='kernel dir') + + # grub tools + parser.add_argument('--grub-file', default='grub-file', + help='grub-file executable') + parser.add_argument('--grub-script-check', default='grub-script-check', + help='grub-script-check executable') + parser.add_argument('--grub-mkrescue', default='grub-mkrescue', + help='grub-mkrescue executable') + # other tools + parser.add_argument('--strip', default='i686-elf-strip', + help='strip executable') + + args = parser.parse_args() + args.boot_dir = f'{args.prefix_dir}/{args.boot_dir}' + args.kernel_dir = f'{args.prefix_dir}/{args.kernel_dir}' + + # check inputs + run([ args.grub_file, '--is-x86-multiboot2', args.kernel ], check=True) + run([ args.grub_script_check, args.config ], check=True) + + # create directory structure and copy files + os.makedirs(args.boot_dir, exist_ok=True) + os.makedirs(args.kernel_dir, exist_ok=True) + shutil.copyfile(args.config, f'{args.boot_dir}/grub.cfg') + shutil.copyfile(args.kernel, f'{args.kernel_dir}/glitch.elf') + + # strip and hash binary + run([ args.strip, f'{args.kernel_dir}/glitch.elf' ], check=True) + with open(f'{args.kernel_dir}/checksums', 'w') as checksums: + with open(f'{args.kernel_dir}/glitch.elf', 'rb') as f: + digest = hashlib.file_digest(f, 'sha512').hexdigest() + path = f'{args.kernel_dir}/{args.kernel}'.removeprefix(args.prefix_dir) + print(f'{digest} {path}', file=checksums) + + # create iso image + run([ args.grub_mkrescue, '-o', args.output, args.prefix_dir ], check=True) + + # cleanup + #shutil.rmtree(args.prefix_dir) + diff --git a/tools/qemu.bzl b/tools/qemu.bzl new file mode 100644 index 0000000..9493306 --- /dev/null +++ b/tools/qemu.bzl @@ -0,0 +1,33 @@ +load("//toolchains:i386_qemu.bzl", qemu_i386 = "qemu_wrapper") + +def qemu(**kwargs): + _qemu( + wrapper_content = select({ + "@platforms//cpu:i386": qemu_i386(), + "//conditions:default": "/bin/false", + }), + **kwargs + ) + +def _qemu_impl(ctx): + print(ctx) + print(ctx.attr) + + wrapper = ctx.actions.declare_file("%s_wrapper" % ctx.label.name) + wrapper_content = ctx.attr.wrapper_content.format( + cdrom = ctx.file.cdrom.basename, + ) + ctx.actions.write(wrapper, wrapper_content, is_executable = True) + + runfiles = ctx.runfiles(files = [ctx.file.cdrom]) + + return [DefaultInfo(executable = wrapper, runfiles = runfiles)] + +_qemu = rule( + implementation = _qemu_impl, + attrs = { + "cdrom": attr.label(allow_single_file = True), + "wrapper_content": attr.string(), + }, + executable = True, +) |