Coverage Report

Created: 2025-06-13 06:36

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