xref: /minix/minix/fs/procfs/buf.c (revision e3b78ef1)
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
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
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
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
121 buf_result(void)
122 {
123 
124 	return used;
125 }
126