/src/wget2/libwget/buffer_printf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2012 Tim Ruehsen |
3 | | * Copyright (c) 2015-2024 Free Software Foundation, Inc. |
4 | | * |
5 | | * This file is part of libwget. |
6 | | * |
7 | | * Libwget is free software: you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as published by |
9 | | * the Free Software Foundation, either version 3 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * Libwget is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with libwget. If not, see <https://www.gnu.org/licenses/>. |
19 | | * |
20 | | * |
21 | | * Memory buffer printf routines |
22 | | * |
23 | | * Changelog |
24 | | * 24.09.2012 Tim Ruehsen created |
25 | | * |
26 | | */ |
27 | | |
28 | | #include <config.h> |
29 | | |
30 | | #include <stdio.h> |
31 | | #include <stdlib.h> |
32 | | #include <string.h> |
33 | | #include <stdbool.h> |
34 | | #include <c-ctype.h> |
35 | | |
36 | | #include <wget.h> |
37 | | #include "private.h" |
38 | | |
39 | | /** |
40 | | * \file |
41 | | * \brief Buffer management functions |
42 | | * \defgroup libwget-buffer Buffer management functions |
43 | | * @{ |
44 | | */ |
45 | | |
46 | | /* \cond _hide_internal_symbols */ |
47 | 0 | #define FLAG_ZERO_PADDED 1U |
48 | 0 | #define FLAG_LEFT_ADJUST 2U |
49 | 0 | #define FLAG_ALTERNATE 4U |
50 | 0 | #define FLAG_SIGNED 8U |
51 | 0 | #define FLAG_DECIMAL 16U |
52 | 0 | #define FLAG_OCTAL 32U |
53 | 0 | #define FLAG_HEXLO 64U |
54 | 0 | #define FLAG_HEXUP 128U |
55 | | /* \endcond */ |
56 | | |
57 | | static void copy_string(wget_buffer *buf, unsigned int flags, int field_width, int precision, const char *arg) |
58 | 0 | { |
59 | 0 | size_t length; |
60 | |
|
61 | 0 | if (!arg) { |
62 | 0 | wget_buffer_strcat(buf, "(null)"); |
63 | 0 | return; |
64 | 0 | } |
65 | | |
66 | 0 | if (precision >= 0) { |
67 | 0 | length = strnlen(arg, precision); |
68 | 0 | } else { |
69 | 0 | length = strlen(arg); |
70 | 0 | } |
71 | | |
72 | | // debug_printf("flags=0x%02x field_width=%d precision=%d length=%zu arg='%s'\n", |
73 | | // flags,field_width,precision,length,arg); |
74 | |
|
75 | 0 | if (field_width) { |
76 | 0 | if ((unsigned)field_width > length) { |
77 | 0 | if (flags & FLAG_LEFT_ADJUST) { |
78 | 0 | wget_buffer_memcat(buf, arg, length); |
79 | 0 | wget_buffer_memset_append(buf, ' ', field_width - length); |
80 | 0 | } else { |
81 | 0 | wget_buffer_memset_append(buf, ' ', field_width - length); |
82 | 0 | wget_buffer_memcat(buf, arg, length); |
83 | 0 | } |
84 | 0 | } else { |
85 | 0 | wget_buffer_memcat(buf, arg, length); |
86 | 0 | } |
87 | 0 | } else { |
88 | 0 | wget_buffer_memcat(buf, arg, length); |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | | static void convert_dec_fast(wget_buffer *buf, int arg) |
93 | 0 | { |
94 | 0 | char str[32]; // long enough to hold decimal long long |
95 | 0 | char *dst = str + sizeof(str) - 1; |
96 | 0 | int minus; |
97 | |
|
98 | 0 | if (arg < 0) { |
99 | 0 | minus = 1; |
100 | 0 | arg = -arg; |
101 | 0 | } else |
102 | 0 | minus = 0; |
103 | |
|
104 | 0 | while (arg >= 10) { |
105 | 0 | *dst-- = (arg % 10) + '0'; |
106 | 0 | arg /= 10; |
107 | 0 | } |
108 | 0 | *dst-- = (arg % 10) + '0'; |
109 | |
|
110 | 0 | if (minus) |
111 | 0 | *dst-- = '-'; |
112 | |
|
113 | 0 | wget_buffer_memcat(buf, dst + 1, sizeof(str) - (dst - str) - 1); |
114 | 0 | } |
115 | | |
116 | | static void convert_dec(wget_buffer *buf, unsigned int flags, int field_width, int precision, long long arg) |
117 | 0 | { |
118 | 0 | unsigned long long argu = (unsigned long long) arg; |
119 | 0 | char str[32], minus = 0; // long enough to hold decimal long long |
120 | 0 | char *dst = str + sizeof(str) - 1; |
121 | 0 | unsigned char c; |
122 | 0 | size_t length; |
123 | | |
124 | | // info_printf("arg1 = %lld %lld\n",arg,-arg); |
125 | |
|
126 | 0 | if (flags & FLAG_DECIMAL) { |
127 | 0 | if (flags & FLAG_SIGNED && arg < 0) { |
128 | 0 | minus = 1; |
129 | 0 | argu = -arg; |
130 | 0 | } |
131 | |
|
132 | 0 | while (argu) { |
133 | 0 | *dst-- = argu % 10 + '0'; |
134 | 0 | argu /= 10; |
135 | 0 | } |
136 | 0 | } else if (flags & FLAG_HEXLO) { |
137 | 0 | while (argu) { |
138 | | // slightly faster than having a HEX[] lookup table |
139 | 0 | *dst-- = (c = (argu & 0xf)) >= 10 ? c + 'a' - 10 : c + '0'; |
140 | 0 | argu >>= 4; |
141 | 0 | } |
142 | 0 | } else if (flags & FLAG_HEXUP) { |
143 | 0 | while (argu) { |
144 | | // slightly faster than having a HEX[] lookup table |
145 | 0 | *dst-- = (c = (argu & 0xf)) >= 10 ? c + 'A' - 10 : c + '0'; |
146 | 0 | argu >>= 4; |
147 | 0 | } |
148 | 0 | } else if (flags & FLAG_OCTAL) { |
149 | 0 | while (argu) { |
150 | 0 | *dst-- = (argu & 0x07) + '0'; |
151 | 0 | argu >>= 3; |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | | // info_printf("arg2 = %lld\n",arg); |
156 | | |
157 | |
|
158 | 0 | dst++; |
159 | |
|
160 | 0 | length = sizeof(str) - (dst - str); |
161 | |
|
162 | 0 | if (precision < 0) { |
163 | 0 | precision = 1; |
164 | 0 | } else { |
165 | 0 | flags &= ~FLAG_ZERO_PADDED; |
166 | 0 | } |
167 | | |
168 | | // info_printf("flags=0x%02x field_width=%d precision=%d length=%zd dst='%.*s'\n", |
169 | | // flags,field_width,precision,length,length,dst); |
170 | |
|
171 | 0 | if (field_width) { |
172 | 0 | if ((unsigned)field_width > length + minus) { |
173 | 0 | if (flags & FLAG_LEFT_ADJUST) { |
174 | 0 | if (minus) |
175 | 0 | wget_buffer_memset_append(buf, '-', 1); |
176 | |
|
177 | 0 | if (length < (unsigned)precision) { |
178 | 0 | wget_buffer_memset_append(buf, '0', precision - length); |
179 | 0 | wget_buffer_memcat(buf, dst, length); |
180 | 0 | if (field_width > precision + minus) |
181 | 0 | wget_buffer_memset_append(buf, ' ', field_width - precision - minus); |
182 | 0 | } else { |
183 | 0 | wget_buffer_memcat(buf, dst, length); |
184 | 0 | wget_buffer_memset_append(buf, ' ', field_width - length - minus); |
185 | 0 | } |
186 | 0 | } else { |
187 | 0 | if (length < (unsigned)precision) { |
188 | 0 | if (field_width > precision + minus) { |
189 | 0 | if (flags & FLAG_ZERO_PADDED) { |
190 | 0 | if (minus) |
191 | 0 | wget_buffer_memset_append(buf, '-', 1); |
192 | 0 | wget_buffer_memset_append(buf, '0', field_width - precision - minus); |
193 | 0 | } else { |
194 | 0 | wget_buffer_memset_append(buf, ' ', field_width - precision - minus); |
195 | 0 | if (minus) |
196 | 0 | wget_buffer_memset_append(buf, '-', 1); |
197 | 0 | } |
198 | 0 | } else { |
199 | 0 | if (minus) |
200 | 0 | wget_buffer_memset_append(buf, '-', 1); |
201 | 0 | } |
202 | 0 | wget_buffer_memset_append(buf, '0', precision - length); |
203 | 0 | } else { |
204 | 0 | if (flags & FLAG_ZERO_PADDED) { |
205 | 0 | if (minus) |
206 | 0 | wget_buffer_memset_append(buf, '-', 1); |
207 | 0 | wget_buffer_memset_append(buf, '0', field_width - length - minus); |
208 | 0 | } else { |
209 | 0 | wget_buffer_memset_append(buf, ' ', field_width - length - minus); |
210 | 0 | if (minus) |
211 | 0 | wget_buffer_memset_append(buf, '-', 1); |
212 | 0 | } |
213 | 0 | } |
214 | 0 | wget_buffer_memcat(buf, dst, length); |
215 | 0 | } |
216 | 0 | } else { |
217 | 0 | if (minus) |
218 | 0 | wget_buffer_memset_append(buf, '-', 1); |
219 | 0 | if (length < (unsigned)precision) |
220 | 0 | wget_buffer_memset_append(buf, '0', precision - length); |
221 | 0 | wget_buffer_memcat(buf, dst, length); |
222 | 0 | } |
223 | 0 | } else { |
224 | 0 | if (minus) |
225 | 0 | wget_buffer_memset_append(buf, '-', 1); |
226 | |
|
227 | 0 | if (length < (unsigned)precision) |
228 | 0 | wget_buffer_memset_append(buf, '0', precision - length); |
229 | |
|
230 | 0 | wget_buffer_memcat(buf, dst, length); |
231 | 0 | } |
232 | 0 | } |
233 | | |
234 | | static void convert_pointer(wget_buffer *buf, void *pointer) |
235 | 0 | { |
236 | 0 | static const char HEX[16] = "0123456789abcdef"; |
237 | 0 | char str[32]; // long enough to hold hexadecimal pointer |
238 | 0 | char *dst; |
239 | 0 | int length; |
240 | 0 | size_t arg; |
241 | |
|
242 | 0 | if (!pointer) { |
243 | 0 | wget_buffer_memcat(buf, "0x0", 3); |
244 | 0 | return; |
245 | 0 | } else { |
246 | 0 | wget_buffer_memcat(buf, "0x", 2); |
247 | 0 | } |
248 | | |
249 | | // convert to a size_t (covers full address room) tp allow integer arithmetic |
250 | 0 | arg = (size_t)pointer; |
251 | |
|
252 | 0 | length = 0; |
253 | 0 | dst = str + sizeof(str); |
254 | 0 | *--dst = 0; |
255 | 0 | do { |
256 | 0 | *--dst = HEX[arg&0xF]; |
257 | 0 | arg >>= 4; |
258 | 0 | length++; |
259 | 0 | } while (arg); |
260 | |
|
261 | 0 | wget_buffer_memcat(buf, dst, length); |
262 | 0 | } |
263 | | |
264 | | static const char *read_precision(const char *p, int *out, bool precision_is_external) |
265 | 0 | { |
266 | 0 | int precision; |
267 | |
|
268 | 0 | if (precision_is_external) { |
269 | 0 | precision = *out; |
270 | 0 | if (precision < 0 ) |
271 | 0 | precision = 0; |
272 | 0 | p++; |
273 | 0 | } else if (c_isdigit(*p)) { |
274 | 0 | precision = 0; |
275 | 0 | do { |
276 | 0 | precision = precision * 10 + (*p - '0'); |
277 | 0 | } while (c_isdigit(*++p)); |
278 | 0 | } else { |
279 | 0 | precision = -1; |
280 | 0 | } |
281 | |
|
282 | 0 | *out = precision; |
283 | 0 | return p; |
284 | 0 | } |
285 | | |
286 | | static const char *read_flag_chars(const char *p, unsigned int *out) |
287 | 0 | { |
288 | 0 | unsigned int flags; |
289 | |
|
290 | 0 | for (flags = 0; *p; p++) { |
291 | 0 | if (*p == '0') |
292 | 0 | flags |= FLAG_ZERO_PADDED; |
293 | 0 | else if (*p == '-') |
294 | 0 | flags |= FLAG_LEFT_ADJUST; |
295 | 0 | else if (*p == '#') |
296 | 0 | flags |= FLAG_ALTERNATE; |
297 | 0 | else |
298 | 0 | break; |
299 | 0 | } |
300 | |
|
301 | 0 | *out = flags; |
302 | 0 | return p; |
303 | 0 | } |
304 | | |
305 | | static const char *read_field_width(const char *p, int *out, unsigned int *flags, bool width_is_external) |
306 | 0 | { |
307 | 0 | int field_width; |
308 | |
|
309 | 0 | if (width_is_external) { |
310 | 0 | field_width = *out; |
311 | |
|
312 | 0 | if (field_width < 0) { |
313 | 0 | *flags |= FLAG_LEFT_ADJUST; |
314 | 0 | field_width = -field_width; |
315 | 0 | } |
316 | |
|
317 | 0 | p++; |
318 | 0 | } else { |
319 | 0 | for (field_width = 0; c_isdigit(*p); p++) |
320 | 0 | field_width = field_width * 10 + (*p - '0'); |
321 | 0 | } |
322 | |
|
323 | 0 | *out = field_width; |
324 | 0 | return p; |
325 | 0 | } |
326 | | |
327 | | /** |
328 | | * \param[in] buf A buffer, created with wget_buffer_init() or wget_buffer_alloc() |
329 | | * \param[in] fmt A `printf(3)`-like format string |
330 | | * \param[in] args A `va_list` with the format string placeholders' values |
331 | | * \return Length of the buffer after appending the formatted string |
332 | | * |
333 | | * Formats the string \p fmt (with `printf(3)`-like args) and appends the result to the end |
334 | | * of the buffer \p buf (using wget_buffer_memcat()). |
335 | | * |
336 | | * For more information, see `vprintf(3)`. |
337 | | */ |
338 | | size_t wget_buffer_vprintf_append(wget_buffer *buf, const char *fmt, va_list args) |
339 | 80 | { |
340 | 80 | const char *p = fmt, *begin; |
341 | 80 | int field_width, precision; |
342 | 80 | unsigned int flags; |
343 | 80 | long long arg; |
344 | 80 | unsigned long long argu; |
345 | | |
346 | 80 | if (!p) |
347 | 0 | return 0; |
348 | | |
349 | 160 | for (;*p;) { |
350 | | |
351 | | /* |
352 | | * Collect plain char sequence. |
353 | | * Walk the string until we find a '%' character. |
354 | | */ |
355 | 80 | for (begin = p; *p && *p != '%'; p++); |
356 | 80 | if (p != begin) |
357 | 0 | wget_buffer_memcat(buf, begin, p - begin); |
358 | | |
359 | 80 | if (!*p) |
360 | 0 | break; |
361 | | |
362 | | /* Shortcut to %s and %p, handle %% */ |
363 | 80 | if (*++p == 's') { |
364 | 80 | const char *s = va_arg(args, const char *); |
365 | 80 | wget_buffer_strcat(buf, s ? s : "(null)"); |
366 | 80 | p++; |
367 | 80 | continue; |
368 | 80 | } else if (*p == 'd') { |
369 | 0 | convert_dec_fast(buf, va_arg(args, int)); |
370 | 0 | p++; |
371 | 0 | continue; |
372 | 0 | } else if (*p == 'c') { |
373 | 0 | char c = (char ) va_arg(args, int); |
374 | 0 | wget_buffer_memcat(buf, &c, 1); |
375 | 0 | p++; |
376 | 0 | continue; |
377 | 0 | } else if (*p == 'p') { |
378 | 0 | convert_pointer(buf, va_arg(args, void *)); |
379 | 0 | p++; |
380 | 0 | continue; |
381 | 0 | } else if (*p == '%') { |
382 | 0 | wget_buffer_memset_append(buf, '%', 1); |
383 | 0 | p++; |
384 | 0 | continue; |
385 | 0 | } |
386 | | |
387 | | /* Read the flag chars (optional, simplified) */ |
388 | 0 | p = read_flag_chars(p, &flags); |
389 | | |
390 | | /* |
391 | | * Read field width (optional). |
392 | | * If '*', then the field width is given as an additional argument, |
393 | | * which precedes the argument to be formatted. |
394 | | */ |
395 | 0 | if (*p == '*') { |
396 | 0 | field_width = va_arg(args, int); |
397 | 0 | p = read_field_width(p, &field_width, &flags, 1); |
398 | 0 | } else { |
399 | 0 | p = read_field_width(p, &field_width, &flags, 0); |
400 | 0 | } |
401 | | |
402 | | /* |
403 | | * Read precision (optional). |
404 | | * If '*', the precision is given as an additional argument, |
405 | | * just as the case for the field width. |
406 | | */ |
407 | 0 | if (*p == '.') { |
408 | 0 | if (*++p == '*') { |
409 | 0 | precision = va_arg(args, int); |
410 | 0 | p = read_precision(p, &precision, 1); |
411 | 0 | } else { |
412 | 0 | p = read_precision(p, &precision, 0); |
413 | 0 | } |
414 | 0 | } else |
415 | 0 | precision = -1; |
416 | | |
417 | | /* Read length modifier (optional) */ |
418 | 0 | switch (*p) { |
419 | 0 | case 'z': |
420 | 0 | arg = va_arg(args, ssize_t); |
421 | 0 | argu = (size_t)arg; |
422 | 0 | p++; |
423 | 0 | break; |
424 | | |
425 | 0 | case 'l': |
426 | 0 | if (p[1] == 'l') { |
427 | 0 | p += 2; |
428 | 0 | arg = va_arg(args, long long); |
429 | 0 | argu = (unsigned long long)arg; |
430 | 0 | } else { |
431 | 0 | p++; |
432 | 0 | arg = (long)va_arg(args, long); |
433 | 0 | argu = (unsigned long)arg; |
434 | 0 | } |
435 | 0 | break; |
436 | | |
437 | 0 | case 'L': |
438 | 0 | p++; |
439 | 0 | arg = va_arg(args, long long); |
440 | 0 | argu = (unsigned long long)arg; |
441 | 0 | break; |
442 | | |
443 | 0 | case 'h': |
444 | 0 | if (p[1] == 'h') { |
445 | 0 | p += 2; |
446 | 0 | arg = (signed char) va_arg(args, int); |
447 | 0 | argu = (unsigned char) arg; |
448 | 0 | } else { |
449 | 0 | p++; |
450 | 0 | arg = (short) va_arg(args, int); |
451 | 0 | argu = (unsigned short) arg; |
452 | 0 | } |
453 | 0 | break; |
454 | | |
455 | 0 | case 's': |
456 | 0 | p++; |
457 | 0 | copy_string(buf, flags, field_width, precision, va_arg(args, const char *)); |
458 | 0 | continue; |
459 | | |
460 | 0 | case 'c': |
461 | 0 | { |
462 | 0 | char c[2] = { (char) va_arg(args, int), 0 }; |
463 | 0 | p++; |
464 | 0 | copy_string(buf, flags, field_width, precision, c); |
465 | 0 | continue; |
466 | 0 | } |
467 | | |
468 | 0 | case 'p': // %p shortcut |
469 | 0 | p++; |
470 | 0 | convert_dec(buf, flags | FLAG_HEXLO | FLAG_ALTERNATE, field_width, precision, (long long)(ptrdiff_t)va_arg(args, void *)); |
471 | 0 | continue; |
472 | | |
473 | 0 | default: |
474 | 0 | arg = va_arg(args, int); |
475 | 0 | argu = (unsigned int)arg; |
476 | 0 | } |
477 | | |
478 | 0 | if (*p == 'd' || *p == 'i') { |
479 | 0 | convert_dec(buf, flags | FLAG_SIGNED | FLAG_DECIMAL, field_width, precision, arg); |
480 | 0 | } else if (*p == 'u') { |
481 | 0 | convert_dec(buf, flags | FLAG_DECIMAL, field_width, precision, (long long) argu); |
482 | 0 | } else if (*p == 'x') { |
483 | 0 | convert_dec(buf, flags | FLAG_HEXLO, field_width, precision, (long long) argu); |
484 | 0 | } else if (*p == 'X') { |
485 | 0 | convert_dec(buf, flags | FLAG_HEXUP, field_width, precision, (long long) argu); |
486 | 0 | } else if (*p == 'o') { |
487 | 0 | convert_dec(buf, flags | FLAG_OCTAL, field_width, precision, (long long) argu); |
488 | 0 | } else { |
489 | | /* |
490 | | * This is an unknown conversion specifier, |
491 | | * so just put '%' and move on. |
492 | | */ |
493 | 0 | wget_buffer_memset_append(buf, '%', 1); |
494 | 0 | p = begin + 1; |
495 | 0 | continue; |
496 | 0 | } |
497 | | |
498 | 0 | p++; |
499 | 0 | } |
500 | | |
501 | 80 | return buf->length; |
502 | 80 | } |
503 | | |
504 | | /** |
505 | | * \param[in] buf A buffer, created with wget_buffer_init() or wget_buffer_alloc() |
506 | | * \param[in] fmt A `printf(3)`-like format string |
507 | | * \param[in] args A `va_list` with the format string placeholders' values |
508 | | * \return Length of the buffer after appending the formatted string |
509 | | * |
510 | | * Formats the string \p fmt (with `printf(3)`-like args) and overwrites the contents |
511 | | * of the buffer \p buf with that formatted string. |
512 | | * |
513 | | * This is equivalent to the following code: |
514 | | * |
515 | | * buf->length = 0; |
516 | | * wget_buffer_vprintf_append(buf, fmt, args); |
517 | | * |
518 | | * For more information, see `vprintf(3)`. |
519 | | */ |
520 | | size_t wget_buffer_vprintf(wget_buffer *buf, const char *fmt, va_list args) |
521 | 80 | { |
522 | 80 | buf->length = 0; |
523 | | |
524 | 80 | return wget_buffer_vprintf_append(buf, fmt, args); |
525 | 80 | } |
526 | | |
527 | | /** |
528 | | * \param[in] buf A buffer, created with wget_buffer_init() or wget_buffer_alloc() |
529 | | * \param[in] fmt A `printf(3)`-like format string |
530 | | * \param[in] ... Variable arguments |
531 | | * \return Length of the buffer after appending the formatted string |
532 | | * |
533 | | * Formats the string \p fmt (with `printf(3)`-like args) and appends the result to the end |
534 | | * of the buffer \p buf (using wget_buffer_memcat()). |
535 | | * |
536 | | * This function is equivalent to wget_buffer_vprintf_append(), except in that it uses |
537 | | * a variable number of arguments rather than a `va_list`. |
538 | | * |
539 | | * For more information, see `printf(3)`. |
540 | | */ |
541 | | size_t wget_buffer_printf_append(wget_buffer *buf, const char *fmt, ...) |
542 | 0 | { |
543 | 0 | va_list args; |
544 | |
|
545 | 0 | va_start(args, fmt); |
546 | 0 | wget_buffer_vprintf_append(buf, fmt, args); |
547 | 0 | va_end(args); |
548 | |
|
549 | 0 | return buf->length; |
550 | 0 | } |
551 | | |
552 | | /** |
553 | | * \param[in] buf A buffer, created with wget_buffer_init() or wget_buffer_alloc() |
554 | | * \param[in] fmt A `printf(3)`-like format string |
555 | | * \param[in] ... Variable arguments |
556 | | * \return Length of the buffer after appending the formatted string |
557 | | * |
558 | | * Formats the string \p fmt (with `printf(3)`-like args) and overwrites the contents |
559 | | * of the buffer \p buf with that formatted string. |
560 | | * |
561 | | * This function is equivalent to wget_buffer_vprintf(), except in that it uses |
562 | | * a variable number of arguments rather than a `va_list`. |
563 | | * |
564 | | * For more information, see `printf(3)`. |
565 | | */ |
566 | | size_t wget_buffer_printf(wget_buffer *buf, const char *fmt, ...) |
567 | 0 | { |
568 | 0 | va_list args; |
569 | |
|
570 | 0 | va_start(args, fmt); |
571 | 0 | size_t len = wget_buffer_vprintf(buf, fmt, args); |
572 | 0 | va_end(args); |
573 | |
|
574 | 0 | return len; |
575 | 0 | } |
576 | | /** @} */ |