1 /* ProcFS - buf.c - output buffer management for read calls */
2
3 #include "inc.h"
4 #include <stdarg.h>
5
6 static char *buf;
7 static size_t left, used;
8 static off_t skip;
9
10 /*
11 * Initialize the buffer for fresh use. The output is to be stored into 'ptr'
12 * which is BUF_SIZE bytes in size, since that is the size we requested. Due
13 * to the way vsnprintf works, we cannot use the last byte of this buffer. The
14 * first 'start' bytes of the produced output are to be skipped. After that, a
15 * total of 'len' bytes are requested.
16 */
17 void
buf_init(char * ptr,size_t len,off_t start)18 buf_init(char * ptr, size_t len, off_t start)
19 {
20
21 buf = ptr;
22 skip = start;
23 left = MIN(len, BUF_SIZE - 1);
24 used = 0;
25 }
26
27 /*
28 * Add formatted text to the end of the buffer.
29 */
30 void
buf_printf(char * fmt,...)31 buf_printf(char * fmt, ...)
32 {
33 va_list args;
34 ssize_t len, max;
35
36 if (left == 0)
37 return;
38
39 /*
40 * There is no way to estimate how much space the result will take, so
41 * we need to produce the string even when skipping part of the start.
42 * The null terminating character is not part of the result, so room
43 * must be given for it to be stored after completely filling up the
44 * requested part of the buffer.
45 */
46 max = MIN(skip + left + 1, BUF_SIZE);
47
48 va_start(args, fmt);
49 len = vsnprintf(&buf[used], max, fmt, args);
50 va_end(args);
51
52 /*
53 * The snprintf family returns the number of bytes that would be stored
54 * if the buffer were large enough, excluding the null terminator.
55 */
56 if (len >= BUF_SIZE)
57 len = BUF_SIZE - 1;
58
59 if (skip > 0) {
60 assert(used == 0);
61
62 if (skip >= len) {
63 skip -= len;
64
65 return;
66 }
67
68 memmove(buf, &buf[skip], len - skip);
69
70 len -= skip;
71 skip = 0;
72 }
73
74 assert(skip == 0);
75 assert(len >= 0);
76 assert((ssize_t) left >= 0);
77
78 if (len > (ssize_t)left)
79 len = left;
80
81 used += len;
82 left -= len;
83 }
84
85 /*
86 * Add arbitrary data to the end of the buffer.
87 */
88 void
buf_append(char * data,size_t len)89 buf_append(char * data, size_t len)
90 {
91
92 if (left == 0)
93 return;
94
95 if (skip > 0) {
96 if (skip >= (ssize_t)len) {
97 skip -= len;
98
99 return;
100 }
101
102 data += skip;
103 len -= skip;
104 skip = 0;
105 }
106
107 if (len > left)
108 len = left;
109
110 memcpy(&buf[used], data, len);
111
112 used += len;
113 left -= len;
114 }
115
116 /*
117 * Return the resulting number of bytes produced, not counting the trailing
118 * null character in the buffer.
119 */
120 ssize_t
buf_result(void)121 buf_result(void)
122 {
123
124 return used;
125 }
126