Some uses of the 'string-buffer' module don't need the *printf implementation. In order to eliminate it from linking, when linking statically, this patch splits up the module into two compilation units.
(The alternative would be a separate module 'string-buffer-printf', but that leads to an excessive number of modules, IMO.) 2024-09-24 Bruno Haible <br...@clisp.org> string-buffer: Link to vasnprintf implementation only when needed. * lib/string-buffer-printf.c: New file, extracted from lib/string-buffer.c. * lib/string-buffer.c: Don't include <stdarg.h>. (sb_ensure_more_bytes): Declare. Make non-static. (sb_appendvf, sb_appendf): Moved to lib/string-buffer-printf.c. * modules/string-buffer (Files): Add lib/string-buffer-printf.c. (Makefile.am): Arrange to compile string-buffer-printf.c. diff --git a/lib/string-buffer-printf.c b/lib/string-buffer-printf.c new file mode 100644 index 0000000000..16ef4e4144 --- /dev/null +++ b/lib/string-buffer-printf.c @@ -0,0 +1,189 @@ +/* A buffer that accumulates a string by piecewise concatenation. + Copyright (C) 2021-2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <br...@clisp.org>, 2021. */ + +#include <config.h> + +/* Specification. */ +#include "string-buffer.h" + +/* Undocumented. */ +extern int sb_ensure_more_bytes (struct string_buffer *buffer, + size_t increment); + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +int +sb_appendvf (struct string_buffer *buffer, const char *formatstring, + va_list list) +{ + va_list list_copy; + + /* Make a bit of room, so that the probability that the first vsnprintf() call + succeeds is high. */ + size_t room = buffer->allocated - buffer->length; + if (room < 64) + { + if (sb_ensure_more_bytes (buffer, 64) < 0) + { + buffer->error = true; + return -1; + } + room = buffer->allocated - buffer->length; + } + + va_copy (list_copy, list); + + /* First vsnprintf() call. */ + int ret = vsnprintf (buffer->data + buffer->length, room, formatstring, list); + if (ret < 0) + { + /* Failed. */ + buffer->error = true; + ret = -1; + } + else + { + if ((size_t) ret <= room) + { + /* The result has fit into room bytes. */ + buffer->length += (size_t) ret; + ret = 0; + } + else + { + /* The result was truncated. Make more room, for a second vsnprintf() + call. */ + if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0) + { + buffer->error = true; + ret = -1; + } + else + { + /* Second vsnprintf() call. */ + room = buffer->allocated - buffer->length; + ret = vsnprintf (buffer->data + buffer->length, room, + formatstring, list_copy); + if (ret < 0) + { + /* Failed. */ + buffer->error = true; + ret = -1; + } + else + { + if ((size_t) ret <= room) + { + /* The result has fit into room bytes. */ + buffer->length += (size_t) ret; + ret = 0; + } + else + /* The return values of the vsnprintf() calls are not + consistent. */ + abort (); + } + } + } + } + + va_end (list_copy); + return ret; +} + +int +sb_appendf (struct string_buffer *buffer, const char *formatstring, ...) +{ + va_list args; + + /* Make a bit of room, so that the probability that the first vsnprintf() call + succeeds is high. */ + size_t room = buffer->allocated - buffer->length; + if (room < 64) + { + if (sb_ensure_more_bytes (buffer, 64) < 0) + { + buffer->error = true; + return -1; + } + room = buffer->allocated - buffer->length; + } + + va_start (args, formatstring); + + /* First vsnprintf() call. */ + int ret = vsnprintf (buffer->data + buffer->length, room, formatstring, args); + if (ret < 0) + { + /* Failed. */ + buffer->error = true; + ret = -1; + } + else + { + if ((size_t) ret <= room) + { + /* The result has fit into room bytes. */ + buffer->length += (size_t) ret; + ret = 0; + } + else + { + /* The result was truncated. Make more room, for a second vsnprintf() + call. */ + if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0) + { + buffer->error = true; + ret = -1; + } + else + { + /* Second vsnprintf() call. */ + room = buffer->allocated - buffer->length; + va_end (args); + va_start (args, formatstring); + ret = vsnprintf (buffer->data + buffer->length, room, + formatstring, args); + if (ret < 0) + { + /* Failed. */ + buffer->error = true; + ret = -1; + } + else + { + if ((size_t) ret <= room) + { + /* The result has fit into room bytes. */ + buffer->length += (size_t) ret; + ret = 0; + } + else + /* The return values of the vsnprintf() calls are not + consistent. */ + abort (); + } + } + } + } + + va_end (args); + return ret; +} diff --git a/lib/string-buffer.c b/lib/string-buffer.c index 6ea589d67d..221cd9191e 100644 --- a/lib/string-buffer.c +++ b/lib/string-buffer.c @@ -21,7 +21,10 @@ /* Specification. */ #include "string-buffer.h" -#include <stdarg.h> +/* Undocumented. */ +extern int sb_ensure_more_bytes (struct string_buffer *buffer, + size_t increment); + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -38,7 +41,7 @@ sb_init (struct string_buffer *buffer) /* Ensures that INCREMENT bytes are available beyond the current used length of BUFFER. Returns 0, or -1 in case of out-of-memory error. */ -static int +int sb_ensure_more_bytes (struct string_buffer *buffer, size_t increment) { size_t incremented_length = buffer->length + increment; @@ -91,165 +94,6 @@ sb_append (struct string_buffer *buffer, const char *str) return 0; } -int -sb_appendvf (struct string_buffer *buffer, const char *formatstring, - va_list list) -{ - va_list list_copy; - - /* Make a bit of room, so that the probability that the first vsnprintf() call - succeeds is high. */ - size_t room = buffer->allocated - buffer->length; - if (room < 64) - { - if (sb_ensure_more_bytes (buffer, 64) < 0) - { - buffer->error = true; - return -1; - } - room = buffer->allocated - buffer->length; - } - - va_copy (list_copy, list); - - /* First vsnprintf() call. */ - int ret = vsnprintf (buffer->data + buffer->length, room, formatstring, list); - if (ret < 0) - { - /* Failed. */ - buffer->error = true; - ret = -1; - } - else - { - if ((size_t) ret <= room) - { - /* The result has fit into room bytes. */ - buffer->length += (size_t) ret; - ret = 0; - } - else - { - /* The result was truncated. Make more room, for a second vsnprintf() - call. */ - if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0) - { - buffer->error = true; - ret = -1; - } - else - { - /* Second vsnprintf() call. */ - room = buffer->allocated - buffer->length; - ret = vsnprintf (buffer->data + buffer->length, room, - formatstring, list_copy); - if (ret < 0) - { - /* Failed. */ - buffer->error = true; - ret = -1; - } - else - { - if ((size_t) ret <= room) - { - /* The result has fit into room bytes. */ - buffer->length += (size_t) ret; - ret = 0; - } - else - /* The return values of the vsnprintf() calls are not - consistent. */ - abort (); - } - } - } - } - - va_end (list_copy); - return ret; -} - -int -sb_appendf (struct string_buffer *buffer, const char *formatstring, ...) -{ - va_list args; - - /* Make a bit of room, so that the probability that the first vsnprintf() call - succeeds is high. */ - size_t room = buffer->allocated - buffer->length; - if (room < 64) - { - if (sb_ensure_more_bytes (buffer, 64) < 0) - { - buffer->error = true; - return -1; - } - room = buffer->allocated - buffer->length; - } - - va_start (args, formatstring); - - /* First vsnprintf() call. */ - int ret = vsnprintf (buffer->data + buffer->length, room, formatstring, args); - if (ret < 0) - { - /* Failed. */ - buffer->error = true; - ret = -1; - } - else - { - if ((size_t) ret <= room) - { - /* The result has fit into room bytes. */ - buffer->length += (size_t) ret; - ret = 0; - } - else - { - /* The result was truncated. Make more room, for a second vsnprintf() - call. */ - if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0) - { - buffer->error = true; - ret = -1; - } - else - { - /* Second vsnprintf() call. */ - room = buffer->allocated - buffer->length; - va_end (args); - va_start (args, formatstring); - ret = vsnprintf (buffer->data + buffer->length, room, - formatstring, args); - if (ret < 0) - { - /* Failed. */ - buffer->error = true; - ret = -1; - } - else - { - if ((size_t) ret <= room) - { - /* The result has fit into room bytes. */ - buffer->length += (size_t) ret; - ret = 0; - } - else - /* The return values of the vsnprintf() calls are not - consistent. */ - abort (); - } - } - } - } - - va_end (args); - return ret; -} - void sb_free (struct string_buffer *buffer) { diff --git a/modules/string-buffer b/modules/string-buffer index 54da1db988..76c07d94ac 100644 --- a/modules/string-buffer +++ b/modules/string-buffer @@ -4,6 +4,7 @@ A buffer that accumulates a string by piecewise concatenation. Files: lib/string-buffer.h lib/string-buffer.c +lib/string-buffer-printf.c Depends-on: stdbool @@ -14,7 +15,7 @@ vsnprintf-posix configure.ac: Makefile.am: -lib_SOURCES += string-buffer.c +lib_SOURCES += string-buffer.c string-buffer-printf.c Include: "string-buffer.h"