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