xref: /minix3/minix/fs/procfs/buf.c (revision f1abbce7257a5fbf50b3422d6dd5631fd0bf26a5)
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