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