From 9921e8784ce2ff5ade747bc15903d2f598c37029 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Fri, 9 Dec 2022 03:46:31 +0400 Subject: [PATCH 1/4] i386 IDT (#135) --- Makefile.am | 2 +- include/Makefile.am | 2 +- include/kernaux/arch/i386-idt.h | 62 ++++++++++++++++ include/kernaux/arch/i386.h | 20 +----- src/arch/i386.c | 14 ---- src/arch/i386/idt.c | 74 +++++++++++++++++++ tests/test_arch_i386.c | 123 ++++++++++++++++++++++++++++---- 7 files changed, 250 insertions(+), 47 deletions(-) create mode 100644 include/kernaux/arch/i386-idt.h delete mode 100644 src/arch/i386.c create mode 100644 src/arch/i386/idt.c diff --git a/Makefile.am b/Makefile.am index 6a26bbf..1022f1d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,7 +47,7 @@ endif ####### if WITH_ARCH_I386 -libkernaux_la_SOURCES += src/arch/i386.c +libkernaux_la_SOURCES += src/arch/i386/idt.c endif ####### diff --git a/include/Makefile.am b/include/Makefile.am index 64eba2d..f8f40ee 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -17,7 +17,7 @@ nobase_include_HEADERS = \ ######## if WITH_ARCH_I386 -nobase_include_HEADERS += kernaux/arch/i386.h +nobase_include_HEADERS += kernaux/arch/i386.h kernaux/arch/i386-idt.h endif if WITH_ARCH_RISCV64 nobase_include_HEADERS += kernaux/arch/riscv64.h diff --git a/include/kernaux/arch/i386-idt.h b/include/kernaux/arch/i386-idt.h new file mode 100644 index 0000000..d9d674e --- /dev/null +++ b/include/kernaux/arch/i386-idt.h @@ -0,0 +1,62 @@ +#ifndef KERNAUX_INCLUDED_ARCH_I386_IDT +#define KERNAUX_INCLUDED_ARCH_I386_IDT + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +#include + +/** + * @brief Interrupt Descriptor Table entry + * + * @see https://en.wikibooks.org/wiki/X86_Assembly/Advanced_Interrupts#The_Interrupt_Descriptor_Table + */ +typedef struct KernAux_Arch_I386_IDTE { + uint16_t offset_low; + uint16_t selector; + uint8_t _; + uint8_t flags; + uint16_t offset_high; +} +KERNAUX_PACKED +KERNAUX_ALIGNED(8) +*KernAux_Arch_I386_IDTE; + +KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Arch_I386_IDTE, 8); + +#include + +void KernAux_Arch_I386_IDTE_init_intr( + KernAux_Arch_I386_IDTE idte, + uint32_t offset, + uint16_t cs_selector, + uint8_t dpl +); +void KernAux_Arch_I386_IDTE_init_task( + KernAux_Arch_I386_IDTE idte, + uint16_t tss_selector, + uint8_t dpl +); +void KernAux_Arch_I386_IDTE_init_trap( + KernAux_Arch_I386_IDTE idte, + uint32_t offset, + uint16_t cs_selector, + uint8_t dpl +); + +uint32_t KernAux_Arch_I386_IDTE_offset(KernAux_Arch_I386_IDTE idte); +uint8_t KernAux_Arch_I386_IDTE_dpl (KernAux_Arch_I386_IDTE idte); + +void +KernAux_Arch_I386_IDTE_set_offset(KernAux_Arch_I386_IDTE idte, uint32_t offset); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/kernaux/arch/i386.h b/include/kernaux/arch/i386.h index 679fe35..dc507a0 100644 --- a/include/kernaux/arch/i386.h +++ b/include/kernaux/arch/i386.h @@ -5,6 +5,7 @@ extern "C" { #endif +#include #include #include @@ -91,25 +92,6 @@ KERNAUX_PACKED; KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Arch_I386_DTE, 8); -// Interrupt descriptor table entry -// TODO: validate this according to spec -typedef struct KernAux_Arch_I386_IDTE { - uint16_t offset_low; - uint16_t selector; - uint8_t _zero0; - uint8_t flags; - uint16_t offset_high; -} -KERNAUX_PACKED -*KernAux_Arch_I386_IDTE; - -KERNAUX_STATIC_TEST_STRUCT_SIZE(KernAux_Arch_I386_IDTE, 8); - -void KernAux_Arch_I386_IDTE_set_offset( - KernAux_Arch_I386_IDTE idte, - uint32_t address -); - /** * @brief Task state segment * @see The manual, page 132, figure 7-1 diff --git a/src/arch/i386.c b/src/arch/i386.c deleted file mode 100644 index 7337f74..0000000 --- a/src/arch/i386.c +++ /dev/null @@ -1,14 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -void KernAux_Arch_I386_IDTE_set_offset( - const KernAux_Arch_I386_IDTE idte, - const uint32_t address -) -{ - idte->offset_low = 0xFFFF & address; - idte->offset_high = 0xFFFF & (address >> 16); -} diff --git a/src/arch/i386/idt.c b/src/arch/i386/idt.c new file mode 100644 index 0000000..1a7d848 --- /dev/null +++ b/src/arch/i386/idt.c @@ -0,0 +1,74 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#define DPL (0x60u & (dpl << 5)) + +void KernAux_Arch_I386_IDTE_init_intr( + const KernAux_Arch_I386_IDTE idte, + const uint32_t offset, + const uint16_t cs_selector, + const uint8_t dpl +) { + KERNAUX_ASSERT(idte); + + memset(idte, 0, sizeof(*idte)); + KernAux_Arch_I386_IDTE_set_offset(idte, offset); + idte->selector = cs_selector; + idte->flags |= 0x80u | DPL | 0xeu; // 1-00-01110 +} + +void KernAux_Arch_I386_IDTE_init_task( + const KernAux_Arch_I386_IDTE idte, + const uint16_t tss_selector, + const uint8_t dpl +) { + KERNAUX_ASSERT(idte); + + memset(idte, 0, sizeof(*idte)); + idte->selector = tss_selector; + idte->flags |= 0x80u | DPL | 0x5u; // 1-00-00101 +} + +void KernAux_Arch_I386_IDTE_init_trap( + const KernAux_Arch_I386_IDTE idte, + const uint32_t offset, + const uint16_t cs_selector, + const uint8_t dpl +) { + KERNAUX_ASSERT(idte); + + memset(idte, 0, sizeof(*idte)); + KernAux_Arch_I386_IDTE_set_offset(idte, offset); + idte->selector = cs_selector; + idte->flags |= 0x80u | DPL | 0xfu; // 1-00-01111 +} + +uint32_t KernAux_Arch_I386_IDTE_offset(const KernAux_Arch_I386_IDTE idte) +{ + KERNAUX_ASSERT(idte); + + return (idte->offset_high << 16) | idte->offset_low; +} + +uint8_t KernAux_Arch_I386_IDTE_dpl(const KernAux_Arch_I386_IDTE idte) +{ + KERNAUX_ASSERT(idte); + + return 3 & (idte->flags >> 5); +} + +void KernAux_Arch_I386_IDTE_set_offset( + const KernAux_Arch_I386_IDTE idte, + const uint32_t offset +) { + KERNAUX_ASSERT(idte); + + idte->offset_low = 0xffffu & offset; + idte->offset_high = 0xffffu & (offset >> 16); +} diff --git a/tests/test_arch_i386.c b/tests/test_arch_i386.c index 37a931a..b600c4d 100644 --- a/tests/test_arch_i386.c +++ b/tests/test_arch_i386.c @@ -7,27 +7,126 @@ #include #include -static void test_idte_set_offset(); +static void test_idte_init_intr(); +static void test_idte_init_task(); +static void test_idte_init_trap(); +static void test_idte_get_and_set_offset(); +static void test_idte_get_dpl(); void test_main() { - test_idte_set_offset(); + test_idte_init_intr(); + test_idte_init_task(); + test_idte_init_trap(); + test_idte_get_and_set_offset(); + test_idte_get_dpl(); } -void test_idte_set_offset() +void test_idte_init_intr() +{ + struct KernAux_Arch_I386_IDTE idte; + memset(&idte, 0xff, sizeof(idte)); + + KernAux_Arch_I386_IDTE_init_intr(&idte, 0x12345678, 0xcafe, 0); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678); + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0); + assert(idte.selector == 0xcafe); + assert(idte._ == 0); + assert(idte.flags == 0x8e); // 1-00-01110 + + KernAux_Arch_I386_IDTE_init_intr(&idte, 0x12345678, 0xcafe, 3); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678); + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3); + assert(idte.selector == 0xcafe); + assert(idte._ == 0); + assert(idte.flags == 0xee); // 1-11-01110 +} + +void test_idte_init_task() +{ + struct KernAux_Arch_I386_IDTE idte; + memset(&idte, 0xff, sizeof(idte)); + + KernAux_Arch_I386_IDTE_init_task(&idte, 0xcafe, 0); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0); + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0); + assert(idte.selector == 0xcafe); + assert(idte._ == 0); + assert(idte.flags == 0x85); // 1-00-00101 + + KernAux_Arch_I386_IDTE_init_task(&idte, 0xcafe, 3); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0); + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3); + assert(idte.selector == 0xcafe); + assert(idte._ == 0); + assert(idte.flags == 0xe5); // 1-11-00101 +} + +void test_idte_init_trap() +{ + struct KernAux_Arch_I386_IDTE idte; + memset(&idte, 0xff, sizeof(idte)); + + KernAux_Arch_I386_IDTE_init_trap(&idte, 0x12345678, 0xcafe, 0); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678); + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0); + assert(idte.selector == 0xcafe); + assert(idte._ == 0); + assert(idte.flags == 0x8f); // 1-00-01111 + + KernAux_Arch_I386_IDTE_init_trap(&idte, 0x12345678, 0xcafe, 3); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678); + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3); + assert(idte.selector == 0xcafe); + assert(idte._ == 0); + assert(idte.flags == 0xef); // 1-11-01111 +} + +void test_idte_get_and_set_offset() +{ + struct KernAux_Arch_I386_IDTE idte; + + memset(&idte, 0xff, sizeof(idte)); + KernAux_Arch_I386_IDTE_set_offset(&idte, 0); + assert(idte.offset_high == 0); + assert(idte.offset_low == 0); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0); + + memset(&idte, 0, sizeof(idte)); + KernAux_Arch_I386_IDTE_set_offset(&idte, 0xffffffff); + assert(idte.offset_high == 0xffff); + assert(idte.offset_low == 0xffff); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0xffffffff); + + memset(&idte, 0, sizeof(idte)); + KernAux_Arch_I386_IDTE_set_offset(&idte, 0x12345678); + assert(idte.offset_high == 0x1234); + assert(idte.offset_low == 0x5678); + assert(KernAux_Arch_I386_IDTE_offset(&idte) == 0x12345678); +} + +void test_idte_get_dpl() { struct KernAux_Arch_I386_IDTE idte; memset(&idte, 0, sizeof(idte)); - KernAux_Arch_I386_IDTE_set_offset(&idte, 0); - assert(idte.offset_high == 0); - assert(idte.offset_low == 0); + idte.flags = 0; // 0-00-00000 + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0); + idte.flags = 0x80; // 1-00-00000 + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 0); - KernAux_Arch_I386_IDTE_set_offset(&idte, 0xFFFFFFFF); - assert(idte.offset_high == 0xFFFF); - assert(idte.offset_low == 0xFFFF); + idte.flags = 0x20; // 0-01-00000 + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 1); + idte.flags = 0xa0; // 1-01-00000 + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 1); - KernAux_Arch_I386_IDTE_set_offset(&idte, 0x12345678); - assert(idte.offset_high == 0x1234); - assert(idte.offset_low == 0x5678); + idte.flags = 0x40; // 0-10-00000 + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 2); + idte.flags = 0xc0; // 1-10-00000 + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 2); + + idte.flags = 0x60; // 0-11-00000 + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3); + idte.flags = 0xe0; // 1-11-00000 + assert(KernAux_Arch_I386_IDTE_dpl(&idte) == 3); } From e6203d58cc7e472a7937c0c830f3658970b88a2f Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Fri, 9 Dec 2022 06:59:54 +0400 Subject: [PATCH 2/4] Create generic debug output formatter (#136) --- .gitignore | 1 + ChangeLog | 4 + Makefile.am | 1 + README.md | 2 + examples/Makefile.am | 8 ++ examples/generic_display.c | 115 +++++++++++++++++++++ include/Makefile.am | 1 + include/kernaux/generic/display.h | 37 +++++++ include/kernaux/multiboot2.h.in | 17 +-- src/generic/display.c | 115 +++++++++++++++++++++ src/multiboot2/header_print.c | 35 ++++--- src/multiboot2/info_print.c | 166 ++++++++++++++++-------------- tests/multiboot2_header_print1.c | 24 +++-- tests/multiboot2_header_print2.c | 24 +++-- tests/multiboot2_info_print1.c | 24 +++-- tests/multiboot2_info_print2.c | 24 +++-- 16 files changed, 473 insertions(+), 125 deletions(-) create mode 100644 examples/generic_display.c create mode 100644 include/kernaux/generic/display.h create mode 100644 src/generic/display.c diff --git a/.gitignore b/.gitignore index 44f99e7..270fa63 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ /examples/assert /examples/cmdline +/examples/generic_display /examples/generic_malloc /examples/generic_mutex /examples/macro_bits diff --git a/ChangeLog b/ChangeLog index eb309db..fdb0fa1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-12-09 Alex Kotov + + * include/kernaux/generic/display.h: The header has been added + 2022-12-08 Alex Kotov * include/kernaux/*.h: Definition "KERNAUX_BITFIELDS" has been added diff --git a/Makefile.am b/Makefile.am index 1022f1d..b3aea18 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,6 +31,7 @@ lib_LTLIBRARIES = libkernaux.la libkernaux_la_LIBADD = libkernaux_la_SOURCES = \ src/assert.c \ + src/generic/display.c \ src/generic/malloc.c \ src/generic/mutex.c diff --git a/README.md b/README.md index 3791e4a..1bc3ba5 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ zero). Work-in-progress APIs can change at any time. * [Example: Panic](/examples/panic.c) * Stack trace *(planned)* * Generic types + * [Display](/include/kernaux/generic/display.h) (*non-breaking since* **?.?.?**) + * [Example](/examples/generic_display.c) * [Memory allocator](/include/kernaux/generic/malloc.h) (*non-breaking since* **0.5.0**) * [Example](/examples/generic_malloc.c) * [Mutex](/include/kernaux/generic/mutex.h) (*non-breaking since* **0.5.0**) diff --git a/examples/Makefile.am b/examples/Makefile.am index 1308dfa..b792a50 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -21,6 +21,14 @@ cmdline_LDADD = $(top_builddir)/libkernaux.la cmdline_SOURCES = main.c cmdline.c endif +################### +# generic_display # +################### + +TESTS += generic_display +generic_display_LDADD = $(top_builddir)/libkernaux.la +generic_display_SOURCES = main.c generic_display.c + ################## # generic_malloc # ################## diff --git a/examples/generic_display.c b/examples/generic_display.c new file mode 100644 index 0000000..44da528 --- /dev/null +++ b/examples/generic_display.c @@ -0,0 +1,115 @@ +//============== +// my_display.c +//============== + +// To not always use macro "KERNAUX_PROTECTED_FIELD" around the names of +// structure fields you may define "KERNAUX_ACCESS_PROTECTED" before including +// any other headers, but ONLY in the file where you implement a generic type. +// +#define KERNAUX_ACCESS_PROTECTED + +//============== +// my_display.h +//============== + +#include +#include + +typedef struct MyDisplay { + struct KernAux_Display display; + char *buffer, *cursor; + size_t capacity; +} *MyDisplay; + +struct MyDisplay MyDisplay_create(); + +//============== +// my_display.c +//============== + +#include +#include +#include +#include +#include +#include +#include + +#define CAP_FREE (1024) +#define CAP_INCR (2 * (CAP_FREE)) + +static void MyDisplay_putc(void *display, char c); +void MyDisplay_vprintf(void *display, const char *format, va_list va); + +static void MyDisplay_realloc(MyDisplay my_display); + +struct MyDisplay MyDisplay_create() +{ + char *const buffer = malloc(CAP_INCR); + if (!buffer) abort(); + + return (struct MyDisplay){ + .display = { + .putc = MyDisplay_putc, + .vprintf = MyDisplay_vprintf, + }, + .buffer = buffer, + .cursor = buffer, + .capacity = CAP_INCR, + }; +} + +void MyDisplay_putc(void *display, char c) +{ + const MyDisplay my_display = display; + MyDisplay_realloc(my_display); + *(my_display->cursor++) = c; +} + +void MyDisplay_vprintf(void *display, const char *format, va_list va) +{ + const MyDisplay my_display = display; + MyDisplay_realloc(my_display); + size_t left = + my_display->buffer + my_display->capacity - my_display->cursor; + const int delta = vsnprintf(my_display->cursor, left, format, va); + if (delta < 0) abort(); + my_display->cursor += delta; +} + +void MyDisplay_realloc(const MyDisplay my_display) +{ + size_t left = + my_display->buffer + my_display->capacity - my_display->cursor; + + if (left < CAP_FREE) { + my_display->buffer = + realloc(my_display->buffer, my_display->capacity + CAP_INCR); + if (!my_display->buffer) abort(); + my_display->capacity += CAP_INCR; + } +} + +//======== +// main.c +//======== + +void example_main() +{ + struct MyDisplay my_display = MyDisplay_create(); + + KernAux_Display_putc(&my_display.display, '@'); + KernAux_Display_print(&my_display.display, "print"); + KernAux_Display_println(&my_display.display, "println"); + KernAux_Display_write(&my_display.display, "write!!!", 5); + KernAux_Display_writeln(&my_display.display, "writeln!!!", 7); + KernAux_Display_printf(&my_display.display, "printf(%d)", 123); + KernAux_Display_printlnf(&my_display.display, "printfln(%d)", 123); + + assert( + strcmp( + my_display.buffer, + "@printprintln\nwritewriteln\nprintf(123)printfln(123)\n" + ) == 0 + ); +} diff --git a/include/Makefile.am b/include/Makefile.am index f8f40ee..2245853 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -9,6 +9,7 @@ nobase_include_HEADERS = \ kernaux/macro/packing_start.run \ kernaux/macro/packing_end.run \ kernaux/version.h \ + kernaux/generic/display.h \ kernaux/generic/malloc.h \ kernaux/generic/mutex.h diff --git a/include/kernaux/generic/display.h b/include/kernaux/generic/display.h new file mode 100644 index 0000000..cbe1ed8 --- /dev/null +++ b/include/kernaux/generic/display.h @@ -0,0 +1,37 @@ +#ifndef KERNAUX_INCLUDED_DISPLAY +#define KERNAUX_INCLUDED_DISPLAY + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +typedef void (*KernAux_Display_Putc )(void *display, char c); +typedef void (*KernAux_Display_Vprintf)(void *display, const char *format, va_list va); + +typedef const struct KernAux_Display { + KernAux_Display_Putc KERNAUX_PROTECTED_FIELD(putc); + KernAux_Display_Vprintf KERNAUX_PROTECTED_FIELD(vprintf); +} *KernAux_Display; + +void KernAux_Display_putc (KernAux_Display display, char c); +void KernAux_Display_print (KernAux_Display display, const char *s); +void KernAux_Display_println (KernAux_Display display, const char *s); +void KernAux_Display_write (KernAux_Display display, const char *data, size_t size); +void KernAux_Display_writeln (KernAux_Display display, const char *data, size_t size); +KERNAUX_PRINTF(2, 3) +void KernAux_Display_printf (KernAux_Display display, const char *format, ...); +KERNAUX_PRINTF(2, 3) +void KernAux_Display_printlnf (KernAux_Display display, const char *format, ...); +void KernAux_Display_vprintf (KernAux_Display display, const char *format, va_list va); +void KernAux_Display_vprintlnf(KernAux_Display display, const char *format, va_list va); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/kernaux/multiboot2.h.in b/include/kernaux/multiboot2.h.in index fb7088e..ad5941e 100644 --- a/include/kernaux/multiboot2.h.in +++ b/include/kernaux/multiboot2.h.in @@ -6,6 +6,7 @@ extern "C" { #endif #include +#include @comment_line_memmap@#include #include @@ -789,12 +790,12 @@ bool KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr_is_valid( void KernAux_Multiboot2_Header_print( const struct KernAux_Multiboot2_Header *multiboot2_header, - void (*printf)(const char *format, ...) KERNAUX_PRINTF(1, 2) + KernAux_Display display ); void KernAux_Multiboot2_HTagBase_print( const struct KernAux_Multiboot2_HTagBase *tag_base, - void (*printf)(const char *format, ...) KERNAUX_PRINTF(1, 2) + KernAux_Display display ); /******************************* @@ -803,32 +804,32 @@ void KernAux_Multiboot2_HTagBase_print( void KernAux_Multiboot2_Info_print( const struct KernAux_Multiboot2_Info *multiboot2_info, - void (*printf)(const char *format, ...) KERNAUX_PRINTF(1, 2) + KernAux_Display display ); void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITagBase *tag_base, - void (*printf)(const char *format, ...) KERNAUX_PRINTF(1, 2) + KernAux_Display display ); void KernAux_Multiboot2_ITag_BootCmdLine_print( const struct KernAux_Multiboot2_ITag_BootCmdLine *tag, - void (*printf)(const char *format, ...) KERNAUX_PRINTF(1, 2) + KernAux_Display display ); void KernAux_Multiboot2_ITag_BootLoaderName_print( const struct KernAux_Multiboot2_ITag_BootLoaderName *tag, - void (*printf)(const char *format, ...) KERNAUX_PRINTF(1, 2) + KernAux_Display display ); void KernAux_Multiboot2_ITag_MemoryMap_print( const struct KernAux_Multiboot2_ITag_MemoryMap *tag, - void (*printf)(const char *format, ...) KERNAUX_PRINTF(1, 2) + KernAux_Display display ); void KernAux_Multiboot2_ITag_ELFSymbols_print( const struct KernAux_Multiboot2_ITag_ELFSymbols *tag, - void (*printf)(const char *format, ...) KERNAUX_PRINTF(1, 2) + KernAux_Display display ); #ifdef __cplusplus diff --git a/src/generic/display.c b/src/generic/display.c new file mode 100644 index 0000000..36a4091 --- /dev/null +++ b/src/generic/display.c @@ -0,0 +1,115 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include + +void KernAux_Display_putc(const KernAux_Display display, const char c) +{ + KERNAUX_ASSERT(display); + KERNAUX_ASSERT(display->putc); + + // Inherited implementation + display->putc((void*)display, c); +} + +void KernAux_Display_print(const KernAux_Display display, const char *const s) +{ + KERNAUX_ASSERT(display); + KERNAUX_ASSERT(display->putc); + + // Default implementation + for (const char *c = s; *c; ++c) display->putc((void*)display, *c); +} + +void KernAux_Display_println(const KernAux_Display display, const char *const s) +{ + KERNAUX_ASSERT(display); + KERNAUX_ASSERT(display->putc); + + // Default implementation + KernAux_Display_print(display, s); + display->putc((void*)display, '\n'); +} + +void KernAux_Display_write( + const KernAux_Display display, + const char *const data, + const size_t size +) { + KERNAUX_ASSERT(display); + KERNAUX_ASSERT(display->putc); + + // Default implementation + for (size_t i = 0; i < size; ++i) display->putc((void*)display, data[i]); +} + +void KernAux_Display_writeln( + const KernAux_Display display, + const char *const data, + const size_t size +) { + KERNAUX_ASSERT(display); + KERNAUX_ASSERT(display->putc); + + // Default implementation + KernAux_Display_write(display, data, size); + display->putc((void*)display, '\n'); +} + +void KernAux_Display_printf( + const KernAux_Display display, + const char *const format, + ... +) { + KERNAUX_ASSERT(display); + + // Default implementation + va_list va; + va_start(va, format); + KernAux_Display_vprintf(display, format, va); + va_end(va); +} + +void KernAux_Display_printlnf( + const KernAux_Display display, + const char *const format, + ... +) { + KERNAUX_ASSERT(display); + + // Default implementation + va_list va; + va_start(va, format); + KernAux_Display_vprintlnf(display, format, va); + va_end(va); +} + +void KernAux_Display_vprintf( + const KernAux_Display display, + const char *const format, + va_list va +) { + KERNAUX_ASSERT(display); + KERNAUX_ASSERT(display->vprintf); + + // Inherited implementation + display->vprintf((void*)display, format, va); +} + +void KernAux_Display_vprintlnf( + const KernAux_Display display, + const char *const format, + va_list va +) { + KERNAUX_ASSERT(display); + KERNAUX_ASSERT(display->putc); + + // Default implementation + KernAux_Display_vprintf(display, format, va); + display->putc((void*)display, '\n'); +} diff --git a/src/multiboot2/header_print.c b/src/multiboot2/header_print.c index 63dc493..6804ae0 100644 --- a/src/multiboot2/header_print.c +++ b/src/multiboot2/header_print.c @@ -3,27 +3,31 @@ #endif #include +#include #include #include #include +#define PRINTLN(s) KernAux_Display_println(display, s) +#define PRINTLNF(format, ...) \ + KernAux_Display_printlnf(display, format, __VA_ARGS__) + void KernAux_Multiboot2_Header_print( const struct KernAux_Multiboot2_Header *const multiboot2_header, - void (*const printf)(const char *format, ...) + const KernAux_Display display ) { KERNAUX_ASSERT(multiboot2_header); - KERNAUX_ASSERT(printf); + KERNAUX_ASSERT(display); - printf("Multiboot 2 header\n"); - printf(" magic: %u\n", multiboot2_header->magic); - printf( - " arch: %u (%s)\n", + PRINTLN("Multiboot 2 header"); + PRINTLNF(" magic: %u", multiboot2_header->magic); + PRINTLNF(" arch: %u (%s)", multiboot2_header->arch, KernAux_Multiboot2_Header_Arch_to_str(multiboot2_header->arch) ); - printf(" size: %u\n", multiboot2_header->total_size); - printf(" checksum: %u\n", multiboot2_header->checksum); + PRINTLNF(" size: %u", multiboot2_header->total_size); + PRINTLNF(" checksum: %u", multiboot2_header->checksum); const struct KernAux_Multiboot2_HTagBase *tag_base = (struct KernAux_Multiboot2_HTagBase*) @@ -35,7 +39,7 @@ void KernAux_Multiboot2_Header_print( { if (!KernAux_Multiboot2_HTagBase_is_valid(tag_base)) return; - KernAux_Multiboot2_HTagBase_print(tag_base, printf); + KernAux_Multiboot2_HTagBase_print(tag_base, display); tag_base = KERNAUX_MULTIBOOT2_HTAG_NEXT(tag_base); } @@ -43,23 +47,22 @@ void KernAux_Multiboot2_Header_print( void KernAux_Multiboot2_HTagBase_print( const struct KernAux_Multiboot2_HTagBase *const tag_base, - void (*const printf)(const char *format, ...) + const KernAux_Display display ) { KERNAUX_ASSERT(tag_base); - KERNAUX_ASSERT(printf); + KERNAUX_ASSERT(display); if (!KernAux_Multiboot2_HTagBase_is_valid(tag_base)) return; - printf("Multiboot 2 header tag\n"); + PRINTLN("Multiboot 2 header tag"); - printf( - " type: %u (%s)\n", + PRINTLNF(" type: %u (%s)", tag_base->type, KernAux_Multiboot2_HTag_to_str(tag_base->type) ); - printf(" flags: %u\n", tag_base->flags); - printf(" size: %u\n", tag_base->size); + PRINTLNF(" flags: %u", tag_base->flags); + PRINTLNF(" size: %u", tag_base->size); switch (tag_base->type) { case KERNAUX_MULTIBOOT2_HTAG_NONE: diff --git a/src/multiboot2/info_print.c b/src/multiboot2/info_print.c index 09c66f7..1cf2a93 100644 --- a/src/multiboot2/info_print.c +++ b/src/multiboot2/info_print.c @@ -8,16 +8,23 @@ #include #include +// TODO: create macro for this +#define INT_IF(a, b) (sizeof(int) == sizeof(long) ? (a) : (b)) + +#define PRINTLN(s) KernAux_Display_println(display, s) +#define PRINTLNF(format, ...) \ + KernAux_Display_printlnf(display, format, __VA_ARGS__) + void KernAux_Multiboot2_Info_print( const struct KernAux_Multiboot2_Info *const multiboot2_info, - void (*const printf)(const char *format, ...) + const KernAux_Display display ) { KERNAUX_ASSERT(multiboot2_info); - KERNAUX_ASSERT(printf); + KERNAUX_ASSERT(display); - printf("Multiboot 2 info\n"); - printf(" size: %u\n", multiboot2_info->total_size); - printf(" reserved1: %u\n", multiboot2_info->reserved1); + PRINTLN("Multiboot 2 info"); + PRINTLNF(" size: %u", multiboot2_info->total_size); + PRINTLNF(" reserved1: %u", multiboot2_info->reserved1); const struct KernAux_Multiboot2_ITagBase *tag_base = (struct KernAux_Multiboot2_ITagBase*) @@ -29,7 +36,7 @@ void KernAux_Multiboot2_Info_print( { if (!KernAux_Multiboot2_ITagBase_is_valid(tag_base)) return; - KernAux_Multiboot2_ITagBase_print(tag_base, printf); + KernAux_Multiboot2_ITagBase_print(tag_base, display); tag_base = KERNAUX_MULTIBOOT2_ITAG_NEXT(tag_base); } @@ -37,22 +44,21 @@ void KernAux_Multiboot2_Info_print( void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITagBase *const tag_base, - void (*const printf)(const char *format, ...) + const KernAux_Display display ) { KERNAUX_ASSERT(tag_base); - KERNAUX_ASSERT(printf); + KERNAUX_ASSERT(display); if (!KernAux_Multiboot2_ITagBase_is_valid(tag_base)) return; - printf("Multiboot 2 info tag\n"); + PRINTLN("Multiboot 2 info tag"); - printf( - " type: %u (%s)\n", + PRINTLNF(" type: %u (%s)", tag_base->type, KernAux_Multiboot2_ITag_to_str(tag_base->type) ); - printf(" size: %u\n", tag_base->size); + PRINTLNF(" size: %u", tag_base->size); switch (tag_base->type) { case KERNAUX_MULTIBOOT2_ITAG_NONE: @@ -60,13 +66,13 @@ void KernAux_Multiboot2_ITagBase_print( case KERNAUX_MULTIBOOT2_ITAG_BOOT_CMD_LINE: KernAux_Multiboot2_ITag_BootCmdLine_print( (struct KernAux_Multiboot2_ITag_BootCmdLine*)tag_base, - printf + display ); break; case KERNAUX_MULTIBOOT2_ITAG_BOOT_LOADER_NAME: KernAux_Multiboot2_ITag_BootLoaderName_print( (struct KernAux_Multiboot2_ITag_BootLoaderName*)tag_base, - printf + display ); break; case KERNAUX_MULTIBOOT2_ITAG_MODULE: @@ -74,9 +80,9 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_Module *const tag_module = (struct KernAux_Multiboot2_ITag_Module*)tag_base; - printf(" start: %u\n", tag_module->mod_start); - printf(" end: %u\n", tag_module->mod_end); - printf(" cmdline: %s\n", KERNAUX_MULTIBOOT2_DATA(tag_module)); + PRINTLNF(" start: %u", tag_module->mod_start); + PRINTLNF(" end: %u", tag_module->mod_end); + PRINTLNF(" cmdline: %s", KERNAUX_MULTIBOOT2_DATA(tag_module)); } break; case KERNAUX_MULTIBOOT2_ITAG_BASIC_MEMORY_INFO: @@ -84,8 +90,8 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *const tag_bmi = (struct KernAux_Multiboot2_ITag_BasicMemoryInfo*)tag_base; - printf(" mem lower: %u\n", tag_bmi->mem_lower); - printf(" mem upper: %u\n", tag_bmi->mem_upper); + PRINTLNF(" mem lower: %u", tag_bmi->mem_lower); + PRINTLNF(" mem upper: %u", tag_bmi->mem_upper); } break; case KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE: @@ -93,15 +99,15 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_BIOSBootDevice *const tag_bbd = (struct KernAux_Multiboot2_ITag_BIOSBootDevice*)tag_base; - printf(" bios dev: %u\n", tag_bbd->bios_dev); - printf(" partition: %u\n", tag_bbd->partition); - printf(" sub_partition: %u\n", tag_bbd->sub_partition); + PRINTLNF(" bios dev: %u", tag_bbd->bios_dev); + PRINTLNF(" partition: %u", tag_bbd->partition); + PRINTLNF(" sub_partition: %u", tag_bbd->sub_partition); } break; case KERNAUX_MULTIBOOT2_ITAG_MEMORY_MAP: KernAux_Multiboot2_ITag_MemoryMap_print( (struct KernAux_Multiboot2_ITag_MemoryMap*)tag_base, - printf + display ); break; case KERNAUX_MULTIBOOT2_ITAG_VBE_INFO: @@ -109,10 +115,10 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_VBEInfo *const tag_vbe = (struct KernAux_Multiboot2_ITag_VBEInfo*)tag_base; - printf(" VBE mode: %hu\n", tag_vbe->vbe_mode); - printf(" VBE interface seg: %hu\n", tag_vbe->vbe_interface_seg); - printf(" VBE interface off: %hu\n", tag_vbe->vbe_interface_off); - printf(" VBE interface len: %hu\n", tag_vbe->vbe_interface_len); + PRINTLNF(" VBE mode: %hu", tag_vbe->vbe_mode); + PRINTLNF(" VBE interface seg: %hu", tag_vbe->vbe_interface_seg); + PRINTLNF(" VBE interface off: %hu", tag_vbe->vbe_interface_off); + PRINTLNF(" VBE interface len: %hu", tag_vbe->vbe_interface_len); } break; case KERNAUX_MULTIBOOT2_ITAG_FRAMEBUFFER_INFO: @@ -120,19 +126,22 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_FramebufferInfo *const tag_fb = (struct KernAux_Multiboot2_ITag_FramebufferInfo*)tag_base; - printf(" framebuffer addr: %llu\n", tag_fb->framebuffer_addr); - printf(" framebuffer pitch: %u\n", tag_fb->framebuffer_pitch); - printf(" framebuffer width: %u\n", tag_fb->framebuffer_width); - printf(" framebuffer height: %u\n", tag_fb->framebuffer_height); - printf(" framebuffer bpp: %u\n", tag_fb->framebuffer_bpp); - printf(" framebuffer type: %u\n", tag_fb->framebuffer_type); - printf(" reserved1: %u\n", tag_fb->reserved1); + PRINTLNF( + INT_IF(" framebuffer addr: %llu", " framebuffer addr: %lu"), + tag_fb->framebuffer_addr + ); + PRINTLNF(" framebuffer pitch: %u", tag_fb->framebuffer_pitch); + PRINTLNF(" framebuffer width: %u", tag_fb->framebuffer_width); + PRINTLNF(" framebuffer height: %u", tag_fb->framebuffer_height); + PRINTLNF(" framebuffer bpp: %u", tag_fb->framebuffer_bpp); + PRINTLNF(" framebuffer type: %u", tag_fb->framebuffer_type); + PRINTLNF(" reserved1: %u", tag_fb->reserved1); } break; case KERNAUX_MULTIBOOT2_ITAG_ELF_SYMBOLS: KernAux_Multiboot2_ITag_ELFSymbols_print( (struct KernAux_Multiboot2_ITag_ELFSymbols*)tag_base, - printf + display ); break; case KERNAUX_MULTIBOOT2_ITAG_APM_TABLE: @@ -140,15 +149,15 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_APMTable *const tag_apm = (struct KernAux_Multiboot2_ITag_APMTable*)tag_base; - printf(" version: %hu\n", tag_apm->version); - printf(" cseg: %hu\n", tag_apm->cseg); - printf(" offset: %u\n", tag_apm->offset); - printf(" cseg 16: %hu\n", tag_apm->cseg_16); - printf(" dseg: %hu\n", tag_apm->dseg); - printf(" flags: %hu\n", tag_apm->flags); - printf(" cseg len: %hu\n", tag_apm->cseg_len); - printf(" cseg 16 len: %hu\n", tag_apm->cseg_16_len); - printf(" dseg len: %hu\n", tag_apm->dseg_len); + PRINTLNF(" version: %hu", tag_apm->version); + PRINTLNF(" cseg: %hu", tag_apm->cseg); + PRINTLNF(" offset: %u", tag_apm->offset); + PRINTLNF(" cseg 16: %hu", tag_apm->cseg_16); + PRINTLNF(" dseg: %hu", tag_apm->dseg); + PRINTLNF(" flags: %hu", tag_apm->flags); + PRINTLNF(" cseg len: %hu", tag_apm->cseg_len); + PRINTLNF(" cseg 16 len: %hu", tag_apm->cseg_16_len); + PRINTLNF(" dseg len: %hu", tag_apm->dseg_len); } break; case KERNAUX_MULTIBOOT2_ITAG_EFI_32BIT_SYSTEM_TABLE_PTR: @@ -166,11 +175,10 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_SMBIOSTables *const tag_smbios = (struct KernAux_Multiboot2_ITag_SMBIOSTables*)tag_base; - printf(" major: %u\n", tag_smbios->major); - printf(" minor: %u\n", tag_smbios->minor); + PRINTLNF(" major: %u", tag_smbios->major); + PRINTLNF(" minor: %u", tag_smbios->minor); - printf( - " reserved1: {%u, %u, %u, %u, %u, %u}\n", + PRINTLNF(" reserved1: {%u, %u, %u, %u, %u, %u}", tag_smbios->reserved1[0], tag_smbios->reserved1[1], tag_smbios->reserved1[2], @@ -213,8 +221,7 @@ void KernAux_Multiboot2_ITagBase_print( } break; case KERNAUX_MULTIBOOT2_ITAG_IMAGE_LOAD_BASE_PHYS_ADDR: - printf( - " load base addr: %u\n", + PRINTLNF(" load base addr: %u", ((struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr*)tag_base)-> load_base_addr ); @@ -224,50 +231,49 @@ void KernAux_Multiboot2_ITagBase_print( void KernAux_Multiboot2_ITag_BootCmdLine_print( const struct KernAux_Multiboot2_ITag_BootCmdLine *const tag, - void (*printf)(const char *format, ...) + const KernAux_Display display ) { KERNAUX_ASSERT(tag); - KERNAUX_ASSERT(printf); + KERNAUX_ASSERT(display); if (!KernAux_Multiboot2_ITag_BootCmdLine_is_valid(tag)) { - printf(" invalid!\n"); + PRINTLN(" invalid!"); return; } - printf(" cmdline: %s\n", KERNAUX_MULTIBOOT2_DATA(tag)); + PRINTLNF(" cmdline: %s", KERNAUX_MULTIBOOT2_DATA(tag)); } void KernAux_Multiboot2_ITag_BootLoaderName_print( const struct KernAux_Multiboot2_ITag_BootLoaderName *const tag, - void (*printf)(const char *format, ...) + const KernAux_Display display ) { KERNAUX_ASSERT(tag); - KERNAUX_ASSERT(printf); + KERNAUX_ASSERT(display); if (!KernAux_Multiboot2_ITag_BootLoaderName_is_valid(tag)) { - printf(" invalid!\n"); + PRINTLN(" invalid!"); return; } - printf(" name: %s\n", KERNAUX_MULTIBOOT2_DATA(tag)); + PRINTLNF(" name: %s", KERNAUX_MULTIBOOT2_DATA(tag)); } void KernAux_Multiboot2_ITag_MemoryMap_print( const struct KernAux_Multiboot2_ITag_MemoryMap *const tag, - void (*printf)(const char *format, ...) + const KernAux_Display display ) { KERNAUX_ASSERT(tag); - KERNAUX_ASSERT(printf); + KERNAUX_ASSERT(display); if (!KernAux_Multiboot2_ITag_MemoryMap_is_valid(tag)) { - printf(" invalid!\n"); + PRINTLN(" invalid!"); return; } - printf(" entry size: %u\n", tag->entry_size); - printf(" entry version: %u\n", tag->entry_version); - - printf(" entries:\n"); + PRINTLNF(" entry size: %u", tag->entry_size); + PRINTLNF(" entry version: %u", tag->entry_version); + PRINTLN(" entries:"); const struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase *const entries = (struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase*) @@ -278,30 +284,36 @@ void KernAux_Multiboot2_ITag_MemoryMap_print( index < (tag->base.size - sizeof(*tag)) / tag->entry_size; ++index ) { - printf(" entry %lu\n", index); - printf(" base addr: %llu\n", entries[index].base_addr); - printf(" length: %llu\n", entries[index].length); - printf(" type: %u\n", entries[index].type); - printf(" reserved1: %u\n", entries[index].reserved1); + PRINTLNF(INT_IF(" entry %u", " entry %lu"), index); + PRINTLNF( + INT_IF(" base addr: %llu", " base addr: %lu"), + entries[index].base_addr + ); + PRINTLNF( + INT_IF(" length: %llu", " length: %lu"), + entries[index].length + ); + PRINTLNF(" type: %u", entries[index].type); + PRINTLNF(" reserved1: %u", entries[index].reserved1); } } void KernAux_Multiboot2_ITag_ELFSymbols_print( const struct KernAux_Multiboot2_ITag_ELFSymbols *const tag, - void (*printf)(const char *format, ...) + const KernAux_Display display ) { KERNAUX_ASSERT(tag); - KERNAUX_ASSERT(printf); + KERNAUX_ASSERT(display); if (!KernAux_Multiboot2_ITag_ELFSymbols_is_valid(tag)) { - printf(" invalid!\n"); + PRINTLN(" invalid!"); return; } - printf(" num: %hu\n", tag->num); - printf(" entsize: %hu\n", tag->ent_size); - printf(" shndx: %hu\n", tag->shndx); - printf(" reserved1: %hu\n", tag->reserved1); + PRINTLNF(" num: %hu", tag->num); + PRINTLNF(" entsize: %hu", tag->ent_size); + PRINTLNF(" shndx: %hu", tag->shndx); + PRINTLNF(" reserved1: %hu", tag->reserved1); // TODO: implement this } diff --git a/tests/multiboot2_header_print1.c b/tests/multiboot2_header_print1.c index b9608e0..0eab3d2 100644 --- a/tests/multiboot2_header_print1.c +++ b/tests/multiboot2_header_print1.c @@ -2,6 +2,10 @@ #include "config.h" #endif +#define KERNAUX_ACCESS_PROTECTED + +#include +#include #include #include @@ -10,14 +14,22 @@ #include "multiboot2_header_example1.h" -static void my_printf(const char *format, ...) +static void my_putc(void *display KERNAUX_UNUSED, char c) { - va_list va; - va_start(va, format); - vprintf(format, va); - va_end(va); + putchar(c); } +static +void my_vprintf(void *display KERNAUX_UNUSED, const char *format, va_list va) +{ + vprintf(format, va); +} + +static const struct KernAux_Display display = { + .putc = my_putc, + .vprintf = my_vprintf, +}; + void test_main() { assert(KernAux_Multiboot2_Header_is_valid( @@ -26,6 +38,6 @@ void test_main() KernAux_Multiboot2_Header_print( (struct KernAux_Multiboot2_Header*)&multiboot2_header_example1, - my_printf + &display ); } diff --git a/tests/multiboot2_header_print2.c b/tests/multiboot2_header_print2.c index faf79ec..50b41bb 100644 --- a/tests/multiboot2_header_print2.c +++ b/tests/multiboot2_header_print2.c @@ -2,6 +2,10 @@ #include "config.h" #endif +#define KERNAUX_ACCESS_PROTECTED + +#include +#include #include #include @@ -10,14 +14,22 @@ #include "multiboot2_header_example2.h" -static void my_printf(const char *format, ...) +static void my_putc(void *display KERNAUX_UNUSED, char c) { - va_list va; - va_start(va, format); - vprintf(format, va); - va_end(va); + putchar(c); } +static +void my_vprintf(void *display KERNAUX_UNUSED, const char *format, va_list va) +{ + vprintf(format, va); +} + +static const struct KernAux_Display display = { + .putc = my_putc, + .vprintf = my_vprintf, +}; + void test_main() { assert(KernAux_Multiboot2_Header_is_valid( @@ -26,6 +38,6 @@ void test_main() KernAux_Multiboot2_Header_print( &multiboot2_header_example2.multiboot2_header, - my_printf + &display ); } diff --git a/tests/multiboot2_info_print1.c b/tests/multiboot2_info_print1.c index e4bc411..095821a 100644 --- a/tests/multiboot2_info_print1.c +++ b/tests/multiboot2_info_print1.c @@ -2,6 +2,10 @@ #include "config.h" #endif +#define KERNAUX_ACCESS_PROTECTED + +#include +#include #include #include @@ -10,14 +14,22 @@ #include "multiboot2_info_example1.h" -static void my_printf(const char *format, ...) +static void my_putc(void *display KERNAUX_UNUSED, char c) { - va_list va; - va_start(va, format); - vprintf(format, va); - va_end(va); + putchar(c); } +static +void my_vprintf(void *display KERNAUX_UNUSED, const char *format, va_list va) +{ + vprintf(format, va); +} + +static const struct KernAux_Display display = { + .putc = my_putc, + .vprintf = my_vprintf, +}; + void test_main() { assert(KernAux_Multiboot2_Info_is_valid( @@ -26,6 +38,6 @@ void test_main() KernAux_Multiboot2_Info_print( (struct KernAux_Multiboot2_Info*)multiboot2_info_example1, - my_printf + &display ); } diff --git a/tests/multiboot2_info_print2.c b/tests/multiboot2_info_print2.c index 82007b6..30ed471 100644 --- a/tests/multiboot2_info_print2.c +++ b/tests/multiboot2_info_print2.c @@ -2,6 +2,10 @@ #include "config.h" #endif +#define KERNAUX_ACCESS_PROTECTED + +#include +#include #include #include @@ -10,14 +14,22 @@ #include "multiboot2_info_example2.h" -static void my_printf(const char *format, ...) +static void my_putc(void *display KERNAUX_UNUSED, char c) { - va_list va; - va_start(va, format); - vprintf(format, va); - va_end(va); + putchar(c); } +static +void my_vprintf(void *display KERNAUX_UNUSED, const char *format, va_list va) +{ + vprintf(format, va); +} + +static const struct KernAux_Display display = { + .putc = my_putc, + .vprintf = my_vprintf, +}; + void test_main() { assert(KernAux_Multiboot2_Info_is_valid( @@ -26,6 +38,6 @@ void test_main() KernAux_Multiboot2_Info_print( &multiboot2_info_example2.multiboot2_info, - my_printf + &display ); } From 6d91acc75f42a987e6f6534de3e501a0db75c9bc Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Sun, 11 Dec 2022 00:15:58 +0400 Subject: [PATCH 3/4] Add macros `KERNAUX_CAST_(VAR|CONST)` (#137) --- .gitignore | 1 + ChangeLog | 4 + README.md | 1 + configure.ac | 2 +- examples/Makefile.am | 8 ++ examples/macro_cast.c | 25 +++++ include/kernaux/macro.h | 21 ++++ make/checks.am | 1 + src/multiboot2/header_print.c | 20 ++-- src/multiboot2/info_print.c | 179 ++++++++++++++++++++++------------ 10 files changed, 191 insertions(+), 71 deletions(-) create mode 100644 examples/macro_cast.c diff --git a/.gitignore b/.gitignore index 270fa63..dcc56ba 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,7 @@ /examples/generic_malloc /examples/generic_mutex /examples/macro_bits +/examples/macro_cast /examples/macro_container_of /examples/macro_packing /examples/memmap diff --git a/ChangeLog b/ChangeLog index fdb0fa1..169f823 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-12-10 Alex Kotov + + * include/kernaux/macro.h: Macros "KERNAUX_CAST_(VAR|CONST)" have been added + 2022-12-09 Alex Kotov * include/kernaux/generic/display.h: The header has been added diff --git a/README.md b/README.md index 1bc3ba5..a328181 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ zero). Work-in-progress APIs can change at any time. * [Feature macros](/include/kernaux/version.h.in) (*work in progress*) * [Macros](/include/kernaux/macro.h) (*non-breaking since* **0.6.0**) * [Example: packing](/examples/macro_packing.c) + * [Example: CAST\_\*](/examples/macro_cast.c); * [Example: CONTAINER_OF](/examples/macro_container_of.c) * [Example: BITS](/examples/macro_bits.c) * [Assertions](/include/kernaux/assert.h) (*non-breaking since* **0.4.0**) diff --git a/configure.ac b/configure.ac index eb3b637..5237c02 100644 --- a/configure.ac +++ b/configure.ac @@ -331,7 +331,7 @@ AC_HEADER_STDBOOL AS_IF([test "$enable_checks" = yes -a "$ac_cv_header_stdbool_h" != yes], [AC_MSG_ERROR([the header is required])]) -AC_CHECK_HEADERS([stdarg.h stddef.h stdint.h],, +AC_CHECK_HEADERS([limits.h stdarg.h stddef.h stdint.h],, [AC_MSG_ERROR([the headers are required])]) AS_IF([test "$enable_checks" = yes], diff --git a/examples/Makefile.am b/examples/Makefile.am index b792a50..f3c6dcf 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -53,6 +53,14 @@ TESTS += macro_bits macro_bits_LDADD = $(top_builddir)/libkernaux.la macro_bits_SOURCES = main.c macro_bits.c +############## +# macro_cast # +############## + +TESTS += macro_cast +macro_cast_LDADD = $(top_builddir)/libkernaux.la +macro_cast_SOURCES = main.c macro_cast.c + ###################### # macro_container_of # ###################### diff --git a/examples/macro_cast.c b/examples/macro_cast.c new file mode 100644 index 0000000..11023a2 --- /dev/null +++ b/examples/macro_cast.c @@ -0,0 +1,25 @@ +#include + +#include +#include + +void example_main() +{ + const uint32_t value = 123; + + // const unsigned long ul = (unsigned long)value; + KERNAUX_CAST_CONST(unsigned long, ul, value); + assert(ul == 123); + + // unsigned long long ull = (unsigned long long)value; + KERNAUX_CAST_VAR(unsigned long long, ull, value); + assert(ull == 123); + + // const [signed] long sl = ([signed] long)value; + KERNAUX_CAST_CONST(long, sl, value); + assert(sl == 123); + + // [signed] long long sll = ([signed] long long)value; + KERNAUX_CAST_VAR(long long, sll, value); + assert(sll == 123); +} diff --git a/include/kernaux/macro.h b/include/kernaux/macro.h index 9cb0c58..820c43c 100644 --- a/include/kernaux/macro.h +++ b/include/kernaux/macro.h @@ -84,6 +84,27 @@ _kernaux_static_test_union_size_##name[ \ #define KERNAUX_BITS32(n) ((uint32_t)(((uint32_t)1) << (n))) #define KERNAUX_BITS64(n) ((uint64_t)(((uint64_t)1) << (n))) +/********************* + * Safe type casting * + *********************/ + +#define KERNAUX_CAST_VAR(type, name, value) \ + { \ + KERNAUX_UNUSED \ + static const int _kernaux_static_test_cast_pos_##name[ \ + sizeof(value) <= sizeof(type) ? 1 : -1 \ + ]; \ + KERNAUX_UNUSED \ + static const int _kernaux_static_test_cast_neg_##name[ \ + sizeof(-(value)) <= sizeof(type) ? 1 : -1 \ + ]; \ + } \ + type name = (type)(value); \ + do {} while (0) + +#define KERNAUX_CAST_CONST(type, name, value) \ + KERNAUX_CAST_VAR(const type, name, value) + #ifdef __cplusplus } #endif diff --git a/make/checks.am b/make/checks.am index 6268fd2..bfb0b86 100644 --- a/make/checks.am +++ b/make/checks.am @@ -20,6 +20,7 @@ CPPCHECK_INC = \ -I$(top_srcdir)/include CPPCHECK_SUPPRESS = \ + --suppress='constArgument:$(top_srcdir)/examples/macro_cast.c' \ --suppress='unusedStructMember:$(top_srcdir)/examples/multiboot2_header_macro.c' \ --suppress='unusedStructMember:$(top_srcdir)/tests/test_multiboot2_info_*.c' diff --git a/src/multiboot2/header_print.c b/src/multiboot2/header_print.c index 6804ae0..bfe76c8 100644 --- a/src/multiboot2/header_print.c +++ b/src/multiboot2/header_print.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -20,14 +21,18 @@ void KernAux_Multiboot2_Header_print( KERNAUX_ASSERT(multiboot2_header); KERNAUX_ASSERT(display); + KERNAUX_CAST_CONST(unsigned long, magic, multiboot2_header->magic); + KERNAUX_CAST_CONST(unsigned long, total_size, multiboot2_header->total_size); + KERNAUX_CAST_CONST(unsigned long, checksum, multiboot2_header->checksum); + PRINTLN("Multiboot 2 header"); - PRINTLNF(" magic: %u", multiboot2_header->magic); + PRINTLNF(" magic: %lu", magic); PRINTLNF(" arch: %u (%s)", multiboot2_header->arch, KernAux_Multiboot2_Header_Arch_to_str(multiboot2_header->arch) ); - PRINTLNF(" size: %u", multiboot2_header->total_size); - PRINTLNF(" checksum: %u", multiboot2_header->checksum); + PRINTLNF(" size: %lu", total_size); + PRINTLNF(" checksum: %lu", checksum); const struct KernAux_Multiboot2_HTagBase *tag_base = (struct KernAux_Multiboot2_HTagBase*) @@ -54,15 +59,16 @@ void KernAux_Multiboot2_HTagBase_print( if (!KernAux_Multiboot2_HTagBase_is_valid(tag_base)) return; - PRINTLN("Multiboot 2 header tag"); + KERNAUX_CAST_CONST(unsigned long, flags, tag_base->flags); + KERNAUX_CAST_CONST(unsigned long, size, tag_base->size); + PRINTLN("Multiboot 2 header tag"); PRINTLNF(" type: %u (%s)", tag_base->type, KernAux_Multiboot2_HTag_to_str(tag_base->type) ); - - PRINTLNF(" flags: %u", tag_base->flags); - PRINTLNF(" size: %u", tag_base->size); + PRINTLNF(" flags: %lu", flags); + PRINTLNF(" size: %lu", size); switch (tag_base->type) { case KERNAUX_MULTIBOOT2_HTAG_NONE: diff --git a/src/multiboot2/info_print.c b/src/multiboot2/info_print.c index 1cf2a93..7e9c473 100644 --- a/src/multiboot2/info_print.c +++ b/src/multiboot2/info_print.c @@ -3,6 +3,7 @@ #endif #include +#include #include #include @@ -22,9 +23,12 @@ void KernAux_Multiboot2_Info_print( KERNAUX_ASSERT(multiboot2_info); KERNAUX_ASSERT(display); + KERNAUX_CAST_CONST(unsigned long, total_size, multiboot2_info->total_size); + KERNAUX_CAST_CONST(unsigned long, reserved1, multiboot2_info->reserved1); + PRINTLN("Multiboot 2 info"); - PRINTLNF(" size: %u", multiboot2_info->total_size); - PRINTLNF(" reserved1: %u", multiboot2_info->reserved1); + PRINTLNF(" size: %lu", total_size); + PRINTLNF(" reserved1: %lu", reserved1); const struct KernAux_Multiboot2_ITagBase *tag_base = (struct KernAux_Multiboot2_ITagBase*) @@ -58,7 +62,8 @@ void KernAux_Multiboot2_ITagBase_print( KernAux_Multiboot2_ITag_to_str(tag_base->type) ); - PRINTLNF(" size: %u", tag_base->size); + KERNAUX_CAST_CONST(unsigned long, size, tag_base->size); + PRINTLNF(" size: %lu", size); switch (tag_base->type) { case KERNAUX_MULTIBOOT2_ITAG_NONE: @@ -80,8 +85,11 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_Module *const tag_module = (struct KernAux_Multiboot2_ITag_Module*)tag_base; - PRINTLNF(" start: %u", tag_module->mod_start); - PRINTLNF(" end: %u", tag_module->mod_end); + KERNAUX_CAST_CONST(unsigned long, mod_start, tag_module->mod_start); + KERNAUX_CAST_CONST(unsigned long, mod_end, tag_module->mod_end); + + PRINTLNF(" start: %lu", mod_start); + PRINTLNF(" end: %lu", mod_end); PRINTLNF(" cmdline: %s", KERNAUX_MULTIBOOT2_DATA(tag_module)); } break; @@ -90,8 +98,11 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *const tag_bmi = (struct KernAux_Multiboot2_ITag_BasicMemoryInfo*)tag_base; - PRINTLNF(" mem lower: %u", tag_bmi->mem_lower); - PRINTLNF(" mem upper: %u", tag_bmi->mem_upper); + KERNAUX_CAST_CONST(unsigned long, mem_lower, tag_bmi->mem_lower); + KERNAUX_CAST_CONST(unsigned long, mem_upper, tag_bmi->mem_upper); + + PRINTLNF(" mem lower: %lu", mem_lower); + PRINTLNF(" mem upper: %lu", mem_upper); } break; case KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE: @@ -99,9 +110,13 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_BIOSBootDevice *const tag_bbd = (struct KernAux_Multiboot2_ITag_BIOSBootDevice*)tag_base; - PRINTLNF(" bios dev: %u", tag_bbd->bios_dev); - PRINTLNF(" partition: %u", tag_bbd->partition); - PRINTLNF(" sub_partition: %u", tag_bbd->sub_partition); + KERNAUX_CAST_CONST(unsigned long, bios_dev, tag_bbd->bios_dev); + KERNAUX_CAST_CONST(unsigned long, partition, tag_bbd->partition); + KERNAUX_CAST_CONST(unsigned long, sub_partition, tag_bbd->sub_partition); + + PRINTLNF(" bios dev: %lu", bios_dev); + PRINTLNF(" partition: %lu", partition); + PRINTLNF(" sub_partition: %lu", sub_partition); } break; case KERNAUX_MULTIBOOT2_ITAG_MEMORY_MAP: @@ -115,10 +130,15 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_VBEInfo *const tag_vbe = (struct KernAux_Multiboot2_ITag_VBEInfo*)tag_base; - PRINTLNF(" VBE mode: %hu", tag_vbe->vbe_mode); - PRINTLNF(" VBE interface seg: %hu", tag_vbe->vbe_interface_seg); - PRINTLNF(" VBE interface off: %hu", tag_vbe->vbe_interface_off); - PRINTLNF(" VBE interface len: %hu", tag_vbe->vbe_interface_len); + KERNAUX_CAST_CONST(unsigned long, vbe_mode, tag_vbe->vbe_mode); + KERNAUX_CAST_CONST(unsigned long, vbe_interface_seg, tag_vbe->vbe_interface_seg); + KERNAUX_CAST_CONST(unsigned long, vbe_interface_off, tag_vbe->vbe_interface_off); + KERNAUX_CAST_CONST(unsigned long, vbe_interface_len, tag_vbe->vbe_interface_len); + + PRINTLNF(" VBE mode: %lu", vbe_mode); + PRINTLNF(" VBE interface seg: %lu", vbe_interface_seg); + PRINTLNF(" VBE interface off: %lu", vbe_interface_off); + PRINTLNF(" VBE interface len: %lu", vbe_interface_len); } break; case KERNAUX_MULTIBOOT2_ITAG_FRAMEBUFFER_INFO: @@ -126,16 +146,21 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_FramebufferInfo *const tag_fb = (struct KernAux_Multiboot2_ITag_FramebufferInfo*)tag_base; - PRINTLNF( - INT_IF(" framebuffer addr: %llu", " framebuffer addr: %lu"), - tag_fb->framebuffer_addr - ); - PRINTLNF(" framebuffer pitch: %u", tag_fb->framebuffer_pitch); - PRINTLNF(" framebuffer width: %u", tag_fb->framebuffer_width); - PRINTLNF(" framebuffer height: %u", tag_fb->framebuffer_height); - PRINTLNF(" framebuffer bpp: %u", tag_fb->framebuffer_bpp); - PRINTLNF(" framebuffer type: %u", tag_fb->framebuffer_type); - PRINTLNF(" reserved1: %u", tag_fb->reserved1); + KERNAUX_CAST_CONST(unsigned long long, framebuffer_addr, tag_fb->framebuffer_addr); + KERNAUX_CAST_CONST(unsigned long, framebuffer_pitch, tag_fb->framebuffer_pitch); + KERNAUX_CAST_CONST(unsigned long, framebuffer_width, tag_fb->framebuffer_width); + KERNAUX_CAST_CONST(unsigned long, framebuffer_height, tag_fb->framebuffer_height); + KERNAUX_CAST_CONST(unsigned long, framebuffer_bpp, tag_fb->framebuffer_bpp); + KERNAUX_CAST_CONST(unsigned long, framebuffer_type, tag_fb->framebuffer_type); + KERNAUX_CAST_CONST(unsigned long, reserved1, tag_fb->reserved1); + + PRINTLNF(" framebuffer addr: %llu", framebuffer_addr); + PRINTLNF(" framebuffer pitch: %lu", framebuffer_pitch); + PRINTLNF(" framebuffer width: %lu", framebuffer_width); + PRINTLNF(" framebuffer height: %lu", framebuffer_height); + PRINTLNF(" framebuffer bpp: %lu", framebuffer_bpp); + PRINTLNF(" framebuffer type: %lu", framebuffer_type); + PRINTLNF(" reserved1: %lu", reserved1); } break; case KERNAUX_MULTIBOOT2_ITAG_ELF_SYMBOLS: @@ -149,15 +174,25 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_APMTable *const tag_apm = (struct KernAux_Multiboot2_ITag_APMTable*)tag_base; - PRINTLNF(" version: %hu", tag_apm->version); - PRINTLNF(" cseg: %hu", tag_apm->cseg); - PRINTLNF(" offset: %u", tag_apm->offset); - PRINTLNF(" cseg 16: %hu", tag_apm->cseg_16); - PRINTLNF(" dseg: %hu", tag_apm->dseg); - PRINTLNF(" flags: %hu", tag_apm->flags); - PRINTLNF(" cseg len: %hu", tag_apm->cseg_len); - PRINTLNF(" cseg 16 len: %hu", tag_apm->cseg_16_len); - PRINTLNF(" dseg len: %hu", tag_apm->dseg_len); + KERNAUX_CAST_CONST(unsigned long, version, tag_apm->version); + KERNAUX_CAST_CONST(unsigned long, cseg, tag_apm->cseg); + KERNAUX_CAST_CONST(unsigned long, offset, tag_apm->offset); + KERNAUX_CAST_CONST(unsigned long, cseg_16, tag_apm->cseg_16); + KERNAUX_CAST_CONST(unsigned long, dseg, tag_apm->dseg); + KERNAUX_CAST_CONST(unsigned long, flags, tag_apm->flags); + KERNAUX_CAST_CONST(unsigned long, cseg_len, tag_apm->cseg_len); + KERNAUX_CAST_CONST(unsigned long, cseg_16_len, tag_apm->cseg_16_len); + KERNAUX_CAST_CONST(unsigned long, dseg_len, tag_apm->dseg_len); + + PRINTLNF(" version: %lu", version); + PRINTLNF(" cseg: %lu", cseg); + PRINTLNF(" offset: %lu", offset); + PRINTLNF(" cseg 16: %lu", cseg_16); + PRINTLNF(" dseg: %lu", dseg); + PRINTLNF(" flags: %lu", flags); + PRINTLNF(" cseg len: %lu", cseg_len); + PRINTLNF(" cseg 16 len: %lu", cseg_16_len); + PRINTLNF(" dseg len: %lu", dseg_len); } break; case KERNAUX_MULTIBOOT2_ITAG_EFI_32BIT_SYSTEM_TABLE_PTR: @@ -175,16 +210,22 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_SMBIOSTables *const tag_smbios = (struct KernAux_Multiboot2_ITag_SMBIOSTables*)tag_base; - PRINTLNF(" major: %u", tag_smbios->major); - PRINTLNF(" minor: %u", tag_smbios->minor); + KERNAUX_CAST_CONST(unsigned long, major, tag_smbios->major); + KERNAUX_CAST_CONST(unsigned long, minor, tag_smbios->minor); + KERNAUX_CAST_CONST(unsigned long, reserved0, tag_smbios->reserved1[0]); + KERNAUX_CAST_CONST(unsigned long, reserved1, tag_smbios->reserved1[1]); + KERNAUX_CAST_CONST(unsigned long, reserved2, tag_smbios->reserved1[2]); + KERNAUX_CAST_CONST(unsigned long, reserved3, tag_smbios->reserved1[3]); + KERNAUX_CAST_CONST(unsigned long, reserved4, tag_smbios->reserved1[4]); + KERNAUX_CAST_CONST(unsigned long, reserved5, tag_smbios->reserved1[5]); - PRINTLNF(" reserved1: {%u, %u, %u, %u, %u, %u}", - tag_smbios->reserved1[0], - tag_smbios->reserved1[1], - tag_smbios->reserved1[2], - tag_smbios->reserved1[3], - tag_smbios->reserved1[4], - tag_smbios->reserved1[5] + PRINTLNF(" major: %lu", major); + PRINTLNF(" minor: %lu", minor); + + PRINTLNF( + " reserved1: {%lu, %lu, %lu, %lu, %lu, %lu}", + reserved0, reserved1, reserved2, + reserved3, reserved4, reserved5 ); } break; @@ -221,10 +262,15 @@ void KernAux_Multiboot2_ITagBase_print( } break; case KERNAUX_MULTIBOOT2_ITAG_IMAGE_LOAD_BASE_PHYS_ADDR: - PRINTLNF(" load base addr: %u", - ((struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr*)tag_base)-> - load_base_addr - ); + { + KERNAUX_CAST_CONST( + unsigned long, + load_base_addr, + ((struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr*) + tag_base)->load_base_addr + ); + PRINTLNF(" load base addr: %lu", load_base_addr); + } break; } } @@ -271,8 +317,11 @@ void KernAux_Multiboot2_ITag_MemoryMap_print( return; } - PRINTLNF(" entry size: %u", tag->entry_size); - PRINTLNF(" entry version: %u", tag->entry_version); + KERNAUX_CAST_CONST(unsigned long, entry_size, tag->entry_size); + KERNAUX_CAST_CONST(unsigned long, entry_version, tag->entry_version); + + PRINTLNF(" entry size: %lu", entry_size); + PRINTLNF(" entry version: %lu", entry_version); PRINTLN(" entries:"); const struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase *const entries = @@ -284,17 +333,16 @@ void KernAux_Multiboot2_ITag_MemoryMap_print( index < (tag->base.size - sizeof(*tag)) / tag->entry_size; ++index ) { - PRINTLNF(INT_IF(" entry %u", " entry %lu"), index); - PRINTLNF( - INT_IF(" base addr: %llu", " base addr: %lu"), - entries[index].base_addr - ); - PRINTLNF( - INT_IF(" length: %llu", " length: %lu"), - entries[index].length - ); - PRINTLNF(" type: %u", entries[index].type); - PRINTLNF(" reserved1: %u", entries[index].reserved1); + KERNAUX_CAST_CONST(unsigned long long, base_addr, entries[index].base_addr); + KERNAUX_CAST_CONST(unsigned long long, length, entries[index].length); + KERNAUX_CAST_CONST(unsigned long, type, entries[index].type); + KERNAUX_CAST_CONST(unsigned long, reserved1, entries[index].reserved1); + + PRINTLNF(" entry %zu", index); + PRINTLNF(" base addr: %llu", base_addr); + PRINTLNF(" length: %llu", length); + PRINTLNF(" type: %lu", type); + PRINTLNF(" reserved1: %lu", reserved1); } } @@ -310,10 +358,15 @@ void KernAux_Multiboot2_ITag_ELFSymbols_print( return; } - PRINTLNF(" num: %hu", tag->num); - PRINTLNF(" entsize: %hu", tag->ent_size); - PRINTLNF(" shndx: %hu", tag->shndx); - PRINTLNF(" reserved1: %hu", tag->reserved1); + KERNAUX_CAST_CONST(unsigned long, num, tag->num); + KERNAUX_CAST_CONST(unsigned long, ent_size, tag->ent_size); + KERNAUX_CAST_CONST(unsigned long, shndx, tag->shndx); + KERNAUX_CAST_CONST(unsigned long, reserved1, tag->reserved1); + + PRINTLNF(" num: %lu", num); + PRINTLNF(" entsize: %lu", ent_size); + PRINTLNF(" shndx: %lu", shndx); + PRINTLNF(" reserved1: %lu", reserved1); // TODO: implement this } From c19193c390346b9e8b74fcb2bc225db6196342b6 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Sun, 11 Dec 2022 17:40:49 +0400 Subject: [PATCH 4/4] Add macro `KERNAUX_STATIC_TEST` (#138) --- .gitignore | 1 + ChangeLog | 4 ++++ README.md | 3 ++- examples/Makefile.am | 8 ++++++++ examples/macro_static_test.c | 28 ++++++++++++++++++++++++++++ include/kernaux/macro.h | 31 ++++++++++--------------------- make/checks.am | 2 +- 7 files changed, 54 insertions(+), 23 deletions(-) create mode 100644 examples/macro_static_test.c diff --git a/.gitignore b/.gitignore index dcc56ba..c44b26b 100644 --- a/.gitignore +++ b/.gitignore @@ -86,6 +86,7 @@ /examples/macro_cast /examples/macro_container_of /examples/macro_packing +/examples/macro_static_test /examples/memmap /examples/multiboot2_header_macro /examples/ntoa diff --git a/ChangeLog b/ChangeLog index 169f823..e659c8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-12-11 Alex Kotov + + * include/kernaux/macro.h: Macro "KERNAUX_STATIC_TEST" has been added + 2022-12-10 Alex Kotov * include/kernaux/macro.h: Macros "KERNAUX_CAST_(VAR|CONST)" have been added diff --git a/README.md b/README.md index a328181..69e5b44 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,9 @@ zero). Work-in-progress APIs can change at any time. * [Macros](/include/kernaux/macro.h) (*non-breaking since* **0.6.0**) * [Example: packing](/examples/macro_packing.c) * [Example: CAST\_\*](/examples/macro_cast.c); - * [Example: CONTAINER_OF](/examples/macro_container_of.c) + * [Example: CONTAINER\_OF](/examples/macro_container_of.c) * [Example: BITS](/examples/macro_bits.c) + * [Example: STATIC\_TEST\*](/examples/macro_static_test.c) * [Assertions](/include/kernaux/assert.h) (*non-breaking since* **0.4.0**) * [Example: Assert](/examples/assert.c) * [Example: Panic](/examples/panic.c) diff --git a/examples/Makefile.am b/examples/Makefile.am index f3c6dcf..dc33671 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -77,6 +77,14 @@ TESTS += macro_packing macro_packing_LDADD = $(top_builddir)/libkernaux.la macro_packing_SOURCES = main.c macro_packing.c +##################### +# macro_static_test # +##################### + +TESTS += macro_static_test +macro_static_test_LDADD = $(top_builddir)/libkernaux.la +macro_static_test_SOURCES = main.c macro_static_test.c + ########## # memmap # ########## diff --git a/examples/macro_static_test.c b/examples/macro_static_test.c new file mode 100644 index 0000000..c3bc054 --- /dev/null +++ b/examples/macro_static_test.c @@ -0,0 +1,28 @@ +#include + +#include + +KERNAUX_STATIC_TEST(uint8_t_size, sizeof(uint8_t) == 1); +KERNAUX_STATIC_TEST(uint16_t_size, sizeof(uint16_t) == 2); +KERNAUX_STATIC_TEST(uint32_t_size, sizeof(uint32_t) == 4); +KERNAUX_STATIC_TEST(uint64_t_size, sizeof(uint64_t) == 8); + +#include + +struct Foo { + uint8_t a; + uint32_t b; +} KERNAUX_PACKED; + +KERNAUX_STATIC_TEST_STRUCT_SIZE(Foo, 5); + +union Bar { + uint8_t a; + uint16_t b; +} KERNAUX_PACKED; + +KERNAUX_STATIC_TEST_UNION_SIZE(Bar, 2); + +#include + +void example_main() {} diff --git a/include/kernaux/macro.h b/include/kernaux/macro.h index 820c43c..4fb1795 100644 --- a/include/kernaux/macro.h +++ b/include/kernaux/macro.h @@ -50,19 +50,16 @@ extern "C" { * Static assertions * *********************/ +#define KERNAUX_STATIC_TEST(name, cond) \ + KERNAUX_UNUSED \ + static const int \ + _kernaux_static_test_##name[(cond) ? 1 : -1] + #define KERNAUX_STATIC_TEST_STRUCT_SIZE(name, size) \ -KERNAUX_UNUSED \ -static const int \ -_kernaux_static_test_struct_size_##name[ \ - sizeof(struct name) == (size) ? 1 : -1 \ -] + KERNAUX_STATIC_TEST(struct_size_##name, sizeof(struct name) == (size)) #define KERNAUX_STATIC_TEST_UNION_SIZE(name, size) \ -KERNAUX_UNUSED \ -static const int \ -_kernaux_static_test_union_size_##name[ \ - sizeof(union name) == (size) ? 1 : -1 \ -] + KERNAUX_STATIC_TEST(union_size_##name, sizeof(union name) == (size)) /***************** * Simple values * @@ -89,17 +86,9 @@ _kernaux_static_test_union_size_##name[ \ *********************/ #define KERNAUX_CAST_VAR(type, name, value) \ - { \ - KERNAUX_UNUSED \ - static const int _kernaux_static_test_cast_pos_##name[ \ - sizeof(value) <= sizeof(type) ? 1 : -1 \ - ]; \ - KERNAUX_UNUSED \ - static const int _kernaux_static_test_cast_neg_##name[ \ - sizeof(-(value)) <= sizeof(type) ? 1 : -1 \ - ]; \ - } \ - type name = (type)(value); \ + KERNAUX_STATIC_TEST(cast_pos_##name, sizeof(value) <= sizeof(type)); \ + KERNAUX_STATIC_TEST(cast_neg_##name, sizeof(-(value)) <= sizeof(type)); \ + type name = (type)(value); \ do {} while (0) #define KERNAUX_CAST_CONST(type, name, value) \ diff --git a/make/checks.am b/make/checks.am index bfb0b86..cd68bd1 100644 --- a/make/checks.am +++ b/make/checks.am @@ -21,7 +21,7 @@ CPPCHECK_INC = \ CPPCHECK_SUPPRESS = \ --suppress='constArgument:$(top_srcdir)/examples/macro_cast.c' \ - --suppress='unusedStructMember:$(top_srcdir)/examples/multiboot2_header_macro.c' \ + --suppress='unusedStructMember:$(top_srcdir)/examples/*.c' \ --suppress='unusedStructMember:$(top_srcdir)/tests/test_multiboot2_info_*.c' CPPCHECK_PATHS = \