xref: /minix3/minix/servers/devman/buf.c (revision 5eefd0fec2bd5bc6ad818ba164bcc653f954426c)
1433d6423SLionel Sambuc /* buf.c - by Alen Stojanov and David van Moolenbroek, taken from procfs */
2433d6423SLionel Sambuc 
3*5eefd0feSDavid van Moolenbroek #include "devman.h"
4*5eefd0feSDavid van Moolenbroek #include "proto.h"
5433d6423SLionel Sambuc #include <stdarg.h>
6433d6423SLionel Sambuc #include <assert.h>
7433d6423SLionel Sambuc 
8*5eefd0feSDavid van Moolenbroek static char *buf;
9*5eefd0feSDavid van Moolenbroek static size_t left, used;
10433d6423SLionel Sambuc static off_t skip;
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc /*===========================================================================*
13433d6423SLionel Sambuc  *				buf_init				     *
14433d6423SLionel Sambuc  *===========================================================================*/
buf_init(char * ptr,size_t len,off_t start)15*5eefd0feSDavid van Moolenbroek void buf_init(char *ptr, size_t len, off_t start)
16433d6423SLionel Sambuc {
17*5eefd0feSDavid van Moolenbroek 	/* Initialize the buffer for fresh use. The output is to be stored into
18*5eefd0feSDavid van Moolenbroek 	 * 'ptr' which is BUF_SIZE bytes in size, since that is the size we
19*5eefd0feSDavid van Moolenbroek 	 * requested. Due to the way vsnprintf works, we cannot use the last
20*5eefd0feSDavid van Moolenbroek 	 * byte of this buffer. The first 'start' bytes of the produced output
21*5eefd0feSDavid van Moolenbroek 	 * are to be skipped. After that, a total of 'len' bytes are requested.
22433d6423SLionel Sambuc 	 */
23433d6423SLionel Sambuc 
24*5eefd0feSDavid van Moolenbroek 	buf = ptr;
25433d6423SLionel Sambuc 	skip = start;
26*5eefd0feSDavid van Moolenbroek 	left = MIN(len, BUF_SIZE - 1);
27433d6423SLionel Sambuc 	used = 0;
28433d6423SLionel Sambuc }
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc /*===========================================================================*
31433d6423SLionel Sambuc  *				buf_printf				     *
32433d6423SLionel Sambuc  *===========================================================================*/
buf_printf(char * fmt,...)33433d6423SLionel Sambuc void buf_printf(char *fmt, ...)
34433d6423SLionel Sambuc {
35433d6423SLionel Sambuc 	/* Add formatted text to the end of the buffer.
36433d6423SLionel Sambuc 	 */
37433d6423SLionel Sambuc 	va_list args;
38433d6423SLionel Sambuc 	ssize_t len, max;
39433d6423SLionel Sambuc 
40433d6423SLionel Sambuc 	if (left == 0)
41433d6423SLionel Sambuc 		return;
42433d6423SLionel Sambuc 
43433d6423SLionel Sambuc 	/* There is no way to estimate how much space the result will take, so
44433d6423SLionel Sambuc 	 * we need to produce the string even when skipping part of the start.
45433d6423SLionel Sambuc 	 * The null terminating character is not part of the result, so room
46433d6423SLionel Sambuc 	 * must be given for it to be stored after completely filling up the
47433d6423SLionel Sambuc 	 * requested part of the buffer.
48433d6423SLionel Sambuc 	 */
49*5eefd0feSDavid van Moolenbroek 	max = MIN(skip + left + 1, BUF_SIZE);
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc 	va_start(args, fmt);
52*5eefd0feSDavid van Moolenbroek 	len = vsnprintf(&buf[used], max, fmt, args);
53433d6423SLionel Sambuc 	va_end(args);
54433d6423SLionel Sambuc 
55*5eefd0feSDavid van Moolenbroek 	/* The snprintf family returns the number of bytes that would be stored
56*5eefd0feSDavid van Moolenbroek 	 * if the buffer were large enough, excluding the null terminator.
57*5eefd0feSDavid van Moolenbroek 	 */
58*5eefd0feSDavid van Moolenbroek 	if (len >= BUF_SIZE)
59*5eefd0feSDavid van Moolenbroek 		len = BUF_SIZE - 1;
60*5eefd0feSDavid van Moolenbroek 
61433d6423SLionel Sambuc 	if (skip > 0) {
62433d6423SLionel Sambuc 		assert(used == 0);
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc 		if (skip >= len) {
65433d6423SLionel Sambuc 			skip -= len;
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc 			return;
68433d6423SLionel Sambuc 		}
69433d6423SLionel Sambuc 
70*5eefd0feSDavid van Moolenbroek 		memmove(buf, &buf[skip], len - skip);
71*5eefd0feSDavid van Moolenbroek 
72*5eefd0feSDavid van Moolenbroek 		len -= skip;
73433d6423SLionel Sambuc 		skip = 0;
74433d6423SLionel Sambuc 	}
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc 	assert(skip == 0);
77433d6423SLionel Sambuc 	assert(len >= 0);
78*5eefd0feSDavid van Moolenbroek 	assert((ssize_t) left >= 0);
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 	if (len > (ssize_t) left)
81433d6423SLionel Sambuc 		len = left;
82433d6423SLionel Sambuc 
83433d6423SLionel Sambuc 	used += len;
84433d6423SLionel Sambuc 	left -= len;
85433d6423SLionel Sambuc }
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc /*===========================================================================*
88433d6423SLionel Sambuc  *				buf_append				     *
89433d6423SLionel Sambuc  *===========================================================================*/
buf_append(char * data,size_t len)90433d6423SLionel Sambuc void buf_append(char *data, size_t len)
91433d6423SLionel Sambuc {
92433d6423SLionel Sambuc 	/* Add arbitrary data to the end of the buffer.
93433d6423SLionel Sambuc 	 */
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc 	if (left == 0)
96433d6423SLionel Sambuc 		return;
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc 	if (skip > 0) {
99433d6423SLionel Sambuc 		if (skip >= (ssize_t) len) {
100433d6423SLionel Sambuc 			skip -= len;
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc 			return;
103433d6423SLionel Sambuc 		}
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc 		data += skip;
106433d6423SLionel Sambuc 		len -= skip;
107433d6423SLionel Sambuc 		skip = 0;
108433d6423SLionel Sambuc 	}
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc 	if (len > left)
111433d6423SLionel Sambuc 		len = left;
112433d6423SLionel Sambuc 
113*5eefd0feSDavid van Moolenbroek 	memcpy(&buf[used], data, len);
114433d6423SLionel Sambuc 
115433d6423SLionel Sambuc 	used += len;
116433d6423SLionel Sambuc 	left -= len;
117433d6423SLionel Sambuc }
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc /*===========================================================================*
120*5eefd0feSDavid van Moolenbroek  *				buf_result				     *
121433d6423SLionel Sambuc  *===========================================================================*/
buf_result(void)122*5eefd0feSDavid van Moolenbroek ssize_t buf_result(void)
123433d6423SLionel Sambuc {
124*5eefd0feSDavid van Moolenbroek 	/* Return the resulting number of bytes produced, not counting the
125*5eefd0feSDavid van Moolenbroek 	 * trailing null character in the buffer.
126433d6423SLionel Sambuc 	 */
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc 	return used;
129433d6423SLionel Sambuc }
130