/src/util-linux/lib/buffer.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * No copyright is claimed. This code is in the public domain; do with |
3 | | * it what you wish. |
4 | | * |
5 | | * Written by Karel Zak <kzak@redhat.com> |
6 | | */ |
7 | | #include "buffer.h" |
8 | | #include "mbsalign.h" |
9 | | #include "strutils.h" |
10 | | |
11 | | void ul_buffer_reset_data(struct ul_buffer *buf) |
12 | 0 | { |
13 | 0 | if (buf->begin) |
14 | 0 | memset(buf->begin, 0, buf->sz); |
15 | 0 | buf->end = buf->begin; |
16 | |
|
17 | 0 | if (buf->ptrs && buf->nptrs) |
18 | 0 | memset(buf->ptrs, 0, buf->nptrs * sizeof(char *)); |
19 | 0 | } |
20 | | |
21 | | void ul_buffer_free_data(struct ul_buffer *buf) |
22 | 0 | { |
23 | 0 | assert(buf); |
24 | | |
25 | 0 | free(buf->begin); |
26 | 0 | buf->begin = NULL; |
27 | 0 | buf->end = NULL; |
28 | 0 | buf->sz = 0; |
29 | |
|
30 | 0 | free(buf->ptrs); |
31 | 0 | buf->ptrs = NULL; |
32 | 0 | buf->nptrs = 0; |
33 | |
|
34 | 0 | free(buf->encoded); |
35 | 0 | buf->encoded = NULL; |
36 | 0 | buf->encoded_sz = 0; |
37 | 0 | } |
38 | | |
39 | | void ul_buffer_set_chunksize(struct ul_buffer *buf, size_t sz) |
40 | 0 | { |
41 | 0 | buf->chunksize = sz; |
42 | 0 | } |
43 | | |
44 | | int ul_buffer_is_empty(struct ul_buffer *buf) |
45 | 0 | { |
46 | 0 | return buf->begin == buf->end; |
47 | 0 | } |
48 | | |
49 | | int ul_buffer_save_pointer(struct ul_buffer *buf, unsigned short ptr_idx) |
50 | 0 | { |
51 | 0 | if (ptr_idx >= buf->nptrs) { |
52 | 0 | char **tmp = reallocarray(buf->ptrs, ptr_idx + 1, sizeof(char *)); |
53 | |
|
54 | 0 | if (!tmp) |
55 | 0 | return -EINVAL; |
56 | 0 | buf->ptrs = tmp; |
57 | 0 | buf->nptrs = ptr_idx + 1; |
58 | 0 | } |
59 | | |
60 | 0 | buf->ptrs[ptr_idx] = buf->end; |
61 | 0 | return 0; |
62 | 0 | } |
63 | | |
64 | | |
65 | | char *ul_buffer_get_pointer(struct ul_buffer *buf, unsigned short ptr_idx) |
66 | 0 | { |
67 | 0 | if (ptr_idx < buf->nptrs) |
68 | 0 | return buf->ptrs[ptr_idx]; |
69 | 0 | return NULL; |
70 | 0 | } |
71 | | |
72 | | /* returns length from begin to the pointer */ |
73 | | size_t ul_buffer_get_pointer_length(struct ul_buffer *buf, unsigned short ptr_idx) |
74 | 0 | { |
75 | 0 | char *ptr = ul_buffer_get_pointer(buf, ptr_idx); |
76 | |
|
77 | 0 | if (ptr && ptr > buf->begin) |
78 | 0 | return ptr - buf->begin; |
79 | 0 | return 0; |
80 | 0 | } |
81 | | |
82 | | /* returns width of data in safe encoding (from the begin to the pointer) */ |
83 | | size_t ul_buffer_get_safe_pointer_width(struct ul_buffer *buf, unsigned short ptr_idx) |
84 | 0 | { |
85 | 0 | size_t len = ul_buffer_get_pointer_length(buf, ptr_idx); |
86 | |
|
87 | 0 | if (!len) |
88 | 0 | return 0; |
89 | | |
90 | 0 | return mbs_safe_nwidth(buf->begin, len, NULL); |
91 | 0 | } |
92 | | |
93 | | void ul_buffer_refer_string(struct ul_buffer *buf, char *str) |
94 | 0 | { |
95 | 0 | if (buf->sz) |
96 | 0 | ul_buffer_free_data(buf); |
97 | 0 | buf->begin = str; |
98 | 0 | buf->sz = str ? strlen(str) : 0; |
99 | 0 | buf->end = buf->begin ? buf->begin + buf->sz : buf->begin; |
100 | 0 | } |
101 | | |
102 | | int ul_buffer_alloc_data(struct ul_buffer *buf, size_t sz) |
103 | 0 | { |
104 | 0 | char *tmp; |
105 | 0 | size_t len = 0; |
106 | |
|
107 | 0 | assert(buf); |
108 | | |
109 | 0 | if (sz <= buf->sz) |
110 | 0 | return 0; |
111 | | |
112 | 0 | if (buf->end && buf->begin) |
113 | 0 | len = buf->end - buf->begin; |
114 | |
|
115 | 0 | if (buf->chunksize) |
116 | 0 | sz = ((sz + buf->chunksize) / buf->chunksize) * buf->chunksize + 1; |
117 | |
|
118 | 0 | tmp = realloc(buf->begin, sz); |
119 | 0 | if (!tmp) |
120 | 0 | return -ENOMEM; |
121 | | |
122 | 0 | buf->begin = tmp; |
123 | 0 | buf->end = buf->begin + len; |
124 | 0 | buf->sz = sz; |
125 | |
|
126 | 0 | memset(buf->end, '\0', sz - len); |
127 | |
|
128 | 0 | return 0; |
129 | 0 | } |
130 | | |
131 | | int ul_buffer_append_data(struct ul_buffer *buf, const char *data, size_t sz) |
132 | 0 | { |
133 | 0 | size_t maxsz = 0; |
134 | |
|
135 | 0 | if (!buf) |
136 | 0 | return -EINVAL; |
137 | 0 | if (!data) |
138 | 0 | return 0; |
139 | | |
140 | 0 | if (buf->begin && buf->end) |
141 | 0 | maxsz = buf->sz - (buf->end - buf->begin); |
142 | 0 | if (maxsz <= sz + 1) { |
143 | 0 | int rc = ul_buffer_alloc_data(buf, buf->sz + sz + 1); |
144 | 0 | if (rc) |
145 | 0 | return rc; |
146 | 0 | } |
147 | 0 | if (!buf->end) |
148 | 0 | return -EINVAL; /* make static analyzers happy */ |
149 | | |
150 | 0 | buf->end = mempcpy(buf->end, data, sz); |
151 | 0 | *buf->end = '\0'; /* make sure it's terminated */ |
152 | 0 | return 0; |
153 | 0 | } |
154 | | |
155 | | int ul_buffer_append_string(struct ul_buffer *buf, const char *str) |
156 | 0 | { |
157 | 0 | if (!str) |
158 | 0 | return 0; |
159 | | |
160 | 0 | return ul_buffer_append_data(buf, str, strlen(str)); |
161 | 0 | } |
162 | | |
163 | | int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str) |
164 | 0 | { |
165 | 0 | size_t i; |
166 | 0 | size_t len = strlen(str); |
167 | |
|
168 | 0 | for (i = 0; len && i < n; i++) { |
169 | 0 | int rc = ul_buffer_append_data(buf, str, len); |
170 | 0 | if (rc) |
171 | 0 | return rc; |
172 | 0 | } |
173 | 0 | return 0; |
174 | 0 | } |
175 | | |
176 | | int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz) |
177 | 0 | { |
178 | 0 | ul_buffer_reset_data(buf); |
179 | 0 | return ul_buffer_append_data(buf, data, sz); |
180 | 0 | } |
181 | | |
182 | | char *ul_buffer_get_data(struct ul_buffer *buf, size_t *sz, size_t *width) |
183 | 0 | { |
184 | 0 | if (sz) |
185 | 0 | *sz = buf->end - buf->begin; |
186 | 0 | if (width) |
187 | 0 | *width = buf->begin && *buf->begin ? mbs_width(buf->begin) : 0; |
188 | 0 | return buf->begin; |
189 | 0 | } |
190 | | |
191 | | char *ul_buffer_get_string(struct ul_buffer *buf, size_t *sz, size_t *width) |
192 | 0 | { |
193 | 0 | char *ret; |
194 | |
|
195 | 0 | ret = ul_buffer_get_data(buf, sz, width); |
196 | | |
197 | | /* data in buffer is already zero-terminated */ |
198 | 0 | if (sz) |
199 | 0 | *sz = *sz + 1; |
200 | |
|
201 | 0 | return ret; |
202 | 0 | } |
203 | | |
204 | | /* size of allocated area (!= size of stored data */ |
205 | | size_t ul_buffer_get_bufsiz(struct ul_buffer *buf) |
206 | 0 | { |
207 | 0 | return buf->sz; |
208 | 0 | } |
209 | | |
210 | | size_t ul_buffer_get_datasiz(struct ul_buffer *buf) |
211 | 0 | { |
212 | 0 | return buf->end - buf->begin; |
213 | 0 | } |
214 | | |
215 | | /* encode data by mbs_safe_encode() to avoid control and non-printable chars */ |
216 | | char *ul_buffer_get_safe_data(struct ul_buffer *buf, size_t *sz, size_t *width, const char *safechars) |
217 | 0 | { |
218 | 0 | char *data = ul_buffer_get_data(buf, NULL, NULL); |
219 | 0 | size_t encsz, wsz = 0; |
220 | 0 | char *res = NULL; |
221 | |
|
222 | 0 | if (!data) |
223 | 0 | goto nothing; |
224 | | |
225 | 0 | encsz = mbs_safe_encode_size(buf->sz) + 1; |
226 | 0 | if (encsz > buf->encoded_sz) { |
227 | 0 | char *tmp = realloc(buf->encoded, encsz); |
228 | 0 | if (!tmp) |
229 | 0 | goto nothing; |
230 | 0 | buf->encoded = tmp; |
231 | 0 | buf->encoded_sz = encsz; |
232 | 0 | } |
233 | | |
234 | 0 | res = mbs_safe_encode_to_buffer(data, &wsz, buf->encoded, safechars); |
235 | 0 | if (!res || !wsz || wsz == (size_t) -1) |
236 | 0 | goto nothing; |
237 | | |
238 | 0 | if (width) |
239 | 0 | *width = wsz; |
240 | 0 | if (sz) |
241 | 0 | *sz = strlen(res); |
242 | 0 | return res; |
243 | 0 | nothing: |
244 | 0 | if (width) |
245 | 0 | *width = 0; |
246 | 0 | if (sz) |
247 | 0 | *sz = 0; |
248 | 0 | return NULL; |
249 | 0 | } |
250 | | |
251 | | |
252 | | #ifdef TEST_PROGRAM_BUFFER |
253 | | |
254 | | enum { |
255 | | PTR_AAA = 0, |
256 | | PTR_BBB, |
257 | | }; |
258 | | |
259 | | int main(void) |
260 | | { |
261 | | struct ul_buffer buf = UL_INIT_BUFFER; |
262 | | char *str; |
263 | | size_t sz = 0; |
264 | | |
265 | | ul_buffer_set_chunksize(&buf, 16); |
266 | | |
267 | | ul_buffer_append_string(&buf, "AAA"); |
268 | | ul_buffer_append_data(&buf, "=", 1); |
269 | | ul_buffer_append_string(&buf, "aaa"); |
270 | | ul_buffer_save_pointer(&buf, PTR_AAA); |
271 | | |
272 | | ul_buffer_append_data(&buf, ",", 1); |
273 | | ul_buffer_append_string(&buf, "BBB"); |
274 | | ul_buffer_append_string(&buf, "="); |
275 | | ul_buffer_append_string(&buf, "bbb"); |
276 | | ul_buffer_save_pointer(&buf, PTR_BBB); |
277 | | |
278 | | str = ul_buffer_get_data(&buf, &sz, NULL); |
279 | | printf("data [%zu] '%s'\n", sz, str); |
280 | | |
281 | | printf(" pointer data len: AAA=%zu, BBB=%zu\n", |
282 | | ul_buffer_get_pointer_length(&buf, PTR_AAA), |
283 | | ul_buffer_get_pointer_length(&buf, PTR_BBB)); |
284 | | printf(" pointer data width: AAA=%zu, BBB=%zu\n", |
285 | | ul_buffer_get_safe_pointer_width(&buf, PTR_AAA), |
286 | | ul_buffer_get_safe_pointer_width(&buf, PTR_BBB)); |
287 | | |
288 | | ul_buffer_reset_data(&buf); |
289 | | ul_buffer_append_string(&buf, "This is really long string to test the buffer function."); |
290 | | ul_buffer_save_pointer(&buf, PTR_AAA); |
291 | | ul_buffer_append_string(&buf, " YES!"); |
292 | | str = ul_buffer_get_data(&buf, &sz, NULL); |
293 | | printf("data [%zu] '%s'\n", sz, str); |
294 | | printf(" pointer data len: AAA=%zu\n", ul_buffer_get_pointer_length(&buf, PTR_AAA)); |
295 | | |
296 | | ul_buffer_free_data(&buf); |
297 | | str = strdup("foo"); |
298 | | ul_buffer_refer_string(&buf, str); |
299 | | ul_buffer_append_data(&buf, ",", 1); |
300 | | ul_buffer_append_string(&buf, "bar"); |
301 | | str = ul_buffer_get_data(&buf, &sz, NULL); |
302 | | printf("data [%zu] '%s'\n", sz, str); |
303 | | |
304 | | ul_buffer_free_data(&buf); |
305 | | |
306 | | return EXIT_SUCCESS; |
307 | | } |
308 | | #endif /* TEST_PROGRAM_BUFFER */ |