Coverage Report

Created: 2026-08-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/lib/buffer.c
Line
Count
Source
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
static inline char *ul_buffer_free_data_common(struct ul_buffer *buf, bool steal)
22
0
{
23
0
  char *t = NULL;
24
25
0
  assert(buf);
26
27
0
  if (steal)
28
0
    t = buf->begin;
29
0
  else
30
0
    free(buf->begin);
31
0
  buf->begin = NULL;
32
0
  buf->end = NULL;
33
0
  buf->sz = 0;
34
35
0
  free(buf->ptrs);
36
0
  buf->ptrs = NULL;
37
0
  buf->nptrs = 0;
38
39
0
  free(buf->encoded);
40
0
  buf->encoded = NULL;
41
0
  buf->encoded_sz = 0;
42
43
0
  return t;
44
0
}
45
46
void ul_buffer_free_data(struct ul_buffer *buf)
47
0
{
48
0
  ul_buffer_free_data_common(buf, false);
49
0
}
50
51
char *ul_buffer_steal_string(struct ul_buffer *buf)
52
0
{
53
0
  if (ul_buffer_is_empty(buf)) {
54
0
    ul_buffer_free_data(buf);
55
0
    return NULL;
56
0
  }
57
58
0
  return ul_buffer_free_data_common(buf, true);
59
0
}
60
61
void ul_buffer_set_chunksize(struct ul_buffer *buf, size_t sz)
62
0
{
63
0
  buf->chunksize = sz;
64
0
}
65
66
int ul_buffer_is_empty(struct ul_buffer *buf)
67
0
{
68
0
  return buf->begin == buf->end;
69
0
}
70
71
int ul_buffer_save_pointer(struct ul_buffer *buf, unsigned short ptr_idx)
72
0
{
73
0
  if (ptr_idx >= buf->nptrs) {
74
0
    char **tmp = reallocarray(buf->ptrs, ptr_idx + 1, sizeof(char *));
75
76
0
    if (!tmp)
77
0
      return -EINVAL;
78
0
    buf->ptrs = tmp;
79
0
    buf->nptrs = ptr_idx + 1;
80
0
  }
81
82
0
  buf->ptrs[ptr_idx] = buf->end;
83
0
  return 0;
84
0
}
85
86
87
char *ul_buffer_get_pointer(struct ul_buffer *buf, unsigned short ptr_idx)
88
0
{
89
0
  if (ptr_idx < buf->nptrs)
90
0
    return buf->ptrs[ptr_idx];
91
0
  return NULL;
92
0
}
93
94
/* returns length from begin to the pointer */
95
size_t ul_buffer_get_pointer_length(struct ul_buffer *buf, unsigned short ptr_idx)
96
0
{
97
0
  char *ptr = ul_buffer_get_pointer(buf, ptr_idx);
98
99
0
  if (ptr && ptr > buf->begin)
100
0
    return ptr - buf->begin;
101
0
  return 0;
102
0
}
103
104
/* returns width of data in safe encoding (from the begin to the pointer) */
105
size_t ul_buffer_get_safe_pointer_width(struct ul_buffer *buf, unsigned short ptr_idx)
106
0
{
107
0
  size_t len = ul_buffer_get_pointer_length(buf, ptr_idx);
108
109
0
  if (!len)
110
0
    return 0;
111
112
0
  return mbs_safe_nwidth(buf->begin, len, NULL);
113
0
}
114
115
void ul_buffer_refer_string(struct ul_buffer *buf, char *str)
116
0
{
117
0
  if (buf->sz)
118
0
    ul_buffer_free_data(buf);
119
0
  buf->begin = str;
120
0
  buf->sz = str ? strlen(str) : 0;
121
0
  buf->end = buf->begin ? buf->begin + buf->sz : buf->begin;
122
0
}
123
124
int ul_buffer_alloc_data(struct ul_buffer *buf, size_t sz)
125
0
{
126
0
  char *tmp;
127
0
  size_t len = 0;
128
129
0
  assert(buf);
130
131
0
  if (sz <= buf->sz)
132
0
    return 0;
133
134
0
  if (buf->end && buf->begin)
135
0
    len = buf->end - buf->begin;
136
137
0
  if (buf->chunksize)
138
0
    sz = ((sz + buf->chunksize) / buf->chunksize) * buf->chunksize + 1;
139
140
0
  tmp = realloc(buf->begin, sz);
141
0
  if (!tmp)
142
0
    return -ENOMEM;
143
144
0
  buf->begin = tmp;
145
0
  buf->end = buf->begin + len;
146
0
  buf->sz = sz;
147
148
0
  memset(buf->end, '\0', sz - len);
149
150
0
  return 0;
151
0
}
152
153
int ul_buffer_append_data(struct ul_buffer *buf, const char *data, size_t sz)
154
0
{
155
0
  size_t maxsz = 0;
156
157
0
  if (!buf)
158
0
    return -EINVAL;
159
0
  if (!data)
160
0
    return 0;
161
162
0
  if (buf->begin && buf->end)
163
0
    maxsz = buf->sz - (buf->end - buf->begin);
164
0
  if (maxsz <= sz + 1) {
165
0
    int rc = ul_buffer_alloc_data(buf, buf->sz + sz + 1);
166
0
    if (rc)
167
0
      return rc;
168
0
  }
169
0
  if (!buf->end)
170
0
    return -EINVAL; /* make static analyzers happy */
171
172
0
  buf->end = mempcpy(buf->end, data, sz);
173
0
  *buf->end = '\0'; /* make sure it's terminated */
174
0
  return 0;
175
0
}
176
177
int ul_buffer_append_char(struct ul_buffer *buf, const char c)
178
0
{
179
0
  return ul_buffer_append_data(buf, &c, 1);
180
0
}
181
182
int ul_buffer_append_string(struct ul_buffer *buf, const char *str)
183
0
{
184
0
  if (!str)
185
0
    return 0;
186
187
0
  return ul_buffer_append_data(buf, str, strlen(str));
188
0
}
189
190
int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str)
191
0
{
192
0
  size_t i;
193
0
  size_t len = strlen(str);
194
195
0
  for (i = 0; len && i < n; i++) {
196
0
    int rc = ul_buffer_append_data(buf, str, len);
197
0
    if (rc)
198
0
      return rc;
199
0
  }
200
0
  return 0;
201
0
}
202
203
int ul_buffer_appendf(struct ul_buffer *buf, const char *format, ...)
204
0
{
205
0
  va_list ap;
206
0
  int res;
207
208
0
  va_start(ap, format);
209
0
  res = ul_buffer_appendvf(buf, format, ap);
210
0
  va_end(ap);
211
212
0
  return res;
213
0
}
214
215
int ul_buffer_appendvf(struct ul_buffer *buf, const char *format, va_list ap)
216
0
{
217
0
  char *val;
218
0
  int sz;
219
0
  int res;
220
221
0
  sz = vasprintf(&val, format, ap);
222
0
  if (sz < 0)
223
0
    return -errno;
224
225
  /* Like strlen(), sz doesn't include the last null byte. */
226
0
  res = ul_buffer_append_data(buf, val, sz);
227
0
  free(val);
228
229
0
  return res;
230
0
}
231
232
int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz)
233
0
{
234
0
  ul_buffer_reset_data(buf);
235
0
  return ul_buffer_append_data(buf, data, sz);
236
0
}
237
238
char *ul_buffer_get_data(struct ul_buffer *buf, size_t *sz, size_t *width)
239
0
{
240
0
  if (sz)
241
0
    *sz = buf->end - buf->begin;
242
0
  if (width)
243
0
    *width = buf->begin && *buf->begin ? mbs_width(buf->begin) : 0;
244
0
  return buf->begin;
245
0
}
246
247
char *ul_buffer_get_string(struct ul_buffer *buf, size_t *sz, size_t *width)
248
0
{
249
0
  char *ret;
250
251
0
  ret = ul_buffer_get_data(buf, sz, width);
252
253
  /* data in buffer is already zero-terminated */
254
0
  if (sz)
255
0
    *sz = *sz + 1;
256
257
0
  return ret;
258
0
}
259
260
/* size of allocated area (!= size of stored data */
261
size_t ul_buffer_get_bufsiz(struct ul_buffer *buf)
262
0
{
263
0
  return buf->sz;
264
0
}
265
266
size_t ul_buffer_get_datasiz(struct ul_buffer *buf)
267
0
{
268
0
  return buf->end - buf->begin;
269
0
}
270
271
/* encode data by mbs_safe_encode() to avoid control and non-printable chars */
272
char *ul_buffer_get_safe_data(struct ul_buffer *buf, size_t *sz, size_t *width, const char *safechars)
273
0
{
274
0
  char *data = ul_buffer_get_data(buf, NULL, NULL);
275
0
  size_t encsz, wsz = 0;
276
0
  char *res = NULL;
277
278
0
  if (!data)
279
0
    goto nothing;
280
281
0
  encsz = mbs_safe_encode_size(buf->sz) + 1;
282
0
  if (encsz > buf->encoded_sz) {
283
0
    char *tmp = realloc(buf->encoded, encsz);
284
0
    if (!tmp)
285
0
      goto nothing;
286
0
    buf->encoded = tmp;
287
0
    buf->encoded_sz = encsz;
288
0
  }
289
290
0
  res = mbs_safe_encode_to_buffer(data, &wsz, buf->encoded, buf->encoded_sz, safechars);
291
0
  if (!res || !wsz || wsz == (size_t) -1)
292
0
    goto nothing;
293
294
0
  if (width)
295
0
    *width = wsz;
296
0
  if (sz)
297
0
    *sz = strlen(res);
298
0
  return res;
299
0
nothing:
300
0
  if (width)
301
0
    *width = 0;
302
0
  if (sz)
303
0
    *sz = 0;
304
  return NULL;
305
0
}
306
307
308
#ifdef TEST_PROGRAM_BUFFER
309
310
enum {
311
  PTR_AAA  = 0,
312
  PTR_BBB,
313
};
314
315
int main(void)
316
{
317
  struct ul_buffer buf = UL_INIT_BUFFER;
318
  char *str;
319
  size_t sz = 0;
320
321
  ul_buffer_set_chunksize(&buf, 16);
322
323
  ul_buffer_append_string(&buf, "AAA");
324
  ul_buffer_append_data(&buf, "=", 1);
325
  ul_buffer_append_string(&buf, "aaa");
326
  ul_buffer_save_pointer(&buf, PTR_AAA);
327
328
  ul_buffer_append_data(&buf, ",", 1);
329
  ul_buffer_append_string(&buf, "BBB");
330
  ul_buffer_append_string(&buf, "=");
331
  ul_buffer_append_string(&buf, "bbb");
332
  ul_buffer_save_pointer(&buf, PTR_BBB);
333
334
  str = ul_buffer_get_data(&buf, &sz, NULL);
335
  printf("data [%zu] '%s'\n", sz, str);
336
337
  printf(" pointer data len: AAA=%zu, BBB=%zu\n",
338
      ul_buffer_get_pointer_length(&buf, PTR_AAA),
339
      ul_buffer_get_pointer_length(&buf, PTR_BBB));
340
  printf(" pointer data width: AAA=%zu, BBB=%zu\n",
341
      ul_buffer_get_safe_pointer_width(&buf, PTR_AAA),
342
      ul_buffer_get_safe_pointer_width(&buf, PTR_BBB));
343
344
  ul_buffer_reset_data(&buf);
345
  ul_buffer_append_string(&buf, "This is really long string to test the buffer function.");
346
  ul_buffer_save_pointer(&buf, PTR_AAA);
347
  ul_buffer_append_string(&buf, " YES!");
348
  str = ul_buffer_get_data(&buf, &sz, NULL);
349
  printf("data [%zu] '%s'\n", sz, str);
350
  printf(" pointer data len: AAA=%zu\n", ul_buffer_get_pointer_length(&buf, PTR_AAA));
351
352
  ul_buffer_free_data(&buf);
353
  str = strdup("foo");
354
  ul_buffer_refer_string(&buf, str);
355
  ul_buffer_append_data(&buf, ",", 1);
356
  ul_buffer_append_string(&buf, "bar");
357
  str = ul_buffer_get_data(&buf, &sz, NULL);
358
  printf("data [%zu] '%s'\n", sz, str);
359
360
  ul_buffer_free_data(&buf);
361
  ul_buffer_appendf(&buf, "a%se%d", "bcd", 10);
362
  str = ul_buffer_get_data(&buf, &sz, NULL);
363
  printf("data [%zu] '%s'\n", sz, str);
364
365
  ul_buffer_free_data(&buf);
366
  ul_buffer_append_char(&buf, 'x');
367
  {
368
    char c = 'y';
369
    ul_buffer_append_char(&buf, c);
370
  }
371
  {
372
    const char c = 'z';
373
    ul_buffer_append_char(&buf, c);
374
  }
375
  str = ul_buffer_get_data(&buf, &sz, NULL);
376
  printf("data [%zu] '%s'\n", sz, str);
377
378
  ul_buffer_free_data(&buf);
379
380
  return EXIT_SUCCESS;
381
}
382
#endif /* TEST_PROGRAM_BUFFER */