1*f1abbce7SDavid van Moolenbroek /* ProcFS - buf.c - output buffer management for read calls */
2433d6423SLionel Sambuc
3433d6423SLionel Sambuc #include "inc.h"
4433d6423SLionel Sambuc #include <stdarg.h>
5433d6423SLionel Sambuc
65eefd0feSDavid van Moolenbroek static char *buf;
75eefd0feSDavid van Moolenbroek static size_t left, used;
8433d6423SLionel Sambuc static off_t skip;
9433d6423SLionel Sambuc
10*f1abbce7SDavid van Moolenbroek /*
11*f1abbce7SDavid van Moolenbroek * Initialize the buffer for fresh use. The output is to be stored into 'ptr'
12*f1abbce7SDavid van Moolenbroek * which is BUF_SIZE bytes in size, since that is the size we requested. Due
13*f1abbce7SDavid van Moolenbroek * to the way vsnprintf works, we cannot use the last byte of this buffer. The
14*f1abbce7SDavid van Moolenbroek * first 'start' bytes of the produced output are to be skipped. After that, a
15*f1abbce7SDavid van Moolenbroek * total of 'len' bytes are requested.
16433d6423SLionel Sambuc */
17*f1abbce7SDavid van Moolenbroek void
buf_init(char * ptr,size_t len,off_t start)18*f1abbce7SDavid van Moolenbroek buf_init(char * ptr, size_t len, off_t start)
19*f1abbce7SDavid van Moolenbroek {
20433d6423SLionel Sambuc
215eefd0feSDavid van Moolenbroek buf = ptr;
22433d6423SLionel Sambuc skip = start;
235eefd0feSDavid van Moolenbroek left = MIN(len, BUF_SIZE - 1);
24433d6423SLionel Sambuc used = 0;
25433d6423SLionel Sambuc }
26433d6423SLionel Sambuc
27*f1abbce7SDavid van Moolenbroek /*
28*f1abbce7SDavid van Moolenbroek * Add formatted text to the end of the buffer.
29433d6423SLionel Sambuc */
30*f1abbce7SDavid van Moolenbroek void
buf_printf(char * fmt,...)31*f1abbce7SDavid van Moolenbroek buf_printf(char * fmt, ...)
32*f1abbce7SDavid van Moolenbroek {
33433d6423SLionel Sambuc va_list args;
34433d6423SLionel Sambuc ssize_t len, max;
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc if (left == 0)
37433d6423SLionel Sambuc return;
38433d6423SLionel Sambuc
39*f1abbce7SDavid van Moolenbroek /*
40*f1abbce7SDavid van Moolenbroek * There is no way to estimate how much space the result will take, so
41433d6423SLionel Sambuc * we need to produce the string even when skipping part of the start.
42433d6423SLionel Sambuc * The null terminating character is not part of the result, so room
43433d6423SLionel Sambuc * must be given for it to be stored after completely filling up the
44433d6423SLionel Sambuc * requested part of the buffer.
45433d6423SLionel Sambuc */
465eefd0feSDavid van Moolenbroek max = MIN(skip + left + 1, BUF_SIZE);
47433d6423SLionel Sambuc
48433d6423SLionel Sambuc va_start(args, fmt);
495eefd0feSDavid van Moolenbroek len = vsnprintf(&buf[used], max, fmt, args);
50433d6423SLionel Sambuc va_end(args);
51433d6423SLionel Sambuc
52*f1abbce7SDavid van Moolenbroek /*
53*f1abbce7SDavid van Moolenbroek * The snprintf family returns the number of bytes that would be stored
545eefd0feSDavid van Moolenbroek * if the buffer were large enough, excluding the null terminator.
555eefd0feSDavid van Moolenbroek */
565eefd0feSDavid van Moolenbroek if (len >= BUF_SIZE)
575eefd0feSDavid van Moolenbroek len = BUF_SIZE - 1;
585eefd0feSDavid van Moolenbroek
59433d6423SLionel Sambuc if (skip > 0) {
60433d6423SLionel Sambuc assert(used == 0);
61433d6423SLionel Sambuc
62433d6423SLionel Sambuc if (skip >= len) {
63433d6423SLionel Sambuc skip -= len;
64433d6423SLionel Sambuc
65433d6423SLionel Sambuc return;
66433d6423SLionel Sambuc }
67433d6423SLionel Sambuc
685eefd0feSDavid van Moolenbroek memmove(buf, &buf[skip], len - skip);
695eefd0feSDavid van Moolenbroek
705eefd0feSDavid van Moolenbroek len -= skip;
71433d6423SLionel Sambuc skip = 0;
72433d6423SLionel Sambuc }
73433d6423SLionel Sambuc
74433d6423SLionel Sambuc assert(skip == 0);
75433d6423SLionel Sambuc assert(len >= 0);
765eefd0feSDavid van Moolenbroek assert((ssize_t) left >= 0);
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc if (len > (ssize_t)left)
79433d6423SLionel Sambuc len = left;
80433d6423SLionel Sambuc
81433d6423SLionel Sambuc used += len;
82433d6423SLionel Sambuc left -= len;
83433d6423SLionel Sambuc }
84433d6423SLionel Sambuc
85*f1abbce7SDavid van Moolenbroek /*
86*f1abbce7SDavid van Moolenbroek * Add arbitrary data to the end of the buffer.
87433d6423SLionel Sambuc */
88*f1abbce7SDavid van Moolenbroek void
buf_append(char * data,size_t len)89*f1abbce7SDavid van Moolenbroek buf_append(char * data, size_t len)
90*f1abbce7SDavid van Moolenbroek {
91433d6423SLionel Sambuc
92433d6423SLionel Sambuc if (left == 0)
93433d6423SLionel Sambuc return;
94433d6423SLionel Sambuc
95433d6423SLionel Sambuc if (skip > 0) {
96433d6423SLionel Sambuc if (skip >= (ssize_t)len) {
97433d6423SLionel Sambuc skip -= len;
98433d6423SLionel Sambuc
99433d6423SLionel Sambuc return;
100433d6423SLionel Sambuc }
101433d6423SLionel Sambuc
102433d6423SLionel Sambuc data += skip;
103433d6423SLionel Sambuc len -= skip;
104433d6423SLionel Sambuc skip = 0;
105433d6423SLionel Sambuc }
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc if (len > left)
108433d6423SLionel Sambuc len = left;
109433d6423SLionel Sambuc
1105eefd0feSDavid van Moolenbroek memcpy(&buf[used], data, len);
111433d6423SLionel Sambuc
112433d6423SLionel Sambuc used += len;
113433d6423SLionel Sambuc left -= len;
114433d6423SLionel Sambuc }
115433d6423SLionel Sambuc
116*f1abbce7SDavid van Moolenbroek /*
117*f1abbce7SDavid van Moolenbroek * Return the resulting number of bytes produced, not counting the trailing
118*f1abbce7SDavid van Moolenbroek * null character in the buffer.
119433d6423SLionel Sambuc */
120*f1abbce7SDavid van Moolenbroek ssize_t
buf_result(void)121*f1abbce7SDavid van Moolenbroek buf_result(void)
122*f1abbce7SDavid van Moolenbroek {
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc return used;
125433d6423SLionel Sambuc }
126