GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/lbm_channel.c
Date: 2025-08-08 18:10:24
Exec Total Coverage
Lines: 284 286 99.3%
Functions: 49 49 100.0%
Branches: 50 58 86.2%

Line Branch Exec Source
1 /*
2 Copyright 2022, 2025 Joel Svensson svenssonjoel@yahoo.se
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <lbm_channel.h>
19 #include <string.h>
20 #include <lbm_defines.h>
21
22 /* ------------------------------------------------------------
23 Interface
24 ------------------------------------------------------------ */
25 23280524 bool lbm_channel_more(lbm_char_channel_t *chan) {
26 23280524 return chan->more(chan);
27 }
28
29 312232178 int lbm_channel_peek(lbm_char_channel_t *chan, unsigned int n, char *res) {
30 312232178 return chan->peek(chan, n, res);
31 }
32
33 52 bool lbm_channel_read(lbm_char_channel_t *chan, char *res) {
34 52 return chan->read(chan, res);
35 }
36
37 22274480 bool lbm_channel_drop(lbm_char_channel_t *chan, unsigned int n) {
38 22274480 return chan->drop(chan, n);
39 }
40
41 11643180 bool lbm_channel_comment(lbm_char_channel_t *chan) {
42 11643180 return chan->comment(chan);
43 }
44
45 28069 void lbm_channel_set_comment(lbm_char_channel_t *chan, bool comment) {
46 28069 chan->set_comment(chan, comment);
47 28069 }
48
49 21499254 bool lbm_channel_is_empty(lbm_char_channel_t *chan) {
50 21499254 return chan->channel_is_empty(chan);
51 }
52
53 260 bool lbm_channel_is_full(lbm_char_channel_t *chan) {
54 260 return chan->channel_is_full(chan);
55 }
56
57 11213199 int lbm_channel_write(lbm_char_channel_t *chan, char c) {
58 11213199 return chan->write(chan, c);
59 }
60
61 22038 void lbm_channel_writer_close(lbm_char_channel_t *chan) {
62 22038 chan->writer_close(chan);
63 22038 }
64
65 663621 void lbm_channel_reader_close(lbm_char_channel_t *chan) {
66 663621 chan->reader_close(chan);
67 663621 }
68
69 3 bool lbm_channel_reader_is_closed(lbm_char_channel_t *chan) {
70 3 return chan->reader_is_closed(chan);
71 }
72
73 763531 unsigned int lbm_channel_row(lbm_char_channel_t *chan) {
74 763531 return chan->row(chan);
75 }
76
77 168 unsigned int lbm_channel_column(lbm_char_channel_t *chan) {
78 168 return chan->column(chan);
79 }
80
81 55517 bool lbm_channel_may_block(lbm_char_channel_t *chan) {
82 55517 return chan->may_block(chan);
83 }
84
85 /* ------------------------------------------------------------
86 Implementation buffered channel
87 ------------------------------------------------------------ */
88 22037 bool buffered_may_block(lbm_char_channel_t *chan) {
89 (void) chan;
90 22037 return true;
91 }
92
93 3757324 bool buffered_more(lbm_char_channel_t *chan) {
94 3757324 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
95 3757324 return st->more;
96 }
97
98 22037 void buffered_writer_close(lbm_char_channel_t *chan) {
99 22037 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
100 22037 st->more = false;
101 22037 }
102
103 22015 void buffered_reader_close(lbm_char_channel_t *chan) {
104 22015 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
105 22015 st->reader_closed = true;
106 22015 }
107
108 2 bool buffered_reader_is_closed(lbm_char_channel_t *chan) {
109 2 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
110 2 return st->reader_closed;
111 }
112
113 40100089 int buffered_peek(lbm_char_channel_t *chan, unsigned int n, char *res) {
114 40100089 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
115 40100089 char *buffer = st->buffer;
116 40100089 int ret = CHANNEL_MORE;
117 40100089 mutex_lock(&st->lock);
118 40100089 unsigned int peek_pos = (st->read_pos + n) % TOKENIZER_BUFFER_SIZE;
119 bool in_data;
120
121
2/2
✓ Branch 0 taken 19102265 times.
✓ Branch 1 taken 20997824 times.
40100089 if (st->write_pos >= st->read_pos) {
122
3/4
✓ Branch 0 taken 19078757 times.
✓ Branch 1 taken 23508 times.
✓ Branch 2 taken 19078757 times.
✗ Branch 3 not taken.
19102265 in_data = peek_pos < st->write_pos && peek_pos >= st->read_pos;
123 } else {
124
4/4
✓ Branch 0 taken 20925779 times.
✓ Branch 1 taken 72045 times.
✓ Branch 2 taken 20925778 times.
✓ Branch 3 taken 1 times.
20997824 in_data = !(peek_pos >= st->write_pos && peek_pos < st->read_pos);
125 }
126
127
2/2
✓ Branch 0 taken 40076580 times.
✓ Branch 1 taken 23509 times.
40100089 if (in_data) {
128 40076580 *res = buffer[peek_pos];
129 40076580 ret = CHANNEL_SUCCESS;
130
2/2
✓ Branch 0 taken 21791 times.
✓ Branch 1 taken 1718 times.
23509 } else if (!buffered_more(chan)) {
131 21791 ret = CHANNEL_END;
132
1/2
✓ Branch 0 taken 1718 times.
✗ Branch 1 not taken.
1718 } else if (buffered_more(chan)) {
133 1718 ret = CHANNEL_MORE;
134 }
135 40100089 mutex_unlock(&st->lock);
136 40100089 return ret;
137 }
138
139 8437110 bool buffered_channel_is_empty(lbm_char_channel_t *chan) {
140 8437110 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
141
2/2
✓ Branch 0 taken 22018 times.
✓ Branch 1 taken 8415092 times.
8437110 if (st->read_pos == st->write_pos) {
142 22018 return true;
143 }
144 8415092 return false;
145 }
146
147 6547505 bool buffered_channel_is_full(lbm_char_channel_t *chan) {
148 6547505 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
149
2/2
✓ Branch 0 taken 6511775 times.
✓ Branch 1 taken 35730 times.
6547505 if (st->write_pos == st->read_pos - 1 ||
150
2/2
✓ Branch 0 taken 3240067 times.
✓ Branch 1 taken 3271708 times.
6511775 (st->read_pos == 0 &&
151
2/2
✓ Branch 0 taken 23947 times.
✓ Branch 1 taken 3216120 times.
3240067 st->write_pos == TOKENIZER_BUFFER_SIZE-1)) {
152 59677 return true;
153 }
154 6487828 return false;
155 }
156
157 6486284 bool buffered_read(lbm_char_channel_t *chan, char *res) {
158 6486284 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
159 6486284 char *buffer = st->buffer;
160 6486284 bool ret = false;
161 6486284 mutex_lock(&st->lock);
162
2/2
✓ Branch 0 taken 6486283 times.
✓ Branch 1 taken 1 times.
6486284 if (!buffered_channel_is_empty(chan)) {
163 6486283 *res = buffer[st->read_pos];
164 6486283 st->column++;
165
2/2
✓ Branch 0 taken 213753 times.
✓ Branch 1 taken 6272530 times.
6486283 if (*res == '\n') {
166 213753 st->column = 1;
167 213753 st->row ++;
168 }
169 6486283 st->read_pos = (st->read_pos + 1) % TOKENIZER_BUFFER_SIZE;
170 6486283 ret = true;
171 }
172 6486284 mutex_unlock(&st->lock);
173 6486284 return ret;
174 }
175
176 4202827 bool buffered_drop(lbm_char_channel_t *chan, unsigned int n) {
177 4202827 bool r = true;
178 char c;
179
180
2/2
✓ Branch 0 taken 6486265 times.
✓ Branch 1 taken 4202827 times.
10689092 for (unsigned int i = 0; i < n; i ++) {
181 6486265 r = buffered_read(chan, &c);
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6486265 times.
6486265 if (r == false) break;
183 }
184 4202827 return r;
185 }
186
187 6547248 int buffered_write(lbm_char_channel_t *chan, char c) {
188 6547248 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6547248 times.
6547248 if (st->reader_closed) return CHANNEL_READER_CLOSED;
190 6547248 int ret = CHANNEL_FULL;
191 6547248 mutex_lock(&st->lock);
192 6547248 char *buffer = st->buffer;
193
2/2
✓ Branch 0 taken 6487572 times.
✓ Branch 1 taken 59676 times.
6547248 if (!buffered_channel_is_full(chan)) {
194 6487572 buffer[st->write_pos] = c;
195 6487572 st->write_pos = (st->write_pos + 1) % TOKENIZER_BUFFER_SIZE;
196 6487572 ret = CHANNEL_SUCCESS;
197 }
198 6547248 mutex_unlock(&st->lock);
199 6547248 return ret;
200 }
201
202 95546 unsigned int buffered_row(lbm_char_channel_t *chan) {
203 95546 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
204 95546 return st->row;
205 }
206
207 1 unsigned int buffered_column(lbm_char_channel_t *chan) {
208 1 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
209 1 return st->column;
210 }
211
212 1872848 bool buffered_comment(lbm_char_channel_t *chan) {
213 1872848 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
214 1872848 return st->comment;
215 }
216
217 12141 void buffered_set_comment(lbm_char_channel_t *chan, bool comment) {
218 12141 lbm_buffered_channel_state_t *st = (lbm_buffered_channel_state_t*)chan->state;
219 12141 st->comment = comment;
220 12141 }
221
222 22048 void lbm_create_buffered_char_channel(lbm_buffered_channel_state_t *st,
223 lbm_char_channel_t *chan) {
224
225 22048 st->write_pos = 0;
226 22048 st->read_pos = 0;
227 22048 st->more = true;
228 22048 st->reader_closed = false;
229 22048 st->comment = false;
230 22048 st->row = 1;
231 22048 st->column = 1;
232
233
2/2
✓ Branch 0 taken 22037 times.
✓ Branch 1 taken 11 times.
22048 if (!st->mutex_initialized) {
234 22037 mutex_init(&st->lock);
235 22037 st->mutex_initialized = true;
236 }
237
238 22048 chan->state = st;
239 22048 chan->more = buffered_more;
240 22048 chan->peek = buffered_peek;
241 22048 chan->read = buffered_read;
242 22048 chan->drop = buffered_drop;
243 22048 chan->comment = buffered_comment;
244 22048 chan->set_comment = buffered_set_comment;
245 22048 chan->channel_is_empty = buffered_channel_is_empty;
246 22048 chan->channel_is_full = buffered_channel_is_full;
247 22048 chan->write = buffered_write;
248 22048 chan->writer_close = buffered_writer_close;
249 22048 chan->reader_close = buffered_reader_close;
250 22048 chan->reader_is_closed = buffered_reader_is_closed;
251 22048 chan->row = buffered_row;
252 22048 chan->column = buffered_column;
253 22048 chan->may_block = buffered_may_block;
254 22048 }
255
256 /* ------------------------------------------------------------
257 Implementation string channel
258 ------------------------------------------------------------ */
259
260 33480 bool string_may_block(lbm_char_channel_t *chan) {
261 (void) chan;
262 33480 return false;
263 }
264
265 19548427 bool string_more(lbm_char_channel_t *chan) {
266 19548427 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
267 19548427 return st->more;
268 }
269
270 1 void string_writer_close(lbm_char_channel_t *chan) {
271 1 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
272 1 st->more = false;
273 1 }
274
275 641606 void string_reader_close(lbm_char_channel_t *chan) {
276 641606 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
277 641606 st->reader_closed = true;
278 641606 }
279
280 1 bool string_reader_is_closed(lbm_char_channel_t *chan) {
281 1 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
282 1 return st->reader_closed;
283 }
284
285 272132089 int string_peek(lbm_char_channel_t *chan, unsigned int n, char *res) {
286 272132089 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
287 272132089 char *str = st->str;
288
289 272132089 unsigned int peek_pos = st->read_pos + n;
290
291
2/2
✓ Branch 0 taken 272085338 times.
✓ Branch 1 taken 46751 times.
272132089 if (peek_pos < st->length) {
292 272085338 *res = str[peek_pos];
293 272085338 return CHANNEL_SUCCESS;
294 }
295 46751 return CHANNEL_END;
296 }
297
298 19548428 bool string_channel_is_empty(lbm_char_channel_t *chan) {
299 19548428 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
300
2/2
✓ Branch 0 taken 45637 times.
✓ Branch 1 taken 19502791 times.
19548428 if (st->read_pos == st->length) {
301 45637 return true;
302 }
303 19502791 return false;
304 }
305
306 3 bool string_channel_is_full(lbm_char_channel_t *chan) {
307 3 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (st->write_pos == st->length) {
309 return true;
310 }
311 3 return false;
312 }
313
314 21709224 bool string_read(lbm_char_channel_t *chan, char *res) {
315 21709224 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
316 21709224 char *str = st->str;
317
318
2/2
✓ Branch 0 taken 21709222 times.
✓ Branch 1 taken 2 times.
21709224 if (st->read_pos < st->length) {
319 21709222 *res = str[st->read_pos];
320
2/2
✓ Branch 0 taken 222052 times.
✓ Branch 1 taken 21487170 times.
21709222 if (*res == '\n') {
321 222052 st->row ++;
322 222052 st->column = 1;
323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21487170 times.
21487170 } else if (*res == 0) {
324 st->more = false;
325 } else {
326 21487170 st->column++;
327 }
328 21709222 st->read_pos = st->read_pos + 1;
329 } else {
330 2 st->more = false;
331 }
332 21709224 return true;
333 }
334
335 18071653 bool string_drop(lbm_char_channel_t *chan, unsigned int n) {
336 18071653 bool r = true;
337 char c;
338
339
1/2
✓ Branch 0 taken 18071653 times.
✗ Branch 1 not taken.
18071653 if (n > 0) {
340 do {
341 21709191 r = string_read(chan, &c);
342 21709191 n--;
343
3/4
✓ Branch 0 taken 3637538 times.
✓ Branch 1 taken 18071653 times.
✓ Branch 2 taken 3637538 times.
✗ Branch 3 not taken.
21709191 } while (n > 0 && r);
344 }
345 18071653 return r;
346 }
347
348 4676491 int string_write(lbm_char_channel_t *chan, char c) {
349 4676491 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
350 4676491 char *str = st->str;
351
352
2/2
✓ Branch 0 taken 3918895 times.
✓ Branch 1 taken 757596 times.
4676491 if (st->write_pos < st->length) {
353 3918895 str[st->write_pos] = c;
354 3918895 st->write_pos = st->write_pos + 1;
355 } else {
356 757596 return CHANNEL_FULL;
357 }
358 3918895 return CHANNEL_SUCCESS;
359 }
360
361 812493 unsigned int string_row(lbm_char_channel_t *chan) {
362 812493 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
363 812493 return st->row;
364 }
365
366 167 unsigned int string_column(lbm_char_channel_t *chan) {
367 167 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
368 167 return st->column;
369 }
370
371 9770332 bool string_comment(lbm_char_channel_t *chan) {
372 9770332 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
373 9770332 return st->comment;
374 }
375
376 15928 void string_set_comment(lbm_char_channel_t *chan, bool comment) {
377 15928 lbm_string_channel_state_t *st = (lbm_string_channel_state_t*)chan->state;
378 15928 st->comment = comment;
379 15928 }
380
381 644617 void lbm_create_string_char_channel(lbm_string_channel_state_t *st,
382 lbm_char_channel_t *chan,
383 char *str) {
384
385 644617 st->str = str;
386 644617 st->length = (unsigned int)strlen(str);
387 644617 st->read_pos = 0;
388 644617 st->write_pos = 0;
389 644617 st->more = false;
390 644617 st->comment = false;
391 644617 st->row = 1;
392 644617 st->column = 1;
393
394 644617 chan->dependency = ENC_SYM_NIL;
395 644617 chan->state = st;
396 644617 chan->more = string_more;
397 644617 chan->peek = string_peek;
398 644617 chan->read = string_read;
399 644617 chan->drop = string_drop;
400 644617 chan->comment = string_comment;
401 644617 chan->set_comment = string_set_comment;
402 644617 chan->channel_is_empty = string_channel_is_empty;
403 644617 chan->channel_is_full = string_channel_is_full;
404 644617 chan->write = string_write;
405 644617 chan->writer_close = string_writer_close;
406 644617 chan->reader_close = string_reader_close;
407 644617 chan->reader_is_closed = string_reader_is_closed;
408 644617 chan->row = string_row;
409 644617 chan->column = string_column;
410 644617 chan->may_block = string_may_block;
411 644617 }
412
413 667559 void lbm_create_string_char_channel_size(lbm_string_channel_state_t *st,
414 lbm_char_channel_t *chan,
415 char *str,
416 unsigned int size) {
417 667559 st->str = str;
418 667559 st->length = size;
419 667559 st->read_pos = 0;
420 667559 st->write_pos = 0;
421 667559 st->more = false;
422 667559 st->comment = false;
423 667559 st->row = 1;
424 667559 st->column = 1;
425
426 667559 chan->dependency = ENC_SYM_NIL;
427 667559 chan->state = st;
428 667559 chan->more = string_more;
429 667559 chan->peek = string_peek;
430 667559 chan->read = string_read;
431 667559 chan->drop = string_drop;
432 667559 chan->comment = string_comment;
433 667559 chan->set_comment = string_set_comment;
434 667559 chan->channel_is_empty = string_channel_is_empty;
435 667559 chan->channel_is_full = string_channel_is_full;
436 667559 chan->write = string_write;
437 667559 chan->writer_close = string_writer_close;
438 667559 chan->reader_close = string_reader_close;
439 667559 chan->reader_is_closed = string_reader_is_closed;
440 667559 chan->row = string_row;
441 667559 chan->column = string_column;
442 667559 chan->may_block = string_may_block;
443 667559 }
444
445 619453 void lbm_char_channel_set_dependency(lbm_char_channel_t *chan, lbm_value dep) {
446 619453 chan->dependency = dep;
447 619453 }
448
449