-
Notifications
You must be signed in to change notification settings - Fork 2
/
generic_display.c
115 lines (95 loc) · 2.91 KB
/
generic_display.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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 <kernaux/generic/display.h>
#include <stddef.h>
typedef struct MyDisplay {
struct KernAux_Display display;
char *buffer, *cursor;
size_t capacity;
} *MyDisplay;
struct MyDisplay MyDisplay_create();
//==============
// my_display.c
//==============
#include <assert.h>
#include <kernaux/generic/display.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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
);
}