]>
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) | |
14 | buf->begin[0] = '\0'; | |
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; | |
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 | } | |
f831651e KZ |
148 | if (!buf->end) |
149 | return -EINVAL; /* make static analyzers happy */ | |
150 | ||
cba33452 | 151 | buf->end = mempcpy(buf->end, data, sz); |
0a993981 KZ |
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 | { | |
cc9e5641 KZ |
158 | if (!str) |
159 | return 0; | |
160 | ||
0a993981 KZ |
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 | ||
9ea47344 | 183 | char *ul_buffer_get_data(struct ul_buffer *buf, size_t *sz, size_t *width) |
0a993981 | 184 | { |
f60dc888 KZ |
185 | if (sz) |
186 | *sz = buf->end - buf->begin; | |
9ea47344 KZ |
187 | if (width) |
188 | *width = buf->begin && *buf->begin ? mbs_width(buf->begin) : 0; | |
0a993981 KZ |
189 | return buf->begin; |
190 | } | |
191 | ||
f60dc888 KZ |
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 | ||
9ea47344 KZ |
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 | ||
f60dc888 | 234 | |
0a993981 | 235 | #ifdef TEST_PROGRAM_BUFFER |
f55be401 KZ |
236 | |
237 | enum { | |
238 | PTR_AAA = 0, | |
239 | PTR_BBB, | |
240 | }; | |
241 | ||
0a993981 KZ |
242 | int main(void) |
243 | { | |
244 | struct ul_buffer buf = UL_INIT_BUFFER; | |
245 | char *str; | |
f60dc888 | 246 | size_t sz = 0; |
0a993981 KZ |
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"); | |
f55be401 KZ |
253 | ul_buffer_save_pointer(&buf, PTR_AAA); |
254 | ||
0a993981 KZ |
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"); | |
f55be401 | 259 | ul_buffer_save_pointer(&buf, PTR_BBB); |
0a993981 | 260 | |
9ea47344 | 261 | str = ul_buffer_get_data(&buf, &sz, NULL); |
f60dc888 | 262 | printf("data [%zu] '%s'\n", sz, str); |
0a993981 | 263 | |
f55be401 KZ |
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)); | |
9ea47344 KZ |
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)); | |
f55be401 | 270 | |
0a993981 KZ |
271 | ul_buffer_reset_data(&buf); |
272 | ul_buffer_append_string(&buf, "This is really long string to test the buffer function."); | |
f55be401 | 273 | ul_buffer_save_pointer(&buf, PTR_AAA); |
0a993981 | 274 | ul_buffer_append_string(&buf, " YES!"); |
9ea47344 | 275 | str = ul_buffer_get_data(&buf, &sz, NULL); |
f60dc888 | 276 | printf("data [%zu] '%s'\n", sz, str); |
f55be401 | 277 | printf(" pointer data len: AAA=%zu\n", ul_buffer_get_pointer_length(&buf, PTR_AAA)); |
0a993981 KZ |
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"); | |
9ea47344 | 284 | str = ul_buffer_get_data(&buf, &sz, NULL); |
f60dc888 | 285 | printf("data [%zu] '%s'\n", sz, str); |
0a993981 KZ |
286 | |
287 | ul_buffer_free_data(&buf); | |
740b6c73 AP |
288 | |
289 | return EXIT_SUCCESS; | |
0a993981 KZ |
290 | } |
291 | #endif /* TEST_PROGRAM_BUFFER */ |