From 123bddd19c39884f1de406873499bf0ca725a781 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Thu, 30 Jun 2022 23:07:10 +0300 Subject: [PATCH] File input (#107) --- examples/generic_file.c | 75 ++++++++++++++++------ include/kernaux/generic/file.h | 33 ++++++---- include/kernaux/macro.h | 2 + src/cmdline.c | 1 + src/generic/file.c | 113 ++++++++++++++++++++++++++++----- 5 files changed, 179 insertions(+), 45 deletions(-) diff --git a/examples/generic_file.c b/examples/generic_file.c index 0dedd82..14c8976 100644 --- a/examples/generic_file.c +++ b/examples/generic_file.c @@ -29,22 +29,37 @@ struct MyFile MyFile_create(char *ptr, size_t size); //=========== #include +#include #include -static int MyFile_putc(void *file, unsigned char c); +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.puts = NULL; // "puts" has a default implementation + 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; @@ -53,10 +68,18 @@ int MyFile_putc(void *const file, const unsigned char c) return c; } +void MyFile_rewind(void *const file) +{ + const MyFile my_file = file; + my_file->pos = 0; +} + //======== // main.c //======== +#include + #include #include @@ -65,31 +88,47 @@ 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 - { - const int result = KernAux_File_puts(&my_file.file, hello); - assert(result != KERNAUX_EOF); - } + assert(KernAux_File_puts(&my_file.file, hello) == true); // Write null character to the file - { - const int result = KernAux_File_putc(&my_file.file, '\0'); - assert(result != KERNAUX_EOF); - } - - char data[6]; - memset(data, 0xff, sizeof(data)); + assert(KernAux_File_putc(&my_file.file, '\0') != KERNAUX_EOF); // Write random data to the file - { - const int result = KernAux_File_write(&my_file.file, data, sizeof(data)); - assert(result != KERNAUX_EOF); - } + count = sizeof(data); + assert(KernAux_File_write(&my_file.file, data, &count) == true); + assert(count == sizeof(data)); - assert(strcmp(buffer, hello) == 0); + // 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/include/kernaux/generic/file.h b/include/kernaux/generic/file.h index 890d9f4..127deff 100644 --- a/include/kernaux/generic/file.h +++ b/include/kernaux/generic/file.h @@ -7,23 +7,34 @@ extern "C" { #include +#include #include -#define KERNAUX_EOF (-1) - -typedef int (*KernAux_File_Putc) (void *file, unsigned char c); -typedef int (*KernAux_File_Puts) (void *file, const char *s); -typedef int (*KernAux_File_Write)(void *file, const void *buffer, size_t count); +typedef int (*KernAux_File_Getc) (void *file); +typedef int (*KernAux_File_Putc) (void *file, unsigned char c); +typedef bool (*KernAux_File_Gets) (void *file, void *buffer, size_t *count); +typedef bool (*KernAux_File_Puts) (void *file, const char *s); +typedef bool (*KernAux_File_Read) (void *file, void *buffer, size_t *count); +typedef bool (*KernAux_File_Write) (void *file, const void *buffer, size_t *count); +typedef void (*KernAux_File_Rewind)(void *file); typedef const struct KernAux_File { - KernAux_File_Putc KERNAUX_PROTECTED_FIELD(putc); - KernAux_File_Puts KERNAUX_PROTECTED_FIELD(puts); - KernAux_File_Write KERNAUX_PROTECTED_FIELD(write); + KernAux_File_Getc KERNAUX_PROTECTED_FIELD(getc); + KernAux_File_Putc KERNAUX_PROTECTED_FIELD(putc); + KernAux_File_Gets KERNAUX_PROTECTED_FIELD(gets); + KernAux_File_Puts KERNAUX_PROTECTED_FIELD(puts); + KernAux_File_Read KERNAUX_PROTECTED_FIELD(read); + KernAux_File_Write KERNAUX_PROTECTED_FIELD(write); + KernAux_File_Rewind KERNAUX_PROTECTED_FIELD(rewind); } *KernAux_File; -int KernAux_File_putc (KernAux_File file, int c); -int KernAux_File_puts (KernAux_File file, const char *s); -int KernAux_File_write(KernAux_File file, const void *buffer, size_t count); +int KernAux_File_getc (KernAux_File file); +int KernAux_File_putc (KernAux_File file, int c); +bool KernAux_File_gets (KernAux_File file, void *buffer, size_t *count); +bool KernAux_File_puts (KernAux_File file, const char *s); +bool KernAux_File_read (KernAux_File file, void *buffer, size_t *count); +bool KernAux_File_write (KernAux_File file, const void *buffer, size_t *count); +void KernAux_File_rewind(KernAux_File file); #ifdef __cplusplus } diff --git a/include/kernaux/macro.h b/include/kernaux/macro.h index e31c1f5..0c35c90 100644 --- a/include/kernaux/macro.h +++ b/include/kernaux/macro.h @@ -8,6 +8,8 @@ extern "C" { #include #include +#define KERNAUX_EOF (-1) + #define KERNAUX_CONTAINER_OF(ptr, type, member) \ ((type*)((uintptr_t)(ptr) - offsetof(type, member))) diff --git a/src/cmdline.c b/src/cmdline.c index 2527e76..197d538 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/src/generic/file.c b/src/generic/file.c index 8786582..770d954 100644 --- a/src/generic/file.c +++ b/src/generic/file.c @@ -4,9 +4,19 @@ #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); @@ -15,43 +25,114 @@ int KernAux_File_putc(const KernAux_File file, const int c) return file->putc((void*)file, c); } -int KernAux_File_puts(const KernAux_File file, const char *const s) +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 0; + if (!s) return true; // Inherited implementation if (file->puts) return file->puts((void*)file, s); // Default implementation - size_t ccount = 0; - for (const char *ss = s; *ss; ++ss, ++ccount) { - if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return KERNAUX_EOF; + for (const char *ss = s; *ss; ++ss) { + if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return false; } - const int icount = ccount; - return icount >= 0 ? icount : 0; + return true; } -int KernAux_File_write( +bool KernAux_File_read( const KernAux_File file, - const void *const buffer, - const size_t count + void *const buffer, + size_t *const count ) { KERNAUX_ASSERT(file); + KERNAUX_ASSERT(buffer); + KERNAUX_ASSERT(count); // Common implementation - if (count == 0 || !buffer) return 0; + 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 ccount = 0; - for (const char *ss = buffer; ccount < count; ++ss, ++ccount) { - if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return KERNAUX_EOF; + size_t index = 0; + for (const char *ss = buffer; index < *count; ++ss, ++index) { + if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return false; } - const int icount = ccount; - return icount >= 0 ? icount : 0; + return true; +} + +void KernAux_File_rewind(const KernAux_File file) +{ + KERNAUX_ASSERT(file); + KERNAUX_ASSERT(file->rewind); + + file->rewind((void*)file); }