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