ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
output_buffer.c
Go to the documentation of this file.
1
7#include <ascii-chat/video/output_buffer.h>
8#include <ascii-chat/common.h>
9#include <ascii-chat/video/simd/ascii_simd.h>
10
11/*****************************************************************************/
12// char* output buffer helpers
13//
14// ob_* - build strings with an output buffer
15// ob_reserve - reserve space in the output buffer
16// ob_putc - append a single character to the output buffer
17// ob_write - append a string to the output buffer
18// ob_term - terminate the output buffer
19// ob_u8 - append a decimal number to the output buffer
20// ob_u32 - append a decimal number to the output buffer
21
22void ob_reserve(outbuf_t *ob, size_t need) {
23 if (!ob)
24 return;
25 if (ob->cap == 0) {
26 // Always allocate at least default capacity on first call
27 size_t ncap = 4096;
28 while (ncap < ob->len + need)
29 ncap = (ncap * 3) / 2;
30 // SAFE_REALLOC handles NULL ptr as malloc - this is safe
31 ob->buf = SAFE_REALLOC(ob->buf, ncap, char *);
32 ob->cap = ncap;
33 } else if (ob->len + need > ob->cap) {
34 // Expand existing buffer
35 size_t ncap = ob->cap;
36 while (ncap < ob->len + need)
37 ncap = (ncap * 3) / 2;
38 ob->buf = SAFE_REALLOC(ob->buf, ncap, char *);
39 ob->cap = ncap;
40 }
41}
42
43void ob_putc(outbuf_t *ob, char c) {
44 if (!ob)
45 return;
46 ob_reserve(ob, 1);
47 ob->buf[ob->len++] = c;
48}
49
50void ob_write(outbuf_t *ob, const char *s, size_t n) {
51 if (!ob || n == 0)
52 return;
53 ob_reserve(ob, n);
54 SAFE_MEMCPY(ob->buf + ob->len, ob->cap - ob->len, s, n);
55 ob->len += n;
56}
57
58void ob_term(outbuf_t *ob) {
59 if (!ob)
60 return;
61 ob_putc(ob, '\0');
62}
63
64// Fast decimal for uint8_t (0..255)
65void ob_u8(outbuf_t *ob, uint8_t v) {
66 if (!ob)
67 return;
68 if (v >= 100) {
69 uint8_t d0 = v / 100;
70 uint8_t r = v % 100;
71 uint8_t d1 = r / 10;
72 uint8_t d2 = r % 10;
73 ob_putc(ob, '0' + d0);
74 ob_putc(ob, '0' + d1);
75 ob_putc(ob, '0' + d2);
76 } else if (v >= 10) {
77 uint8_t d1 = v / 10;
78 uint8_t d2 = v % 10;
79 ob_putc(ob, '0' + d1);
80 ob_putc(ob, '0' + d2);
81 } else {
82 ob_putc(ob, '0' + v);
83 }
84}
85
86void ob_u32(outbuf_t *ob, uint32_t v) {
87 if (!ob)
88 return;
89 char tmp[10];
90 int i = 0;
91 do {
92 tmp[i++] = '0' + (v % 10u);
93 v /= 10u;
94 } while (v);
95 ob_reserve(ob, (size_t)i);
96 while (i--)
97 ob->buf[ob->len++] = tmp[i];
98}
99
100// Truecolor SGR emission (foreground)
101void emit_set_truecolor_fg(outbuf_t *ob, uint8_t r, uint8_t g, uint8_t b) {
102 if (!ob)
103 return;
104 // ESC[38;2;R;G;Bm
105 ob_putc(ob, 0x1b);
106 ob_putc(ob, '[');
107 ob_write(ob, "38;2;", 5);
108 ob_u8(ob, r);
109 ob_putc(ob, ';');
110 ob_u8(ob, g);
111 ob_putc(ob, ';');
112 ob_u8(ob, b);
113 ob_putc(ob, 'm');
114}
115
116// Truecolor SGR emission (background)
117void emit_set_truecolor_bg(outbuf_t *ob, uint8_t r, uint8_t g, uint8_t b) {
118 if (!ob)
119 return;
120 // ESC[48;2;R;G;Bm
121 ob_putc(ob, 0x1b);
122 ob_putc(ob, '[');
123 ob_write(ob, "48;2;", 5);
124 ob_u8(ob, r);
125 ob_putc(ob, ';');
126 ob_u8(ob, g);
127 ob_putc(ob, ';');
128 ob_u8(ob, b);
129 ob_putc(ob, 'm');
130}
131
132void emit_reset(outbuf_t *ob) {
133 if (!ob)
134 return;
135 ob_putc(ob, 0x1b);
136 ob_putc(ob, '[');
137 ob_putc(ob, '0');
138 ob_putc(ob, 'm');
139}
140
141// REP profitability calculation
142bool rep_is_profitable(uint32_t runlen) {
143 if (runlen <= 2)
144 return false;
145 uint32_t k = runlen - 1; // Extra repetitions beyond the first character
146 uint32_t rep_cost = (uint32_t)(digits_u32(k) + 3); // ESC [ digits b
147 return k > rep_cost; // Manual repetition cost vs REP cost
148}
149
150void emit_rep(outbuf_t *ob, uint32_t extra) {
151 if (!ob)
152 return;
153 // ESC [ extra b
154 ob_putc(ob, 0x1b);
155 ob_putc(ob, '[');
156 ob_u32(ob, extra);
157 ob_putc(ob, 'b');
158}
159
160// 256-color SGR emission (foreground) - uses cached sequences for performance
161void emit_set_256_color_fg(outbuf_t *ob, uint8_t color_idx) {
162 if (!ob)
163 return;
164 // Use pre-cached color sequence instead of building on-demand
165 uint8_t seq_len;
166 const char *seq = get_sgr256_fg_string(color_idx, &seq_len);
167 ob_write(ob, seq, seq_len);
168}
169
170// 256-color SGR emission (background) - uses cached sequences for performance
171void emit_set_256_color_bg(outbuf_t *ob, uint8_t color_idx) {
172 if (!ob)
173 return;
174 // Use pre-cached color sequence instead of building on-demand
175 uint8_t seq_len;
176 const char *seq = get_sgr256_bg_string(color_idx, &seq_len);
177 ob_write(ob, seq, seq_len);
178}
179
180void emit_set_fg(outbuf_t *ob, uint8_t r, uint8_t g, uint8_t b) {
181 if (!ob)
182 return;
183 // ESC[38;2;R;G;Bm
184 ob_putc(ob, 0x1b);
185 ob_putc(ob, '[');
186 ob_write(ob, "38;2;", 5);
187 ob_u8(ob, r);
188 ob_putc(ob, ';');
189 ob_u8(ob, g);
190 ob_putc(ob, ';');
191 ob_u8(ob, b);
192 ob_putc(ob, 'm');
193}
194
195void emit_set_bg(outbuf_t *ob, uint8_t r, uint8_t g, uint8_t b) {
196 if (!ob)
197 return;
198 // ESC[48;2;R;G;Bm
199 ob_putc(ob, 0x1b);
200 ob_putc(ob, '[');
201 ob_write(ob, "48;2;", 5);
202 ob_u8(ob, r);
203 ob_putc(ob, ';');
204 ob_u8(ob, g);
205 ob_putc(ob, ';');
206 ob_u8(ob, b);
207 ob_putc(ob, 'm');
208}
char * get_sgr256_bg_string(uint8_t bg, uint8_t *len_out)
char * get_sgr256_fg_string(uint8_t fg, uint8_t *len_out)
void emit_set_256_color_bg(outbuf_t *ob, uint8_t color_idx)
void emit_set_bg(outbuf_t *ob, uint8_t r, uint8_t g, uint8_t b)
void ob_u32(outbuf_t *ob, uint32_t v)
void ob_u8(outbuf_t *ob, uint8_t v)
void emit_set_256_color_fg(outbuf_t *ob, uint8_t color_idx)
void ob_term(outbuf_t *ob)
void ob_putc(outbuf_t *ob, char c)
bool rep_is_profitable(uint32_t runlen)
void ob_reserve(outbuf_t *ob, size_t need)
void emit_set_truecolor_fg(outbuf_t *ob, uint8_t r, uint8_t g, uint8_t b)
void emit_rep(outbuf_t *ob, uint32_t extra)
void ob_write(outbuf_t *ob, const char *s, size_t n)
void emit_reset(outbuf_t *ob)
void emit_set_truecolor_bg(outbuf_t *ob, uint8_t r, uint8_t g, uint8_t b)
void emit_set_fg(outbuf_t *ob, uint8_t r, uint8_t g, uint8_t b)