1 /* ==========================================================================
2 * fifo.h - Simple byte FIFO with simple bit packing.
3 * --------------------------------------------------------------------------
4 * Copyright (c) 2008-2013 William Ahern
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to permit
11 * persons to whom the Software is furnished to do so, subject to the
12 * following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * ==========================================================================
25 */
26 #ifndef FIFO_H
27 #define FIFO_H
28
29 #include <stdarg.h> /* va_list va_start() va_end() */
30 #include <stddef.h> /* size_t */
31 #include <stdint.h> /* SIZE_MAX */
32 #include <stdio.h> /* EOF FILE fputc(3) vsnprintf(3) */
33 #include <stdlib.h> /* realloc(3) free(3) */
34
35 #include <string.h> /* memcpy(3) memmove(3) strlen(3) memchr(3) */
36
37 #include <ctype.h> /* isgraph(3) */
38
39 #include <errno.h> /* ENOMEM EOVERFLOW errno */
40
41 #include <assert.h> /* assert(3) */
42
43 #include <sys/uio.h> /* struct iovec */
44
45
46 /*
47 * V E R S I O N I N T E R F A C E S
48 *
49 * Vendor: Entity for which versions numbers are relevant. (If forking
50 * change FIFO_VENDOR to avoid confusion.)
51 *
52 * Three versions:
53 *
54 * REL Official "release"--bug fixes, new features, etc.
55 * ABI Changes to existing object sizes or parameter types.
56 * API Changes that might effect application source.
57 *
58 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
59
60 #define FIFO_VENDOR "william@25thandClement.com"
61
62 #define FIFO_V_REL 0x20140424 /* 0x20130330 */
63 #define FIFO_V_ABI 0x20111113 /* 0x20100815 */
64 #define FIFO_V_API 0x20130325 /* 0x20111113 */
65
fifo_vendor(void)66 static inline const char *fifo_vendor(void) { return FIFO_VENDOR; }
67
fifo_v_rel(void)68 static inline int fifo_v_rel(void) { return FIFO_V_REL; }
fifo_v_abi(void)69 static inline int fifo_v_abi(void) { return FIFO_V_ABI; }
fifo_v_api(void)70 static inline int fifo_v_api(void) { return FIFO_V_API; }
71
72
73 /*
74 * M I S C E L L A N E O U S M A C R O S
75 *
76 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
77
78 #define FIFO_MIN(a, b) (((a) < (b))? (a) : (b))
79
80 #define FIFO_NARG_(_15, _14, _13, _12, _11, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
81 #define FIFO_NARG(...) FIFO_NARG_(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
82
83 #define FIFO_PASTE(a, b) a ## b
84 #define FIFO_XPASTE(a, b) FIFO_PASTE(a, b)
85
86 #if __GNUC__
87 #define FIFO_NOTUSED __attribute__((unused))
88 #define FIFO_FORMAT(type, x, y) __attribute__((format (type, x, y)))
89 #else
90 #define FIFO_NOTUSED
91 #define FIFO_FORMAT(...)
92 #endif
93
94
95 /*
96 * O B J E C T I N I T I A L I Z A T I O N R O U T I N E S
97 *
98 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
99
100 #define FIFO_INITIALIZER { { 0 } }
101
102 #define fifo_new(size) fifo_init(&(struct fifo)FIFO_INITIALIZER, ((size))? (unsigned char [(size) + !(size)]){ 0 } : (void *)0, (size))
103
104 struct fifo {
105 /* static buffer */
106 struct iovec sbuf;
107
108 unsigned char *base;
109 size_t size, head, count;
110
111 /* bit accumulators */
112 struct {
113 unsigned char byte, count;
114 } rbits, wbits;
115 }; /* struct fifo */
116
117
118 #define FIFO_STATIC (1 << 0)
119 #define FIFO_DYNAMIC (1 << 1)
120
fifo_type(struct fifo * fifo)121 static inline int fifo_type(struct fifo *fifo) {
122 return (1 << !fifo->sbuf.iov_base);
123 } /* fifo_type() */
124
125
126 /*
127 * Initialize fifo object as static or dynamic buffer.
128 *
129 * - Dynamic: Only pass the fifo object to initialize. DO NOT forget to
130 * call fifo_reset() to release dynamic resources.
131 *
132 * - Static: Pass two additional arguments, pointer and size. Can safely
133 * call fifo_reset(), but not required.
134 */
fifo_init(struct fifo * fifo,void * buf,size_t size)135 static struct fifo *fifo_init(struct fifo *fifo, void *buf, size_t size) {
136 fifo->sbuf = (struct iovec){ buf, size };
137 fifo->base = fifo->sbuf.iov_base;
138 fifo->size = fifo->sbuf.iov_len;
139 fifo->head = 0;
140 fifo->count = 0;
141 fifo->rbits.byte = 0;
142 fifo->rbits.count = 0;
143 fifo->wbits.byte = 0;
144 fifo->wbits.count = 0;
145
146 return fifo;
147 } /* fifo_init() */
148
149 #define fifo_init3(...) (fifo_init)(__VA_ARGS__)
150 #define fifo_init2(fifo, buf) fifo_init3((fifo), (buf), __builtin_object_size((buf), 3))
151 #define fifo_init1(fifo) fifo_init3((fifo), (void *)0, 0U)
152 #define fifo_init(...) FIFO_XPASTE(fifo_init, FIFO_NARG(__VA_ARGS__))(__VA_ARGS__)
153
154
155 static inline size_t fifo_update(struct fifo *, size_t); /* forward declaration */
156
fifo_from(struct fifo * fifo,void * src,size_t size)157 static inline struct fifo *fifo_from(struct fifo *fifo, void *src, size_t size) {
158 fifo_init(fifo, src, size);
159 fifo_update(fifo, size);
160 return fifo;
161 } /* fifo_from() */
162
163 #define fifo_from3(...) (fifo_from)(__VA_ARGS__)
164 #define fifo_from2(src, size) fifo_from3(&(struct fifo)FIFO_INITIALIZER, (src), (size))
165 #define fifo_from1(src) fifo_from3(&(struct fifo)FIFO_INITIALIZER, (src), __builtin_object_size((src), 3))
166 #define fifo_from(...) FIFO_XPASTE(fifo_from, FIFO_NARG(__VA_ARGS__))(__VA_ARGS__)
167
168
169 #define fifo_into2(buf, size) fifo_init(&(struct fifo)FIFO_INITIALIZER, (buf), (size))
170 #define fifo_into1(buf) fifo_init(&(struct fifo)FIFO_INITIALIZER, (buf), __builtin_object_size((buf), 3))
171 #define fifo_into(...) FIFO_XPASTE(fifo_into, FIFO_NARG(__VA_ARGS__))(__VA_ARGS__)
172
173
fifo_reset(struct fifo * fifo)174 FIFO_NOTUSED static struct fifo *fifo_reset(struct fifo *fifo) {
175 if (fifo->base != fifo->sbuf.iov_base)
176 free(fifo->base);
177
178 return fifo_init(fifo, fifo->sbuf.iov_base, fifo->sbuf.iov_len);
179 } /* fifo_reset() */
180
181
fifo_purge(struct fifo * fifo)182 FIFO_NOTUSED static struct fifo *fifo_purge(struct fifo *fifo) {
183 fifo->head = 0;
184 fifo->count = 0;
185 fifo->rbits.byte = 0;
186 fifo->rbits.count = 0;
187 fifo->wbits.byte = 0;
188 fifo->wbits.count = 0;
189 return fifo;
190 } /* fifo_purge() */
191
192
193 /*
194 * M E M O R Y M A N A G E M E N T R O U T I N E S
195 *
196 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
197
198 #ifndef FIFO_TMPBUFSIZ
199 #define FIFO_TMPBUFSIZ 2048
200 #endif
201
fifo_realign(struct fifo * fifo)202 static void fifo_realign(struct fifo *fifo) {
203 if (fifo->size - fifo->head >= fifo->count) {
204 memmove(fifo->base, &fifo->base[fifo->head], fifo->count);
205 fifo->head = 0;
206 } else {
207 unsigned char tmp[FIFO_TMPBUFSIZ];
208 unsigned n, m;
209
210 while (fifo->head != 0) {
211 n = FIFO_MIN(fifo->head, sizeof tmp);
212 m = fifo->size - n;
213
214 memcpy(tmp, fifo->base, n);
215 memmove(fifo->base, &fifo->base[n], m);
216 memcpy(&fifo->base[m], tmp, n);
217 fifo->head -= n;
218 }
219 }
220 } /* fifo_realign() */
221
222
fifo_power2(size_t i)223 static inline size_t fifo_power2(size_t i) {
224 #if defined SIZE_MAX
225 i--;
226 i |= i >> 1;
227 i |= i >> 2;
228 i |= i >> 4;
229 i |= i >> 8;
230 i |= i >> 16;
231 #if SIZE_MAX != 0xffffffffu
232 i |= i >> 32;
233 #endif
234 return ++i;
235 #else
236 #error No SIZE_MAX defined
237 #endif
238 } /* fifo_power2() */
239
240
fifo_roundup(size_t i)241 static inline size_t fifo_roundup(size_t i) {
242 if (i > ~(((size_t)-1) >> 1u))
243 return (size_t)-1;
244 else
245 return fifo_power2(i);
246 } /* fifo_roundup() */
247
248
fifo_realloc(struct fifo * fifo,size_t size)249 static int fifo_realloc(struct fifo *fifo, size_t size) {
250 void *tmp;
251
252 if (fifo->size >= size)
253 return 0;
254 if (fifo_type(fifo) == FIFO_STATIC)
255 return ENOMEM;
256
257 fifo_realign(fifo);
258
259 size = fifo_roundup(size);
260
261 if (!(tmp = realloc(fifo->base, size)))
262 return errno;
263
264 fifo->base = tmp;
265 fifo->size = size;
266
267 return 0;
268 } /* fifo_realloc() */
269
270
fifo_grow(struct fifo * fifo,size_t size)271 static inline int fifo_grow(struct fifo *fifo, size_t size) {
272 if (fifo->size - fifo->count >= size)
273 return 0;
274
275 if (~fifo->count < size)
276 return EOVERFLOW;
277
278 return fifo_realloc(fifo, fifo->count + size);
279 } /* fifo_grow() */
280
281
282 /*
283 * V E C T O R R O U T I N E S
284 *
285 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
286
fifo_rlen(struct fifo * fifo)287 static inline size_t fifo_rlen(struct fifo *fifo) {
288 return fifo->count;
289 } /* fifo_rlen() */
290
291
fifo_wlen(struct fifo * fifo)292 static inline size_t fifo_wlen(struct fifo *fifo) {
293 return fifo->size - fifo->count;
294 } /* fifo_wlen() */
295
296
fifo_rvec(struct fifo * fifo,struct iovec * iov,_Bool realign)297 static size_t fifo_rvec(struct fifo *fifo, struct iovec *iov, _Bool realign) {
298 if (fifo->head + fifo->count > fifo->size && realign)
299 fifo_realign(fifo);
300
301 iov->iov_base = &fifo->base[fifo->head];
302 iov->iov_len = FIFO_MIN(fifo->size - fifo->head, fifo->count);
303
304 return iov->iov_len;
305 } /* fifo_rvec() */
306
307 #define fifo_rvec3(fifo, iov, realign, ...) (fifo_rvec)((fifo), (iov), (realign))
308 #define fifo_rvec(...) fifo_rvec3(__VA_ARGS__, 0, (char[-1]{ 0 }))
309
310
fifo_wvec(struct fifo * fifo,struct iovec * iov,_Bool realign)311 static size_t fifo_wvec(struct fifo *fifo, struct iovec *iov, _Bool realign) {
312 size_t tail, count;
313
314 if (fifo->head + fifo->count < fifo->size && realign)
315 fifo_realign(fifo);
316
317 tail = (fifo->size)? ((fifo->head + fifo->count) % fifo->size) : 0;
318 count = fifo_wlen(fifo);
319
320 iov->iov_base = &fifo->base[tail];
321 iov->iov_len = FIFO_MIN(fifo->size - tail, count);
322
323 return iov->iov_len;
324 } /* fifo_wvec() */
325
326 #define fifo_wvec3(fifo, iov, realign, ...) (fifo_wvec)((fifo), (iov), (realign))
327 #define fifo_wvec(...) fifo_wvec3(__VA_ARGS__, 0, (char[-1]{ 0 }))
328
329
fifo_slice(struct fifo * fifo,struct iovec * iov,size_t p,size_t count)330 FIFO_NOTUSED static size_t fifo_slice(struct fifo *fifo, struct iovec *iov, size_t p, size_t count) {
331 size_t pe;
332
333 if (p > fifo->count) {
334 iov->iov_base = 0;
335 iov->iov_len = 0;
336
337 return 0;
338 }
339
340 count = FIFO_MIN(count, fifo->count - p);
341 pe = p + count;
342
343 if (fifo->head + p < fifo->size && fifo->head + pe > fifo->size)
344 fifo_realign(fifo);
345
346 iov->iov_base = &fifo->base[((fifo->head + p) % fifo->size)];
347 iov->iov_len = count;
348
349 return count;
350 } /* fifo_slice() */
351
352
fifo_tvec(struct fifo * fifo,struct iovec * iov,int ch)353 static size_t fifo_tvec(struct fifo *fifo, struct iovec *iov, int ch) {
354 unsigned char *p;
355
356 if (fifo_rvec(fifo, iov)) {
357 if ((p = memchr(iov->iov_base, ch, iov->iov_len)))
358 return iov->iov_len = (p - (unsigned char *)iov->iov_base) + 1;
359
360 if (fifo->count > iov->iov_len) {
361 iov->iov_len = fifo->count - iov->iov_len;
362 iov->iov_base = fifo->base;
363
364 if ((p = memchr(iov->iov_base, ch, iov->iov_len))) {
365 iov->iov_len = (p - fifo->base) + (fifo->size - fifo->head) + 1;
366 iov->iov_base = fifo->base;
367 fifo_realign(fifo);
368
369 return iov->iov_len;
370 }
371 }
372
373 iov->iov_len = 0;
374 }
375
376 return 0;
377 } /* fifo_tvec() */
378
379
fifo_lvec(struct fifo * fifo,struct iovec * iov)380 static inline size_t fifo_lvec(struct fifo *fifo, struct iovec *iov) {
381 return fifo_tvec(fifo, iov, '\n');
382 } /* fifo_lvec() */
383
384
fifo_wbuf(struct fifo * fifo,struct iovec * iov,size_t size)385 static int fifo_wbuf(struct fifo *fifo, struct iovec *iov, size_t size) {
386 int error;
387
388 if ((error = fifo_grow(fifo, size)))
389 return error;
390
391 /* try to avoid realigning buffer */
392 if (fifo_wvec(fifo, iov, 0) < size)
393 fifo_wvec(fifo, iov, 1);
394
395 return 0;
396 } /* fifo_wbuf() */
397
398
399 /*
400 * R E A D / W R I T E R O U T I N E S
401 *
402 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
403
404 #ifndef FIFO_AUTOALIGN
405 #define FIFO_AUTOALIGN 1
406 #endif
407
fifo_discard(struct fifo * fifo,size_t count)408 static inline size_t fifo_discard(struct fifo *fifo, size_t count) {
409 count = FIFO_MIN(count, fifo->count);
410 fifo->head = (fifo->head + count) % fifo->size;
411 fifo->count -= count;
412 #if FIFO_AUTOALIGN
413 if (!fifo->count)
414 fifo->head = 0;
415 #endif
416 return count;
417 } /* fifo_discard() */
418
419
fifo_update(struct fifo * fifo,size_t count)420 static inline size_t fifo_update(struct fifo *fifo, size_t count) {
421 count = FIFO_MIN(count, fifo->size - fifo->count);
422 fifo->count += count;
423 return count;
424 } /* fifo_update() */
425
426
fifo_rewind(struct fifo * fifo,size_t count)427 static inline size_t fifo_rewind(struct fifo *fifo, size_t count) {
428 count = FIFO_MIN(count, fifo->size - fifo->count);
429 fifo->head = (fifo->head + (fifo->size - count)) % fifo->size;
430 fifo->count += count;
431 return count;
432 } /* fifo_rewind() */
433
434
fifo_write(struct fifo * fifo,const void * src,size_t len)435 FIFO_NOTUSED static int fifo_write(struct fifo *fifo, const void *src, size_t len) {
436 const unsigned char *p = src, *pe = p + len;
437 struct iovec iov;
438 size_t n;
439 int error = 0;
440
441 do {
442 while (fifo_wvec(fifo, &iov) && p < pe) {
443 n = FIFO_MIN(iov.iov_len, (size_t)(pe - p));
444 memcpy(iov.iov_base, p, n);
445 p += n;
446 fifo_update(fifo, n);
447 }
448 } while (p < pe && !(error = fifo_grow(fifo, pe - p)));
449
450 return error;
451 } /* fifo_write() */
452
453
fifo_read(struct fifo * fifo,void * dst,size_t lim)454 FIFO_NOTUSED static size_t fifo_read(struct fifo *fifo, void *dst, size_t lim) {
455 unsigned char *p = dst, *pe = p + lim;
456 struct iovec iov;
457 size_t n;
458
459 while (p < pe && fifo_rvec(fifo, &iov)) {
460 n = FIFO_MIN(iov.iov_len, (size_t)(pe - p));
461 memcpy(p, iov.iov_base, n);
462 p += n;
463 fifo_discard(fifo, n);
464 }
465
466 return p - (unsigned char *)dst;
467 } /* fifo_read() */
468
469
fifo_putc(struct fifo * fifo,int c)470 static int fifo_putc(struct fifo *fifo, int c) {
471 int error;
472
473 if (fifo->count >= fifo->size && (error = fifo_grow(fifo, 1)))
474 return error;
475
476 fifo->base[(fifo->head + fifo->count) % fifo->size] = (0xff & c);
477 fifo_update(fifo, 1);
478
479 return 0;
480 } /* fifo_putc() */
481
482
fifo_puts(struct fifo * fifo,const void * src)483 static inline int fifo_puts(struct fifo *fifo, const void *src) {
484 return fifo_write(fifo, src, strlen(src));
485 } /* fifo_puts() */
486
487
fifo_printf(struct fifo * fifo,const char * fmt,...)488 FIFO_NOTUSED FIFO_FORMAT(printf, 2, 3) static int fifo_printf(struct fifo *fifo, const char *fmt, ...) {
489 va_list ap;
490 struct iovec iov;
491 int count = 0, error;
492
493 do {
494 if ((error = fifo_wbuf(fifo, &iov, (size_t)count + 1)))
495 return error;
496
497 va_start(ap, fmt);
498 count = vsnprintf(iov.iov_base, iov.iov_len, fmt, ap);
499 va_end(ap);
500
501 if (count < 0)
502 return (errno)? errno : ENOMEM;
503 } while ((size_t)count >= iov.iov_len);
504
505 fifo_update(fifo, count);
506
507 return 0;
508 } /* fifo_printf() */
509
510
fifo_ungetc(struct fifo * fifo,int c)511 static inline int fifo_ungetc(struct fifo *fifo, int c) {
512 int error;
513
514 if ((error = fifo_grow(fifo, 1)))
515 return error;
516
517 assert(1 == fifo_rewind(fifo, 1));
518 fifo->base[fifo->head] = c;
519
520 return 0;
521 } /* fifo_ungetc() */
522
523
fifo_getc(struct fifo * fifo)524 static inline int fifo_getc(struct fifo *fifo) {
525 int c;
526
527 if (!fifo->count)
528 return EOF;
529
530 c = fifo->base[fifo->head];
531 fifo_discard(fifo, 1);
532
533 return c;
534 } /* fifo_getc() */
535
536
fifo_peek(struct fifo * fifo,size_t p)537 static inline int fifo_peek(struct fifo *fifo, size_t p) {
538 if (p >= fifo->count)
539 return EOF;
540
541 return fifo->base[(fifo->head + p) % fifo->size];
542 } /* fifo_peek() */
543
544
fifo_scan(struct fifo * fifo,size_t * p)545 static inline int fifo_scan(struct fifo *fifo, size_t *p) {
546 return fifo_peek(fifo, (*p)++);
547 } /* fifo_scan() */
548
549
550 #define FIFO_NOINFO 1
551
fifo_dump(struct fifo * fifo,FILE * fp,int flags)552 FIFO_NOTUSED static void fifo_dump(struct fifo *fifo, FILE *fp, int flags) {
553 static const unsigned char hex[] = "0123456789abcdef";
554 size_t p, n;
555 int ch;
556
557 if (!(FIFO_NOINFO & flags))
558 fprintf(fp, "%zu of %zu bytes in FIFO; %u unread bits (0x%.2x); %u unflushed bits (0x%.2x)\n", fifo->count, fifo->size, fifo->rbits.count, (((1 << fifo->rbits.count) - 1) & fifo->rbits.byte), fifo->wbits.count, (((1 << fifo->wbits.count) - 1) & fifo->wbits.byte));
559
560 for (p = 0; p < fifo->count; p += 16) {
561 fprintf(fp, " %.4x ", (unsigned)p);
562
563 for (n = 0; n < 8 && EOF != (ch = fifo_peek(fifo, p)); n++, p++) {
564 fputc(hex[0x0f & (ch >> 4)], fp);
565 fputc(hex[0x0f & (ch >> 0)], fp);
566 fputc(' ', fp);
567 }
568
569 fputc(' ', fp);
570
571 for (; n < 16 && EOF != (ch = fifo_peek(fifo, p)); n++, p++) {
572 fputc(hex[0x0f & (ch >> 4)], fp);
573 fputc(hex[0x0f & (ch >> 0)], fp);
574 fputc(' ', fp);
575 }
576
577 p -= n;
578
579 for (; n < 16; n++) {
580 fputc(' ', fp);
581 fputc(' ', fp);
582 fputc(' ', fp);
583 }
584
585 fputc(' ', fp);
586 fputc('|', fp);
587
588 for (n = 0; n < 16 && EOF != (ch = fifo_peek(fifo, p)); n++, p++) {
589 fputc((isgraph(ch)? ch : '.'), fp);
590 }
591
592 p -= n;
593
594 for (; n < 16; n++)
595 fputc(' ', fp);
596
597 fputc('|', fp);
598 fputc('\n', fp);
599 }
600 } /* fifo_dump() */
601
602 #define fifo_dump3(...) fifo_dump(__VA_ARGS__)
603 #define fifo_dump2(...) fifo_dump3(__VA_ARGS__, 0)
604 #define fifo_dump1(...) fifo_dump3(__VA_ARGS__, stderr, 0)
605 #define fifo_dump(...) FIFO_XPASTE(fifo_dump, FIFO_NARG(__VA_ARGS__))(__VA_ARGS__)
606
607
608 /*
609 * B I T P A C K I N G R O U T I N E S
610 *
611 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
612
fifo_rbits(struct fifo * fifo)613 static inline size_t fifo_rbits(struct fifo *fifo) {
614 return fifo->rbits.count + (8 * fifo_rlen(fifo));
615 } /* fifo_rbits() */
616
617
fifo_wbits(struct fifo * fifo)618 static inline size_t fifo_wbits(struct fifo *fifo) {
619 return (8 - fifo->wbits.count) + (8 * fifo_wlen(fifo));
620 } /* fifo_wbits() */
621
622
fifo_unpack(struct fifo * fifo,unsigned count)623 FIFO_NOTUSED static unsigned long long fifo_unpack(struct fifo *fifo, unsigned count) {
624 unsigned long long bits = 0;
625 unsigned mask, nbits;
626
627 if (fifo_rbits(fifo) < count)
628 return 0;
629
630 while (count) {
631 if (!fifo->rbits.count) {
632 fifo->rbits.byte = fifo_getc(fifo);
633 fifo->rbits.count = 8;
634 }
635
636 nbits = FIFO_MIN(count, fifo->rbits.count);
637 mask = (1 << nbits) - 1;
638
639 bits <<= nbits;
640 bits |= mask & (fifo->rbits.byte >> (fifo->rbits.count - nbits));
641
642 fifo->rbits.count -= nbits;
643 count -= nbits;
644 }
645
646 return bits;
647 } /* fifo_unpack() */
648
649
fifo_pack(struct fifo * fifo,unsigned long long bits,unsigned count)650 FIFO_NOTUSED static int fifo_pack(struct fifo *fifo, unsigned long long bits, unsigned count) {
651 unsigned mask, nbits;
652 int error;
653
654 if (fifo_wbits(fifo) < count && (error = fifo_grow(fifo, 8)))
655 return error;
656
657 while (count) {
658 nbits = FIFO_MIN(count, 8U - fifo->wbits.count);
659 mask = (1U << nbits) - 1;
660
661 fifo->wbits.byte <<= nbits;
662 fifo->wbits.byte |= mask & (bits >> (count - nbits));
663 fifo->wbits.count += nbits;
664
665 count -= nbits;
666
667 if (fifo->wbits.count >= 8) {
668 fifo_putc(fifo, fifo->wbits.byte);
669
670 fifo->wbits.byte = 0;
671 fifo->wbits.count = 0;
672 }
673 }
674
675 return 0;
676 } /* fifo_pack() */
677
678 #endif /* FIFO_H */
679
680
681 #if FIFO_MAIN
682
683 #include <locale.h>
684
main(void)685 int main(void) {
686 struct fifo *fifo = fifo_new(0);
687 struct iovec iov;
688 int ch;
689
690 setlocale(LC_ALL, "C");
691
692 while (EOF != (ch = getchar()))
693 fifo_putc(fifo, ch);
694
695 puts("[stdin]");
696 fifo_dump(fifo, stdout);
697
698 puts("[shifted 4 bits]");
699 fifo_pack(fifo, fifo_unpack(fifo, 4), 4);
700 fifo_dump(fifo, stdout);
701
702 puts("[shifted 1/2 count]");
703 for (size_t i = 0; i < fifo->count / 2; i++)
704 fifo_putc(fifo, fifo_getc(fifo));
705 fifo_dump(fifo, stdout);
706
707 puts("[slice of 17 bytes at 17]");
708 fifo_slice(fifo, &iov, 17, 17);
709 fifo_dump(fifo_from(iov.iov_base, iov.iov_len), stdout);
710
711 return 0;
712 } /* main() */
713
714 #endif /* FIFO_MAIN */
715
716