blob: a901ee815520b3e6573c87ef802082b8bf6d5f28 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
2 *
3 * GNU Library General Public License (LGPL) version 2 or later.
4 *
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
6 */
7
8#include <features.h>
9
10#ifdef __USE_GNU
11#include "_stdio.h"
12#include <stdarg.h>
13#include <bits/uClibc_va_copy.h>
14
15
16#ifdef __UCLIBC_MJN3_ONLY__
17/* Do the memstream stuff inline to avoid fclose and the openlist? */
18#warning CONSIDER: avoid open_memstream call?
19#endif
20
21#ifndef __STDIO_HAS_VSNPRINTF
22#warning Skipping vasprintf since no vsnprintf!
23#else
24
25int vasprintf(char **__restrict buf, const char * __restrict format,
26 va_list arg)
27{
28#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
29
30 FILE *f;
31 size_t size;
32 int rv = -1;
33
34 *buf = NULL;
35
36 if ((f = open_memstream(buf, &size)) != NULL) {
37 rv = vfprintf(f, format, arg);
38 fclose(f);
39 if (rv < 0) {
40 free(*buf);
41 *buf = NULL;
42 }
43 }
44
45 assert(rv >= -1);
46
47 return rv;
48
49#else /* __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */
50
51 /* This implementation actually calls the printf machinery twice, but
52 * only does one malloc. This can be a problem though when custom printf
53 * specs or the %m specifier are involved because the results of the
54 * second call might be different from the first. */
55 va_list arg2;
56 int rv;
57
58 va_copy(arg2, arg);
59 rv = vsnprintf(NULL, 0, format, arg2);
60 va_end(arg2);
61
62 *buf = NULL;
63
64 if (rv >= 0) {
65 if ((*buf = malloc(++rv)) != NULL) {
66 if ((rv = vsnprintf(*buf, rv, format, arg)) < 0) {
67 free(*buf);
68 *buf = NULL;
69 }
70 }
71 }
72
73 assert(rv >= -1);
74
75 return rv;
76
77#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */
78}
79libc_hidden_def(vasprintf)
80
81#endif
82#endif