]>
Commit | Line | Data |
---|---|---|
3836cd2d KZ |
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 | */ | |
0a993981 | 7 | #include "buffer.h" |
9ea47344 | 8 | #include "mbsalign.h" |
cba33452 | 9 | #include "strutils.h" |
0a993981 KZ |
10 | |
11 | void ul_buffer_reset_data(struct ul_buffer *buf) | |
12 | { | |
13 | if (buf->begin) | |
f9ba5fa0 | 14 | memset(buf->begin, 0, buf->sz); |
0a993981 | 15 | buf->end = buf->begin; |
68463f5a KZ |
16 | |
17 | if (buf->ptrs && buf->nptrs) | |
18 | memset(buf->ptrs, 0, buf->nptrs * sizeof(char *)); | |
0a993981 KZ |
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; | |
f55be401 KZ |
29 | |
30 | free(buf->ptrs); | |
31 | buf->ptrs = NULL; | |
32 | buf->nptrs = 0; | |
9ea47344 KZ |
33 | |
34 | free(buf->encoded); | |
35 | buf->encoded = NULL; | |
36 | buf->encoded_sz = 0; | |
0a993981 KZ |
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 | ||
f55be401 KZ |
49 | int ul_buffer_save_pointer(struct ul_buffer *buf, unsigned short ptr_idx) |
50 | { | |
51 | if (ptr_idx >= buf->nptrs) { | |
64d6d400 | 52 | char **tmp = reallocarray(buf->ptrs, ptr_idx + 1, sizeof(char *)); |
f55be401 KZ |
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 | ||
9ea47344 | 72 | /* returns length from begin to the pointer */ |
f55be401 KZ |
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 | ||
9ea47344 | 77 | if (ptr && ptr > buf->begin) |
f55be401 KZ |
78 | return ptr - buf->begin; |
79 | return 0; | |
80 | } | |
81 | ||
9ea47344 KZ |
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 | } | |
f55be401 | 92 | |
0a993981 KZ |
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; | |
c76f79e9 | 99 | buf->end = buf->begin ? buf->begin + buf->sz : buf->begin; |
0a993981 KZ |
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 | ||
43485143 KZ |
126 | memset(buf->end, '\0', sz - len); |
127 | ||
0a993981 KZ |
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; | |
f9ba5fa0 | 137 | if (!data) |
0a993981 KZ |
138 | return 0; |
139 | ||
140 | if (buf->begin && buf->end) | |
141 | maxsz = buf->sz - (buf->end - buf->begin); | |
0a993981 KZ |
142 | if (maxsz <= sz + 1) { |
143 | int rc = ul_buffer_alloc_data(buf, buf->sz + sz + 1); | |
144 | if (rc) | |
145 | return rc; | |
146 | } | |
f831651e KZ |
147 | if (!buf->end) |
148 | return -EINVAL; /* make static analyzers happy */ | |
149 | ||
cba33452 | 150 | buf->end = mempcpy(buf->end, data, sz); |
0a993981 KZ |
151 | *buf->end = '\0'; /* make sure it's terminated */ |
152 | return 0; | |
153 | } | |
154 | ||
155 | int ul_buffer_append_string(struct ul_buffer *buf, const char *str) | |
156 | { | |
cc9e5641 KZ |
157 | if (!str) |
158 | return 0; | |
159 | ||
0a993981 KZ |
160 | return ul_buffer_append_data(buf, str, strlen(str)); |
161 | } | |
162 | ||
163 | int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str) | |
164 | { | |
165 | size_t i; | |
166 | size_t len = strlen(str); | |
167 | ||
168 | for (i = 0; len && i < n; i++) { | |
169 | int rc = ul_buffer_append_data(buf, str, len); | |
170 | if (rc) | |
171 | return rc; | |
172 | } | |
173 | return 0; | |
174 | } | |
175 | ||
176 | int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz) | |
177 | { | |
178 | ul_buffer_reset_data(buf); | |
179 | return ul_buffer_append_data(buf, data, sz); | |
180 | } | |
181 | ||
9ea47344 | 182 | char *ul_buffer_get_data(struct ul_buffer *buf, size_t *sz, size_t *width) |
0a993981 | 183 | { |
f60dc888 KZ |
184 | if (sz) |
185 | *sz = buf->end - buf->begin; | |
9ea47344 KZ |
186 | if (width) |
187 | *width = buf->begin && *buf->begin ? mbs_width(buf->begin) : 0; | |
0a993981 KZ |
188 | return buf->begin; |
189 | } | |
190 | ||
f60dc888 KZ |
191 | /* size of allocated area (!= size of stored data */ |
192 | size_t ul_buffer_get_bufsiz(struct ul_buffer *buf) | |
193 | { | |
194 | return buf->sz; | |
195 | } | |
196 | ||
9ea47344 KZ |
197 | /* encode data by mbs_safe_encode() to avoid control and non-printable chars */ |
198 | char *ul_buffer_get_safe_data(struct ul_buffer *buf, size_t *sz, size_t *width, const char *safechars) | |
199 | { | |
200 | char *data = ul_buffer_get_data(buf, NULL, NULL); | |
201 | size_t encsz, wsz = 0; | |
202 | char *res = NULL; | |
203 | ||
204 | if (!data) | |
205 | goto nothing; | |
206 | ||
207 | encsz = mbs_safe_encode_size(buf->sz) + 1; | |
208 | if (encsz > buf->encoded_sz) { | |
209 | char *tmp = realloc(buf->encoded, encsz); | |
210 | if (!tmp) | |
211 | goto nothing; | |
212 | buf->encoded = tmp; | |
213 | buf->encoded_sz = encsz; | |
214 | } | |
215 | ||
216 | res = mbs_safe_encode_to_buffer(data, &wsz, buf->encoded, safechars); | |
217 | if (!res || !wsz || wsz == (size_t) -1) | |
218 | goto nothing; | |
219 | ||
220 | if (width) | |
221 | *width = wsz; | |
222 | if (sz) | |
223 | *sz = strlen(res); | |
224 | return res; | |
225 | nothing: | |
226 | if (width) | |
227 | *width = 0; | |
228 | if (sz) | |
229 | *sz = 0; | |
230 | return NULL; | |
231 | } | |
232 | ||
f60dc888 | 233 | |
0a993981 | 234 | #ifdef TEST_PROGRAM_BUFFER |
f55be401 KZ |
235 | |
236 | enum { | |
237 | PTR_AAA = 0, | |
238 | PTR_BBB, | |
239 | }; | |
240 | ||
0a993981 KZ |
241 | int main(void) |
242 | { | |
243 | struct ul_buffer buf = UL_INIT_BUFFER; | |
244 | char *str; | |
f60dc888 | 245 | size_t sz = 0; |
0a993981 KZ |
246 | |
247 | ul_buffer_set_chunksize(&buf, 16); | |
248 | ||
249 | ul_buffer_append_string(&buf, "AAA"); | |
250 | ul_buffer_append_data(&buf, "=", 1); | |
251 | ul_buffer_append_string(&buf, "aaa"); | |
f55be401 KZ |
252 | ul_buffer_save_pointer(&buf, PTR_AAA); |
253 | ||
0a993981 KZ |
254 | ul_buffer_append_data(&buf, ",", 1); |
255 | ul_buffer_append_string(&buf, "BBB"); | |
256 | ul_buffer_append_string(&buf, "="); | |
257 | ul_buffer_append_string(&buf, "bbb"); | |
f55be401 | 258 | ul_buffer_save_pointer(&buf, PTR_BBB); |
0a993981 | 259 | |
9ea47344 | 260 | str = ul_buffer_get_data(&buf, &sz, NULL); |
f60dc888 | 261 | printf("data [%zu] '%s'\n", sz, str); |
0a993981 | 262 | |
f55be401 KZ |
263 | printf(" pointer data len: AAA=%zu, BBB=%zu\n", |
264 | ul_buffer_get_pointer_length(&buf, PTR_AAA), | |
265 | ul_buffer_get_pointer_length(&buf, PTR_BBB)); | |
9ea47344 KZ |
266 | printf(" pointer data width: AAA=%zu, BBB=%zu\n", |
267 | ul_buffer_get_safe_pointer_width(&buf, PTR_AAA), | |
268 | ul_buffer_get_safe_pointer_width(&buf, PTR_BBB)); | |
f55be401 | 269 | |
0a993981 KZ |
270 | ul_buffer_reset_data(&buf); |
271 | ul_buffer_append_string(&buf, "This is really long string to test the buffer function."); | |
f55be401 | 272 | ul_buffer_save_pointer(&buf, PTR_AAA); |
0a993981 | 273 | ul_buffer_append_string(&buf, " YES!"); |
9ea47344 | 274 | str = ul_buffer_get_data(&buf, &sz, NULL); |
f60dc888 | 275 | printf("data [%zu] '%s'\n", sz, str); |
f55be401 | 276 | printf(" pointer data len: AAA=%zu\n", ul_buffer_get_pointer_length(&buf, PTR_AAA)); |
0a993981 KZ |
277 | |
278 | ul_buffer_free_data(&buf); | |
279 | str = strdup("foo"); | |
280 | ul_buffer_refer_string(&buf, str); | |
281 | ul_buffer_append_data(&buf, ",", 1); | |
282 | ul_buffer_append_string(&buf, "bar"); | |
9ea47344 | 283 | str = ul_buffer_get_data(&buf, &sz, NULL); |
f60dc888 | 284 | printf("data [%zu] '%s'\n", sz, str); |
0a993981 KZ |
285 | |
286 | ul_buffer_free_data(&buf); | |
740b6c73 AP |
287 | |
288 | return EXIT_SUCCESS; | |
0a993981 KZ |
289 | } |
290 | #endif /* TEST_PROGRAM_BUFFER */ |