diff --git a/.cirrus.yml b/.cirrus.yml index bb4e4c0..61aa719 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -2,7 +2,7 @@ # For GNU/Linux CI see GitHub Actions. freebsd_instance: - image_family: freebsd-13-0 + image_family: freebsd-13-1 main_freebsd_task: name: Main (FreeBSD) diff --git a/.gitignore b/.gitignore index 096540b..a7343fb 100644 --- a/.gitignore +++ b/.gitignore @@ -107,7 +107,6 @@ /examples/assert /examples/cmdline -/examples/generic_file /examples/generic_malloc /examples/generic_mutex /examples/macro_bits diff --git a/ChangeLog b/ChangeLog index c53b646..5c380a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-11-26 Alex Kotov + + * include/kernaux/printf.h: Change API + 2022-06-30 Alex Kotov * include/kernaux/macro.h: Added macros "KERNAUX_BITS[8|16|32|64]" @@ -9,9 +13,7 @@ 2022-06-25 Alex Kotov * configure.ac: Removed package "io" - * include/kernaux/generic/file.h: Added * include/kernaux/io.h: Removed - * include/kernaux/printf.h: Use new file API 2022-06-24 Alex Kotov diff --git a/Makefile.am b/Makefile.am index 5f42b2b..6f9b537 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,7 +31,6 @@ libkernaux_la_LIBADD = libkernaux_la_SOURCES = \ src/assert.c \ src/libc.h \ - src/generic/file.c \ src/generic/malloc.c \ src/generic/mutex.c diff --git a/README.md b/README.md index 7ab6533..445171e 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,6 @@ zero). Work-in-progress APIs can change at any time. * [Example: Panic](/examples/panic.c) * Stack trace *(planned)* * Generic types - * [File](/include/kernaux/generic/file.h) (*non-breaking since* **?.?.?**) - * [Example](/examples/generic_file.c) * [Memory allocator](/include/kernaux/generic/malloc.h) (*non-breaking since* **?.?.?**) * [Example](/examples/generic_malloc.c) * [Mutex](/include/kernaux/generic/mutex.h) (*non-breaking since* **?.?.?**) diff --git a/bindings/mruby/test/printf.rb b/bindings/mruby/test/printf.rb index 922567e..13c311d 100644 --- a/bindings/mruby/test/printf.rb +++ b/bindings/mruby/test/printf.rb @@ -63,6 +63,8 @@ if KernAux::Version.with_printf? else raise "Unknown format: #{args.inspect}" end + elsif item.is_a?(Float) && item.round == item + item.round else item end diff --git a/examples/Makefile.am b/examples/Makefile.am index 31bc40f..d3f56ac 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -21,14 +21,6 @@ cmdline_LDADD = $(top_builddir)/libkernaux.la cmdline_SOURCES = main.c cmdline.c endif -################ -# generic_file # -################ - -TESTS += generic_file -generic_file_LDADD = $(top_builddir)/libkernaux.la -generic_file_SOURCES = main.c generic_file.c - ################## # generic_malloc # ################## diff --git a/examples/generic_file.c b/examples/generic_file.c deleted file mode 100644 index 14c8976..0000000 --- a/examples/generic_file.c +++ /dev/null @@ -1,134 +0,0 @@ -//=========== -// my_file.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_file.h -//=========== - -#include -#include - -typedef struct MyFile { - struct KernAux_File file; - char *ptr; - size_t size; - size_t pos; -} *MyFile; - -struct MyFile MyFile_create(char *ptr, size_t size); - -//=========== -// my_file.c -//=========== - -#include -#include -#include - -static int MyFile_getc (void *file); -static int MyFile_putc (void *file, unsigned char c); -static void MyFile_rewind(void *file); - -struct MyFile MyFile_create(char *const ptr, const size_t size) -{ - struct MyFile my_file; - my_file.file.getc = MyFile_getc; - my_file.file.putc = MyFile_putc; - my_file.file.gets = NULL; // "gets" has a default implementation - my_file.file.puts = NULL; // "puts" has a default implementation - my_file.file.read = NULL; // "read" has a default implementation - my_file.file.write = NULL; // "write" has a default implementation - my_file.file.rewind = MyFile_rewind; - my_file.ptr = ptr; - my_file.size = size; - my_file.pos = 0; - return my_file; -} - -int MyFile_getc(void *const file) -{ - const MyFile my_file = file; - if (my_file->pos >= my_file->size) return KERNAUX_EOF; - const unsigned char c = my_file->ptr[my_file->pos++]; - return c; -} - -int MyFile_putc(void *const file, const unsigned char c) -{ - const MyFile my_file = file; - if (my_file->pos >= my_file->size) return KERNAUX_EOF; - my_file->ptr[my_file->pos++] = c; - return c; -} - -void MyFile_rewind(void *const file) -{ - const MyFile my_file = file; - my_file->pos = 0; -} - -//======== -// main.c -//======== - -#include - -#include -#include - -static const char *const hello = "Hello, World!"; - -void example_main() -{ - char buffer[20]; - char tmp_buffer[20]; - size_t count; - - char data[6]; - memset(&data[0], 0xf0, 3); - memset(&data[3], 0xff, 3); - - - // Create file - struct MyFile my_file = MyFile_create(buffer, sizeof(buffer)); - - // Write "Hello, World!" to the file - assert(KernAux_File_puts(&my_file.file, hello) == true); - - // Write null character to the file - assert(KernAux_File_putc(&my_file.file, '\0') != KERNAUX_EOF); - - // Write random data to the file - count = sizeof(data); - assert(KernAux_File_write(&my_file.file, data, &count) == true); - assert(count == sizeof(data)); - - // Seek to the beginning of the file - KernAux_File_rewind(&my_file.file); - - // Read a line from the file - count = 14; - assert(KernAux_File_gets(&my_file.file, tmp_buffer, &count) == true); - assert(count == 14); - - // Read random data from the file - count = 6; - assert(KernAux_File_read(&my_file.file, &tmp_buffer[14], &count) == true); - assert(count == 6); - - // Read a single character from the file - assert(KernAux_File_getc(&my_file.file) == KERNAUX_EOF); - - - assert(strcmp(&buffer[0], hello) == 0); - assert(memcmp(&buffer[14], data, sizeof(data)) == 0); - assert(strcmp(&tmp_buffer[0], hello) == 0); - assert(memcmp(&tmp_buffer[14], data, sizeof(data)) == 0); -} diff --git a/examples/printf_file.c b/examples/printf_file.c index 53e7ebc..1b5f8bc 100644 --- a/examples/printf_file.c +++ b/examples/printf_file.c @@ -1,6 +1,3 @@ -#define KERNAUX_ACCESS_PROTECTED - -#include #include #include @@ -10,26 +7,23 @@ #define BUFFER_SIZE 1024 +static const char *const data = "foobar"; + static char buffer[BUFFER_SIZE]; static size_t buffer_index = 0; -static int my_putc(__attribute__((unused)) void *const file, unsigned char c) +static void my_putchar(const char chr, void *arg) { + assert(arg == data); if (buffer_index >= BUFFER_SIZE) abort(); - buffer[buffer_index++] = c; - return 1; + buffer[buffer_index++] = chr; } -static const struct KernAux_File file = { - .putc = my_putc, - .puts = NULL, - .write = NULL, -}; - void example_main() { const int result = kernaux_fprintf( - &file, + my_putchar, + (void*)data, "Hello, %s! Session ID: %u.", "Alex", 123 diff --git a/examples/printf_file_va.c b/examples/printf_file_va.c index 029a5c5..75562bc 100644 --- a/examples/printf_file_va.c +++ b/examples/printf_file_va.c @@ -1,6 +1,3 @@ -#define KERNAUX_ACCESS_PROTECTED - -#include #include #include @@ -10,27 +7,23 @@ #define BUFFER_SIZE 1024 +static const char *const data = "foobar"; + static char buffer[BUFFER_SIZE]; static size_t buffer_index = 0; -static int my_putc(__attribute__((unused)) void *const file, unsigned char c) +static void my_putchar(const char chr, void *arg) { + assert(arg == data); if (buffer_index >= BUFFER_SIZE) abort(); - buffer[buffer_index++] = c; - return 1; + buffer[buffer_index++] = chr; } -static const struct KernAux_File file = { - .putc = my_putc, - .puts = NULL, - .write = NULL, -}; - static int my_printf(const char *const format, ...) { va_list va; va_start(va, format); - const int result = kernaux_vfprintf(&file, format, va); + const int result = kernaux_vfprintf(my_putchar, (void*)data, format, va); va_end(va); return result; } diff --git a/include/Makefile.am b/include/Makefile.am index a264a46..5592be4 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -9,7 +9,6 @@ nobase_include_HEADERS = \ kernaux/macro/packing_start.run \ kernaux/macro/packing_end.run \ kernaux/version.h \ - kernaux/generic/file.h \ kernaux/generic/malloc.h \ kernaux/generic/mutex.h diff --git a/include/kernaux.h.in b/include/kernaux.h.in index 3ce50c2..e1fe0ff 100644 --- a/include/kernaux.h.in +++ b/include/kernaux.h.in @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/include/kernaux/cmdline.h b/include/kernaux/cmdline.h index a44a276..57149e0 100644 --- a/include/kernaux/cmdline.h +++ b/include/kernaux/cmdline.h @@ -5,8 +5,6 @@ extern "C" { #endif -#include - #include #include diff --git a/include/kernaux/printf.h b/include/kernaux/printf.h index f89978f..19caedc 100644 --- a/include/kernaux/printf.h +++ b/include/kernaux/printf.h @@ -5,20 +5,19 @@ extern "C" { #endif -#include - #include #include /** * Tiny [v]fprintf implementation - * \param file An output file + * \param out An output function + * \param data Additional data for the output function * \param format A string that specifies the format of the output * \param va A value identifying a variable arguments list * \return The number of characters that are sent to the output function, not counting the terminating null character */ -int kernaux_fprintf(KernAux_File file, const char* format, ...); -int kernaux_vfprintf(KernAux_File file, const char* format, va_list va); +int kernaux_fprintf(void (*out)(char, void*), void *data, const char* format, ...); +int kernaux_vfprintf(void (*out)(char, void*), void *data, const char* format, va_list va); /** * Tiny [v]snprintf implementation diff --git a/src/cmdline.c b/src/cmdline.c index 197d538..b76af7d 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -27,7 +26,6 @@ static bool kernaux_cmdline_common( char arg_terminator, char **argv, char *buffer, - KernAux_File file, size_t *arg_idxs, size_t arg_count_max, size_t buffer_size @@ -42,7 +40,6 @@ static bool kernaux_cmdline_iter( char arg_terminator, char **argv, char *buffer, - KernAux_File file, size_t *arg_idxs, size_t arg_count_max, size_t buffer_size @@ -76,7 +73,6 @@ bool kernaux_cmdline( argv, buffer, NULL, - NULL, arg_count_max, buffer_size ); @@ -100,7 +96,6 @@ bool kernaux_cmdline_common( char arg_terminator, char **const argv, char *const buffer, - const KernAux_File file, size_t *const arg_idxs, const size_t arg_count_max, const size_t buffer_size @@ -128,7 +123,6 @@ bool kernaux_cmdline_common( arg_terminator, argv, buffer, - file, arg_idxs, arg_count_max, buffer_size @@ -159,11 +153,6 @@ fail: if (buffer) { \ buffer[*buffer_or_file_pos] = char; \ } \ - if (file) { \ - if (KernAux_File_putc(file, char) == KERNAUX_EOF) { \ - FAIL("EOF or buffer overflow"); \ - } \ - } \ ++(*buffer_or_file_pos); \ } while (0) @@ -191,11 +180,6 @@ fail: argv[*argc] = &buffer[*buffer_or_file_pos]; \ buffer[*buffer_or_file_pos] = char; \ } \ - if (file) { \ - if (KernAux_File_putc(file, char) == KERNAUX_EOF) { \ - FAIL("EOF or buffer overflow"); \ - } \ - } \ if (arg_idxs) { \ arg_idxs[*argc] = *buffer_or_file_pos; \ } \ @@ -212,7 +196,6 @@ bool kernaux_cmdline_iter( char arg_terminator, char **const argv, char *const buffer, - const KernAux_File file, size_t *const arg_idxs, const size_t arg_count_max, const size_t buffer_size diff --git a/src/drivers/console.c b/src/drivers/console.c index 9d91fda..a206f76 100644 --- a/src/drivers/console.c +++ b/src/drivers/console.c @@ -4,7 +4,6 @@ #include #include -#include #ifdef ASM_I386 #include @@ -20,13 +19,7 @@ #include #ifdef WITH_PRINTF -static int file_putc(void *file, unsigned char c); - -static const struct KernAux_File file = { - .putc = file_putc, - .puts = NULL, - .write = NULL, -}; +static void file_putc(char c, void *arg); #endif void kernaux_drivers_console_putc(const char c __attribute__((unused))) @@ -55,7 +48,7 @@ void kernaux_drivers_console_printf(const char *format, ...) va_list va; va_start(va, format); - kernaux_vfprintf(&file, format, va); + kernaux_vfprintf(file_putc, NULL, format, va); va_end(va); } #endif @@ -78,9 +71,8 @@ void kernaux_drivers_console_write(const char *const data, const size_t size) } #ifdef WITH_PRINTF -int file_putc(__attribute__((unused)) void *const file, const unsigned char c) +void file_putc(char c, void *arg __attribute__((unused))) { kernaux_drivers_console_putc(c); - return 1; } #endif diff --git a/src/generic/file.c b/src/generic/file.c deleted file mode 100644 index 770d954..0000000 --- a/src/generic/file.c +++ /dev/null @@ -1,138 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include - -int KernAux_File_getc(const KernAux_File file) -{ - KERNAUX_ASSERT(file); - KERNAUX_ASSERT(file->getc); - - return file->getc((void*)file); -} - -int KernAux_File_putc(const KernAux_File file, const int c) -{ - KERNAUX_ASSERT(file); - KERNAUX_ASSERT(file->putc); - - return file->putc((void*)file, c); -} - -bool KernAux_File_gets( - const KernAux_File file, - void *const buffer, - size_t *const count -) { - KERNAUX_ASSERT(file); - KERNAUX_ASSERT(buffer); - KERNAUX_ASSERT(count); - // Reserve space for the terminating null character - KERNAUX_ASSERT(*count > 0); - - // Common implementation - if (*count == 1) { - *((char*)buffer) = '\0'; - return true; - } - - // Inherited implementation - if (file->gets) return file->gets((void*)file, buffer, count); - - // Default implementation - size_t index = 0; - for (char *ss = buffer; index < *count; ++ss, ++index) { - const int c = KernAux_File_getc(file); - if (c == KERNAUX_EOF || c == '\0' || c == '\n') { - *ss = '\0'; - *count = index + 1; - return true; - } - *ss = c; - } - ((char*)buffer)[index] = '\0'; - *count = index; - return false; -} - -bool KernAux_File_puts(const KernAux_File file, const char *const s) -{ - KERNAUX_ASSERT(file); - - // Common implementation - if (!s) return true; - - // Inherited implementation - if (file->puts) return file->puts((void*)file, s); - - // Default implementation - for (const char *ss = s; *ss; ++ss) { - if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return false; - } - return true; -} - -bool KernAux_File_read( - const KernAux_File file, - void *const buffer, - size_t *const count -) { - KERNAUX_ASSERT(file); - KERNAUX_ASSERT(buffer); - KERNAUX_ASSERT(count); - - // Common implementation - if (*count == 0) return true; - - // Inherited implementation - if (file->read) return file->read((void*)file, buffer, count); - - // Default implementation - size_t index = 0; - for (char *ss = buffer; index < *count; ++ss, ++index) { - const int c = KernAux_File_getc(file); - if (c == KERNAUX_EOF) { - *count = index; - return false; - } - *ss = c; - } - *count = index; - return true; -} - -bool KernAux_File_write( - const KernAux_File file, - const void *const buffer, - size_t *const count -) { - KERNAUX_ASSERT(file); - KERNAUX_ASSERT(buffer); - - // Common implementation - if (*count == 0) return true; - - // Inherited implementation - if (file->write) return file->write((void*)file, buffer, count); - - // Default implementation - size_t index = 0; - for (const char *ss = buffer; index < *count; ++ss, ++index) { - if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return false; - } - return true; -} - -void KernAux_File_rewind(const KernAux_File file) -{ - KERNAUX_ASSERT(file); - KERNAUX_ASSERT(file->rewind); - - file->rewind((void*)file); -} diff --git a/src/printf.c b/src/printf.c index 5829548..8ffb6bb 100644 --- a/src/printf.c +++ b/src/printf.c @@ -14,7 +14,6 @@ #endif #include -#include #include #include @@ -53,8 +52,6 @@ typedef struct { static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va); -static void file_putc(char c, void *arg); - static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen); static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen); static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen); @@ -72,25 +69,25 @@ static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, d * Implementations: main API * *****************************/ -int kernaux_fprintf(const KernAux_File file, const char* format, ...) +int kernaux_fprintf(void (*out)(char, void*), void *data, const char* format, ...) { - KERNAUX_ASSERT(file); + KERNAUX_ASSERT(out); KERNAUX_ASSERT(format); va_list va; va_start(va, format); - const out_fct_wrap_type out_fct_wrap = { file_putc, (void*)file }; + const out_fct_wrap_type out_fct_wrap = { out, data }; const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); va_end(va); return ret; } -int kernaux_vfprintf(const KernAux_File file, const char* format, va_list va) +int kernaux_vfprintf(void (*out)(char, void*), void *data, const char* format, va_list va) { - KERNAUX_ASSERT(file); + KERNAUX_ASSERT(out); KERNAUX_ASSERT(format); - const out_fct_wrap_type out_fct_wrap = { file_putc, (void*)file }; + const out_fct_wrap_type out_fct_wrap = { out, data }; return _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); } @@ -126,16 +123,6 @@ int kernaux_sprintf(char* buffer, const char* format, ...) return ret; } -/*************************** - * Implementation: file IO * - ***************************/ - -void file_putc(const char c, void *const arg) -{ - KernAux_File file = arg; - KernAux_File_putc(file, c); -} - /****************************************** * Implementation: main internal function * ******************************************/ diff --git a/tests/printf_gen.jinja b/tests/printf_gen.jinja index 22eb21f..3b4127d 100644 --- a/tests/printf_gen.jinja +++ b/tests/printf_gen.jinja @@ -4,7 +4,6 @@ #define KERNAUX_ACCESS_PROTECTED -#include #include #include @@ -15,10 +14,12 @@ #define BUFFER_SIZE 1024 +static const char *const data = "foobar"; + static char buffer[BUFFER_SIZE]; static size_t buffer_index; -static int test_putc(__attribute__((unused)) void *const file, unsigned char c) +static void test_putc(char c, __attribute__((unused)) void *arg) { if (buffer_index >= BUFFER_SIZE) { printf("Buffer overflow!\n"); @@ -26,15 +27,8 @@ static int test_putc(__attribute__((unused)) void *const file, unsigned char c) } buffer[buffer_index++] = c; - return 1; } -static const struct KernAux_File file = { - .putc = test_putc, - .puts = NULL, - .write = NULL, -}; - static void test(const char *const expected, const char *const format, ...) { va_list va; @@ -43,7 +37,7 @@ static void test(const char *const expected, const char *const format, ...) memset(buffer, '\0', sizeof(buffer)); buffer_index = 0; va_start(va, format); - result = kernaux_vfprintf(&file, format, va); + result = kernaux_vfprintf(test_putc, (void*)data, format, va); va_end(va); assert((size_t)result == strlen(expected)); assert(strcmp(expected, buffer) == 0); @@ -61,7 +55,7 @@ void test_main() { memset(buffer, '\0', sizeof(buffer)); buffer_index = 0; - kernaux_fprintf(&file, "Hello, World!"); + kernaux_fprintf(test_putc, (void*)data, "Hello, World!"); assert(strcmp("Hello, World!", buffer) == 0); {% for case in cases %}