gettext: Sync with gettext 0.23.
[gnulib.git] / lib / string-buffer-printf.c
blob6e5ce78b353b76071bc7424ce36a92f6fe5e008a
1 /* A buffer that accumulates a string by piecewise concatenation.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation, either version 3 of the
7 License, or (at your option) any later version.
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2021. */
19 #include <config.h>
21 /* Specification. */
22 #include "string-buffer.h"
24 /* Undocumented. */
25 extern int sb_ensure_more_bytes (struct string_buffer *buffer,
26 size_t increment);
28 #include <errno.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
33 int
34 sb_appendvf (struct string_buffer *buffer, const char *formatstring,
35 va_list list)
37 va_list list_copy;
39 /* Make a bit of room, so that the probability that the first vsnzprintf()
40 call succeeds is high. */
41 size_t room = buffer->allocated - buffer->length;
42 if (room < 64)
44 if (sb_ensure_more_bytes (buffer, 64) < 0)
46 buffer->error = true;
47 errno = ENOMEM;
48 return -1;
50 room = buffer->allocated - buffer->length;
53 va_copy (list_copy, list);
55 /* First vsnzprintf() call. */
56 ptrdiff_t ret = vsnzprintf (buffer->data + buffer->length, room,
57 formatstring, list);
58 if (ret < 0)
60 /* Failed. errno is set. */
61 buffer->error = true;
62 ret = -1;
64 else
66 if (ret <= room)
68 /* The result has fit into room bytes. */
69 buffer->length += (size_t) ret;
70 ret = 0;
72 else
74 /* The result was truncated. Make more room, for a second
75 vsnzprintf() call. */
76 if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0)
78 buffer->error = true;
79 errno = ENOMEM;
80 ret = -1;
82 else
84 /* Second vsnzprintf() call. */
85 room = buffer->allocated - buffer->length;
86 ret = vsnzprintf (buffer->data + buffer->length, room,
87 formatstring, list_copy);
88 if (ret < 0)
90 /* Failed. errno is set. */
91 buffer->error = true;
92 ret = -1;
94 else
96 if (ret <= room)
98 /* The result has fit into room bytes. */
99 buffer->length += (size_t) ret;
100 ret = 0;
102 else
103 /* The return values of the vsnzprintf() calls are not
104 consistent. */
105 abort ();
111 va_end (list_copy);
112 return ret;
116 sb_appendf (struct string_buffer *buffer, const char *formatstring, ...)
118 va_list args;
120 /* Make a bit of room, so that the probability that the first vsnzprintf()
121 call succeeds is high. */
122 size_t room = buffer->allocated - buffer->length;
123 if (room < 64)
125 if (sb_ensure_more_bytes (buffer, 64) < 0)
127 buffer->error = true;
128 errno = ENOMEM;
129 return -1;
131 room = buffer->allocated - buffer->length;
134 va_start (args, formatstring);
136 /* First vsnzprintf() call. */
137 ptrdiff_t ret = vsnzprintf (buffer->data + buffer->length, room,
138 formatstring, args);
139 if (ret < 0)
141 /* Failed. errno is set. */
142 buffer->error = true;
143 ret = -1;
145 else
147 if (ret <= room)
149 /* The result has fit into room bytes. */
150 buffer->length += (size_t) ret;
151 ret = 0;
153 else
155 /* The result was truncated. Make more room, for a second
156 vsnzprintf() call. */
157 if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0)
159 buffer->error = true;
160 errno = ENOMEM;
161 ret = -1;
163 else
165 /* Second vsnzprintf() call. */
166 room = buffer->allocated - buffer->length;
167 va_end (args);
168 va_start (args, formatstring);
169 ret = vsnzprintf (buffer->data + buffer->length, room,
170 formatstring, args);
171 if (ret < 0)
173 /* Failed. errno is set. */
174 buffer->error = true;
175 ret = -1;
177 else
179 if (ret <= room)
181 /* The result has fit into room bytes. */
182 buffer->length += (size_t) ret;
183 ret = 0;
185 else
186 /* The return values of the vsnzprintf() calls are not
187 consistent. */
188 abort ();
194 va_end (args);
195 return ret;