File input (#107)

This commit is contained in:
Alex Kotov 2022-06-30 23:07:10 +03:00 committed by GitHub
parent ab1773964c
commit 123bddd19c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 179 additions and 45 deletions

View File

@ -29,22 +29,37 @@ struct MyFile MyFile_create(char *ptr, size_t size);
//=========== //===========
#include <kernaux/generic/file.h> #include <kernaux/generic/file.h>
#include <kernaux/macro.h>
#include <stddef.h> #include <stddef.h>
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 MyFile_create(char *const ptr, const size_t size)
{ {
struct MyFile my_file; struct MyFile my_file;
my_file.file.getc = MyFile_getc;
my_file.file.putc = MyFile_putc; 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.write = NULL; // "write" has a default implementation
my_file.file.rewind = MyFile_rewind;
my_file.ptr = ptr; my_file.ptr = ptr;
my_file.size = size; my_file.size = size;
my_file.pos = 0; my_file.pos = 0;
return my_file; 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) int MyFile_putc(void *const file, const unsigned char c)
{ {
const MyFile my_file = file; const MyFile my_file = file;
@ -53,10 +68,18 @@ int MyFile_putc(void *const file, const unsigned char c)
return c; return c;
} }
void MyFile_rewind(void *const file)
{
const MyFile my_file = file;
my_file->pos = 0;
}
//======== //========
// main.c // main.c
//======== //========
#include <kernaux/macro.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
@ -65,31 +88,47 @@ static const char *const hello = "Hello, World!";
void example_main() void example_main()
{ {
char buffer[20]; 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 // Create file
struct MyFile my_file = MyFile_create(buffer, sizeof(buffer)); struct MyFile my_file = MyFile_create(buffer, sizeof(buffer));
// Write "Hello, World!" to the file // Write "Hello, World!" to the file
{ assert(KernAux_File_puts(&my_file.file, hello) == true);
const int result = KernAux_File_puts(&my_file.file, hello);
assert(result != KERNAUX_EOF);
}
// Write null character to the file // Write null character to the file
{ assert(KernAux_File_putc(&my_file.file, '\0') != KERNAUX_EOF);
const int result = KernAux_File_putc(&my_file.file, '\0');
assert(result != KERNAUX_EOF);
}
char data[6];
memset(data, 0xff, sizeof(data));
// Write random data to the file // Write random data to the file
{ count = sizeof(data);
const int result = KernAux_File_write(&my_file.file, data, sizeof(data)); assert(KernAux_File_write(&my_file.file, data, &count) == true);
assert(result != KERNAUX_EOF); 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(memcmp(&buffer[14], data, sizeof(data)) == 0);
assert(strcmp(&tmp_buffer[0], hello) == 0);
assert(memcmp(&tmp_buffer[14], data, sizeof(data)) == 0);
} }

View File

@ -7,23 +7,34 @@ extern "C" {
#include <kernaux/macro.h> #include <kernaux/macro.h>
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#define KERNAUX_EOF (-1) typedef int (*KernAux_File_Getc) (void *file);
typedef int (*KernAux_File_Putc) (void *file, unsigned char c);
typedef int (*KernAux_File_Putc) (void *file, unsigned char c); typedef bool (*KernAux_File_Gets) (void *file, void *buffer, size_t *count);
typedef int (*KernAux_File_Puts) (void *file, const char *s); typedef bool (*KernAux_File_Puts) (void *file, const char *s);
typedef int (*KernAux_File_Write)(void *file, const void *buffer, size_t count); 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 { typedef const struct KernAux_File {
KernAux_File_Putc KERNAUX_PROTECTED_FIELD(putc); KernAux_File_Getc KERNAUX_PROTECTED_FIELD(getc);
KernAux_File_Puts KERNAUX_PROTECTED_FIELD(puts); KernAux_File_Putc KERNAUX_PROTECTED_FIELD(putc);
KernAux_File_Write KERNAUX_PROTECTED_FIELD(write); 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; } *KernAux_File;
int KernAux_File_putc (KernAux_File file, int c); int KernAux_File_getc (KernAux_File file);
int KernAux_File_puts (KernAux_File file, const char *s); int KernAux_File_putc (KernAux_File file, int c);
int KernAux_File_write(KernAux_File file, const void *buffer, size_t count); 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 #ifdef __cplusplus
} }

View File

@ -8,6 +8,8 @@ extern "C" {
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#define KERNAUX_EOF (-1)
#define KERNAUX_CONTAINER_OF(ptr, type, member) \ #define KERNAUX_CONTAINER_OF(ptr, type, member) \
((type*)((uintptr_t)(ptr) - offsetof(type, member))) ((type*)((uintptr_t)(ptr) - offsetof(type, member)))

View File

@ -5,6 +5,7 @@
#include <kernaux/assert.h> #include <kernaux/assert.h>
#include <kernaux/cmdline.h> #include <kernaux/cmdline.h>
#include <kernaux/generic/file.h> #include <kernaux/generic/file.h>
#include <kernaux/macro.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>

View File

@ -4,9 +4,19 @@
#include <kernaux/assert.h> #include <kernaux/assert.h>
#include <kernaux/generic/file.h> #include <kernaux/generic/file.h>
#include <kernaux/macro.h>
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
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) int KernAux_File_putc(const KernAux_File file, const int c)
{ {
KERNAUX_ASSERT(file); KERNAUX_ASSERT(file);
@ -15,43 +25,114 @@ int KernAux_File_putc(const KernAux_File file, const int c)
return file->putc((void*)file, 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); KERNAUX_ASSERT(file);
// Common implementation // Common implementation
if (!s) return 0; if (!s) return true;
// Inherited implementation // Inherited implementation
if (file->puts) return file->puts((void*)file, s); if (file->puts) return file->puts((void*)file, s);
// Default implementation // Default implementation
size_t ccount = 0; for (const char *ss = s; *ss; ++ss) {
for (const char *ss = s; *ss; ++ss, ++ccount) { if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return false;
if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return KERNAUX_EOF;
} }
const int icount = ccount; return true;
return icount >= 0 ? icount : 0;
} }
int KernAux_File_write( bool KernAux_File_read(
const KernAux_File file, const KernAux_File file,
const void *const buffer, void *const buffer,
const size_t count size_t *const count
) { ) {
KERNAUX_ASSERT(file); KERNAUX_ASSERT(file);
KERNAUX_ASSERT(buffer);
KERNAUX_ASSERT(count);
// Common implementation // 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 // Inherited implementation
if (file->write) return file->write((void*)file, buffer, count); if (file->write) return file->write((void*)file, buffer, count);
// Default implementation // Default implementation
size_t ccount = 0; size_t index = 0;
for (const char *ss = buffer; ccount < count; ++ss, ++ccount) { for (const char *ss = buffer; index < *count; ++ss, ++index) {
if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return KERNAUX_EOF; if (KernAux_File_putc(file, *ss) == KERNAUX_EOF) return false;
} }
const int icount = ccount; return true;
return icount >= 0 ? icount : 0; }
void KernAux_File_rewind(const KernAux_File file)
{
KERNAUX_ASSERT(file);
KERNAUX_ASSERT(file->rewind);
file->rewind((void*)file);
} }