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