mirror of https://github.com/tailix/libkernaux.git
Add generic type for files (#96)
This commit is contained in:
parent
73a17df3dc
commit
6e2766b938
|
@ -110,6 +110,7 @@
|
|||
/examples/cmdline
|
||||
/examples/fprintf
|
||||
/examples/fprintf_va
|
||||
/examples/generic_file
|
||||
/examples/generic_malloc
|
||||
/examples/generic_mutex
|
||||
/examples/memmap
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2022-06-25 Alex Kotov <kotovalexarian@gmail.com>
|
||||
|
||||
* include/kernaux/generic/file.h: Added
|
||||
|
||||
2022-06-24 Alex Kotov <kotovalexarian@gmail.com>
|
||||
|
||||
* configure.ac: Added packages "arch-*" and "asm"
|
||||
|
|
|
@ -31,6 +31,7 @@ libkernaux_la_LIBADD =
|
|||
libkernaux_la_SOURCES = \
|
||||
src/assert.c \
|
||||
src/libc.h \
|
||||
src/generic/file.c \
|
||||
src/generic/malloc.c \
|
||||
src/generic/mutex.c
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ zero). Work-in-progress APIs can change at any time.
|
|||
* [Declarations](/include/kernaux/arch/)
|
||||
* [Functions](/include/kernaux/asm/)
|
||||
* Generic types
|
||||
* [File](/include/kernaux/generic/file.h) (*work in progress*)
|
||||
* [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* **?.?.?**)
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
#include "main.h"
|
||||
|
||||
#ifdef KERNAUX_VERSION_WITH_IO
|
||||
|
||||
static VALUE rb_KernAux_File_initialize(VALUE self, VALUE out);
|
||||
|
||||
static ID rb_intern_ATout = Qnil;
|
||||
|
||||
static VALUE rb_KernAux_File = Qnil;
|
||||
|
||||
void init_io() {
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_ATout = rb_intern("@out")));
|
||||
|
||||
rb_gc_register_mark_object(rb_KernAux_File =
|
||||
rb_define_class_under(rb_KernAux, "File", rb_cObject));
|
||||
|
||||
rb_define_method(rb_KernAux_File, "initialize",
|
||||
rb_KernAux_File_initialize, 1);
|
||||
}
|
||||
|
||||
VALUE rb_KernAux_File_initialize(VALUE self, VALUE out)
|
||||
{
|
||||
rb_ivar_set(self, rb_intern_ATout, out);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
#endif // KERNAUX_VERSION_WITH_IO
|
|
@ -22,10 +22,6 @@ void Init_default()
|
|||
init_version();
|
||||
init_assert();
|
||||
|
||||
#ifdef KERNAUX_VERSION_WITH_IO
|
||||
init_io();
|
||||
#endif // KERNAUX_VERSION_WITH_IO
|
||||
|
||||
#ifdef KERNAUX_VERSION_WITH_CMDLINE
|
||||
init_cmdline();
|
||||
#endif // KERNAUX_VERSION_WITH_CMDLINE
|
||||
|
|
|
@ -15,10 +15,6 @@ extern VALUE rb_KernAux_Error;
|
|||
void init_version();
|
||||
void init_assert();
|
||||
|
||||
#ifdef KERNAUX_VERSION_WITH_IO
|
||||
void init_io();
|
||||
#endif // KERNAUX_VERSION_WITH_IO
|
||||
|
||||
#ifdef KERNAUX_VERSION_WITH_CMDLINE
|
||||
void init_cmdline();
|
||||
#endif // KERNAUX_VERSION_WITH_CMDLINE
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "main.h"
|
||||
|
||||
static VALUE rb_KernAux_Version_with_cmdlineQN(VALUE self);
|
||||
static VALUE rb_KernAux_Version_with_ioQN(VALUE self);
|
||||
static VALUE rb_KernAux_Version_with_ntoaQN(VALUE self);
|
||||
static VALUE rb_KernAux_Version_with_printfQN(VALUE self);
|
||||
|
||||
|
@ -14,8 +13,6 @@ void init_version()
|
|||
|
||||
rb_define_singleton_method(rb_KernAux_Version, "with_cmdline?",
|
||||
rb_KernAux_Version_with_cmdlineQN, 0);
|
||||
rb_define_singleton_method(rb_KernAux_Version, "with_io?",
|
||||
rb_KernAux_Version_with_ioQN, 0);
|
||||
rb_define_singleton_method(rb_KernAux_Version, "with_ntoa?",
|
||||
rb_KernAux_Version_with_ntoaQN, 0);
|
||||
rb_define_singleton_method(rb_KernAux_Version, "with_printf?",
|
||||
|
@ -31,15 +28,6 @@ VALUE rb_KernAux_Version_with_cmdlineQN(VALUE self)
|
|||
#endif
|
||||
}
|
||||
|
||||
VALUE rb_KernAux_Version_with_ioQN(VALUE self)
|
||||
{
|
||||
#ifdef KERNAUX_VERSION_WITH_IO
|
||||
return Qtrue;
|
||||
#else
|
||||
return Qfalse;
|
||||
#endif
|
||||
}
|
||||
|
||||
VALUE rb_KernAux_Version_with_ntoaQN(VALUE self)
|
||||
{
|
||||
#ifdef KERNAUX_VERSION_WITH_NTOA
|
||||
|
|
|
@ -16,6 +16,5 @@ require_relative 'kernaux/default'
|
|||
require_relative 'kernaux/assert'
|
||||
require_relative 'kernaux/cmdline'
|
||||
require_relative 'kernaux/errors'
|
||||
require_relative 'kernaux/io'
|
||||
require_relative 'kernaux/ntoa'
|
||||
require_relative 'kernaux/printf'
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop:disable Lint/EmptyClass
|
||||
|
||||
if KernAux::Version.with_io?
|
||||
module KernAux
|
||||
##
|
||||
# File simulator.
|
||||
#
|
||||
class File
|
||||
##
|
||||
# @!method initialize(out)
|
||||
# Create a file.
|
||||
#
|
||||
# @param out [Proc] writing method
|
||||
|
||||
# @!parse [ruby]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:enable Lint/EmptyClass
|
|
@ -45,6 +45,14 @@ fprintf_va_SOURCES = main.c fprintf_va.c
|
|||
endif
|
||||
endif
|
||||
|
||||
################
|
||||
# generic_file #
|
||||
################
|
||||
|
||||
TESTS += generic_file
|
||||
generic_file_LDADD = $(top_builddir)/libkernaux.la
|
||||
generic_file_SOURCES = main.c generic_file.c
|
||||
|
||||
##################
|
||||
# generic_malloc #
|
||||
##################
|
||||
|
|
|
@ -22,7 +22,7 @@ static void my_putchar(const char chr, void *arg)
|
|||
|
||||
void example_main()
|
||||
{
|
||||
struct KernAux_File file = KernAux_File_create(my_putchar);
|
||||
struct KernAux_OldFile file = KernAux_OldFile_create(my_putchar);
|
||||
const int result = kernaux_fprintf(
|
||||
&file,
|
||||
(char*)data,
|
||||
|
|
|
@ -24,7 +24,7 @@ static int my_printf(const char *const format, ...)
|
|||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
struct KernAux_File file = KernAux_File_create(my_putchar);
|
||||
struct KernAux_OldFile file = KernAux_OldFile_create(my_putchar);
|
||||
const int result = kernaux_vfprintf(&file, (char*)data, format, va);
|
||||
va_end(va);
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
//===========
|
||||
// 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 <kernaux/generic/file.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
//===========
|
||||
|
||||
static int MyFile_putc(void *file, unsigned char c);
|
||||
|
||||
struct MyFile MyFile_create(char *const ptr, const size_t size)
|
||||
{
|
||||
struct MyFile my_file;
|
||||
my_file.file.putc = MyFile_putc;
|
||||
my_file.file.puts = NULL; // "puts" has a default implementation
|
||||
my_file.file.write = NULL; // "write" has a default implementation
|
||||
my_file.ptr = ptr;
|
||||
my_file.size = size;
|
||||
my_file.pos = 0;
|
||||
return my_file;
|
||||
}
|
||||
|
||||
int MyFile_putc(void *const file, const unsigned char c)
|
||||
{
|
||||
MyFile my_file = file;
|
||||
if (my_file->pos >= my_file->size) return KERNAUX_EOF;
|
||||
my_file->ptr[my_file->pos++] = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
//========
|
||||
// main.c
|
||||
//========
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *const hello = "Hello, World!";
|
||||
|
||||
void example_main()
|
||||
{
|
||||
char buffer[20];
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// Write random data to the file
|
||||
{
|
||||
const int result = KernAux_File_write(&my_file.file, data, sizeof(data));
|
||||
assert(result != KERNAUX_EOF);
|
||||
}
|
||||
|
||||
assert(strcmp(buffer, hello) == 0);
|
||||
assert(memcmp(&buffer[14], data, sizeof(data)) == 0);
|
||||
}
|
|
@ -9,6 +9,7 @@ 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
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <kernaux/macro.h>
|
||||
#include <kernaux/version.h>
|
||||
|
||||
#include <kernaux/generic/file.h>
|
||||
#include <kernaux/generic/malloc.h>
|
||||
#include <kernaux/generic/mutex.h>
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef KERNAUX_INCLUDED_FILE
|
||||
#define KERNAUX_INCLUDED_FILE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <kernaux/macro.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#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 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;
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -5,14 +5,14 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*KernAux_File_Out)(char c, void *arg);
|
||||
typedef void (*KernAux_OldFile_Out)(char c, void *arg);
|
||||
|
||||
typedef struct KernAux_File {
|
||||
KernAux_File_Out out;
|
||||
} *KernAux_File;
|
||||
typedef struct KernAux_OldFile {
|
||||
KernAux_OldFile_Out out;
|
||||
} *KernAux_OldFile;
|
||||
|
||||
struct KernAux_File KernAux_File_create(KernAux_File_Out out);
|
||||
void KernAux_File_init(KernAux_File file, KernAux_File_Out out);
|
||||
struct KernAux_OldFile KernAux_OldFile_create(KernAux_OldFile_Out out);
|
||||
void KernAux_OldFile_init(KernAux_OldFile file, KernAux_OldFile_Out out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ extern "C" {
|
|||
* \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
|
||||
*/
|
||||
@comment_line_io@int kernaux_fprintf(KernAux_File file, void* arg, const char* format, ...);
|
||||
@comment_line_io@int kernaux_vfprintf(KernAux_File file, void* arg, const char* format, va_list va);
|
||||
@comment_line_io@int kernaux_fprintf(KernAux_OldFile file, void* arg, const char* format, ...);
|
||||
@comment_line_io@int kernaux_vfprintf(KernAux_OldFile file, void* arg, const char* format, va_list va);
|
||||
|
||||
/**
|
||||
* Tiny [v]snprintf implementation
|
||||
|
|
|
@ -56,8 +56,8 @@ void kernaux_drivers_console_printf(const char *format, ...)
|
|||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
struct KernAux_File file =
|
||||
KernAux_File_create(kernaux_drivers_console_printf_putc);
|
||||
struct KernAux_OldFile file =
|
||||
KernAux_OldFile_create(kernaux_drivers_console_printf_putc);
|
||||
kernaux_vfprintf(&file, NULL, format, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <kernaux/assert.h>
|
||||
#include <kernaux/generic/file.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int KernAux_File_putc(const KernAux_File file, const int c)
|
||||
{
|
||||
KERNAUX_ASSERT(file);
|
||||
KERNAUX_ASSERT(file->putc);
|
||||
|
||||
return file->putc(file, c);
|
||||
}
|
||||
|
||||
int KernAux_File_puts(const KernAux_File file, const char *const s)
|
||||
{
|
||||
KERNAUX_ASSERT(file);
|
||||
|
||||
// Common implementation
|
||||
if (!s) return 0;
|
||||
|
||||
// Inherited implementation
|
||||
if (file->puts) return file->puts(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;
|
||||
}
|
||||
const int icount = ccount;
|
||||
return icount >= 0 ? icount : 0;
|
||||
}
|
||||
|
||||
int KernAux_File_write(
|
||||
const KernAux_File file,
|
||||
const void *const buffer,
|
||||
const size_t count
|
||||
) {
|
||||
KERNAUX_ASSERT(file);
|
||||
|
||||
// Common implementation
|
||||
if (count == 0 || !buffer) return 0;
|
||||
|
||||
// Inherited implementation
|
||||
if (file->write) return file->write(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;
|
||||
}
|
||||
const int icount = ccount;
|
||||
return icount >= 0 ? icount : 0;
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
void *KernAux_Malloc_calloc(KernAux_Malloc malloc, size_t nmemb, size_t size)
|
||||
{
|
||||
KERNAUX_ASSERT(malloc);
|
||||
KERNAUX_ASSERT(malloc->calloc);
|
||||
|
||||
return malloc->calloc(malloc, nmemb, size);
|
||||
}
|
||||
|
@ -17,6 +18,7 @@ void *KernAux_Malloc_calloc(KernAux_Malloc malloc, size_t nmemb, size_t size)
|
|||
void KernAux_Malloc_free(KernAux_Malloc malloc, void *ptr)
|
||||
{
|
||||
KERNAUX_ASSERT(malloc);
|
||||
KERNAUX_ASSERT(malloc->free);
|
||||
|
||||
malloc->free(malloc, ptr);
|
||||
}
|
||||
|
@ -24,6 +26,7 @@ void KernAux_Malloc_free(KernAux_Malloc malloc, void *ptr)
|
|||
void *KernAux_Malloc_malloc(KernAux_Malloc malloc, size_t size)
|
||||
{
|
||||
KERNAUX_ASSERT(malloc);
|
||||
KERNAUX_ASSERT(malloc->malloc);
|
||||
|
||||
return malloc->malloc(malloc, size);
|
||||
}
|
||||
|
@ -31,6 +34,7 @@ void *KernAux_Malloc_malloc(KernAux_Malloc malloc, size_t size)
|
|||
void *KernAux_Malloc_realloc(KernAux_Malloc malloc, void *ptr, size_t size)
|
||||
{
|
||||
KERNAUX_ASSERT(malloc);
|
||||
KERNAUX_ASSERT(malloc->realloc);
|
||||
|
||||
return malloc->realloc(malloc, ptr, size);
|
||||
}
|
||||
|
|
8
src/io.c
8
src/io.c
|
@ -7,14 +7,14 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
struct KernAux_File KernAux_File_create(const KernAux_File_Out out)
|
||||
struct KernAux_OldFile KernAux_OldFile_create(const KernAux_OldFile_Out out)
|
||||
{
|
||||
struct KernAux_File file;
|
||||
KernAux_File_init(&file, out);
|
||||
struct KernAux_OldFile file;
|
||||
KernAux_OldFile_init(&file, out);
|
||||
return file;
|
||||
}
|
||||
|
||||
void KernAux_File_init(const KernAux_File file, const KernAux_File_Out out)
|
||||
void KernAux_OldFile_init(const KernAux_OldFile file, const KernAux_OldFile_Out out)
|
||||
{
|
||||
KERNAUX_ASSERT(file);
|
||||
KERNAUX_ASSERT(out);
|
||||
|
|
|
@ -71,7 +71,7 @@ static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, d
|
|||
|
||||
#ifdef WITH_IO
|
||||
|
||||
int kernaux_fprintf(const KernAux_File file, void* arg, const char* format, ...)
|
||||
int kernaux_fprintf(const KernAux_OldFile file, void* arg, const char* format, ...)
|
||||
{
|
||||
KERNAUX_ASSERT(file);
|
||||
KERNAUX_ASSERT(format);
|
||||
|
@ -84,7 +84,7 @@ int kernaux_fprintf(const KernAux_File file, void* arg, const char* format, ...)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int kernaux_vfprintf(const KernAux_File file, void* arg, const char* format, va_list va)
|
||||
int kernaux_vfprintf(const KernAux_OldFile file, void* arg, const char* format, va_list va)
|
||||
{
|
||||
KERNAUX_ASSERT(file);
|
||||
KERNAUX_ASSERT(format);
|
||||
|
|
|
@ -45,7 +45,7 @@ static void test(const char *const expected, const char *const format, ...)
|
|||
memset(buffer, '\0', sizeof(buffer));
|
||||
buffer_index = 0;
|
||||
va_start(va, format);
|
||||
struct KernAux_File file = KernAux_File_create(test_putchar);
|
||||
struct KernAux_OldFile file = KernAux_OldFile_create(test_putchar);
|
||||
result = kernaux_vfprintf(&file, (char*)data, format, va);
|
||||
va_end(va);
|
||||
assert((size_t)result == strlen(expected));
|
||||
|
@ -66,7 +66,7 @@ void test_main()
|
|||
#ifdef WITH_IO
|
||||
memset(buffer, '\0', sizeof(buffer));
|
||||
buffer_index = 0;
|
||||
struct KernAux_File file = KernAux_File_create(test_putchar);
|
||||
struct KernAux_OldFile file = KernAux_OldFile_create(test_putchar);
|
||||
kernaux_fprintf(&file, (char*)data, "Hello, World!");
|
||||
assert(strcmp("Hello, World!", buffer) == 0);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue