1
0
mirror of https://git.savannah.gnu.org/git/gnulib.git synced 2025-08-08 17:22:05 +03:00

string-buffer: Add more API.

* lib/string-buffer.h: Include string-desc.h.
(sb_append1, sb_append_desc): New declarations.
(sb_append_c): Renamed from sb_append.
(sb_contents, sb_contents_c, sb_dupfree): New declarations.
(sb_dupfree_c): Renamed from sb_dupfree.
* lib/string-buffer.c (sb_append1, sb_append_desc): New functions.
(sb_append_c): Renamed from sb_append.
(sb_contents, sb_contents_c, sb_dupfree): New functions.
(sb_dupfree_c): Renamed from sb_dupfree. Optimize.
* modules/string-buffer (Depends-on): Add string-desc.
* tests/test-string-buffer.c (main): Use sb_append_c instead of
sb_append. Use sb_dupfree_c instead of sb_dupfree. Test also sb_append1,
sb_append_desc, sb_contents.
* NEWS: Mention the changes.
This commit is contained in:
Bruno Haible
2024-09-25 17:19:41 +02:00
parent 2bbbc32f15
commit db23a7eaa3
6 changed files with 204 additions and 30 deletions

View File

@@ -1,3 +1,21 @@
2024-09-25 Bruno Haible <bruno@clisp.org>
string-buffer: Add more API.
* lib/string-buffer.h: Include string-desc.h.
(sb_append1, sb_append_desc): New declarations.
(sb_append_c): Renamed from sb_append.
(sb_contents, sb_contents_c, sb_dupfree): New declarations.
(sb_dupfree_c): Renamed from sb_dupfree.
* lib/string-buffer.c (sb_append1, sb_append_desc): New functions.
(sb_append_c): Renamed from sb_append.
(sb_contents, sb_contents_c, sb_dupfree): New functions.
(sb_dupfree_c): Renamed from sb_dupfree. Optimize.
* modules/string-buffer (Depends-on): Add string-desc.
* tests/test-string-buffer.c (main): Use sb_append_c instead of
sb_append. Use sb_dupfree_c instead of sb_dupfree. Test also sb_append1,
sb_append_desc, sb_contents.
* NEWS: Mention the changes.
2024-09-25 Bruno Haible <bruno@clisp.org>
string-buffer: Enable resource leak warnings from clang.

3
NEWS
View File

@@ -74,6 +74,9 @@ User visible incompatible changes
Date Modules Changes
2024-09-25 string-buffer The function sb_append is renamed to sb_append_c.
The function sb_dupfree is renamed to sb_dupfree_c.
2024-08-14 verror The include file is changed from "verror.h"
to <error.h>.

View File

@@ -87,7 +87,33 @@ sb_ensure_more_bytes (struct string_buffer *buffer, size_t increment)
}
int
sb_append (struct string_buffer *buffer, const char *str)
sb_append1 (struct string_buffer *buffer, char c)
{
if (sb_ensure_more_bytes (buffer, 1) < 0)
{
buffer->error = true;
return -1;
}
buffer->data[buffer->length++] = c;
return 0;
}
int
sb_append_desc (struct string_buffer *buffer, string_desc_t s)
{
size_t len = string_desc_length (s);
if (sb_ensure_more_bytes (buffer, len) < 0)
{
buffer->error = true;
return -1;
}
memcpy (buffer->data + buffer->length, string_desc_data (s), len);
buffer->length += len;
return 0;
}
int
sb_append_c (struct string_buffer *buffer, const char *str)
{
size_t len = strlen (str);
if (sb_ensure_more_bytes (buffer, len) < 0)
@@ -107,10 +133,57 @@ sb_free (struct string_buffer *buffer)
free (buffer->data);
}
/* Returns the contents of BUFFER, and frees all other memory held
by BUFFER. Returns NULL upon failure or if there was an error earlier. */
char *
string_desc_t
sb_contents (struct string_buffer *buffer)
{
return string_desc_new_addr (buffer->length, buffer->data);
}
const char *
sb_contents_c (struct string_buffer *buffer)
{
if (sb_ensure_more_bytes (buffer, 1) < 0)
return NULL;
buffer->data[buffer->length] = '\0';
return buffer->data;
}
string_desc_t
sb_dupfree (struct string_buffer *buffer)
{
if (buffer->error)
goto fail;
size_t length = buffer->length;
if (buffer->data == buffer->space)
{
char *copy = (char *) malloc (length > 0 ? length : 1);
if (copy == NULL)
goto fail;
memcpy (copy, buffer->data, length);
return string_desc_new_addr (length, copy);
}
else
{
/* Shrink the string before returning it. */
char *contents = buffer->data;
if (length < buffer->allocated)
{
contents = realloc (contents, length > 0 ? length : 1);
if (contents == NULL)
goto fail;
}
return string_desc_new_addr (length, contents);
}
fail:
sb_free (buffer);
return string_desc_new_addr (0, NULL);
}
char *
sb_dupfree_c (struct string_buffer *buffer)
{
if (buffer->error)
goto fail;
@@ -120,21 +193,22 @@ sb_dupfree (struct string_buffer *buffer)
buffer->data[buffer->length] = '\0';
buffer->length++;
size_t length = buffer->length;
if (buffer->data == buffer->space)
{
char *copy = (char *) malloc (buffer->length);
char *copy = (char *) malloc (length);
if (copy == NULL)
goto fail;
memcpy (copy, buffer->data, buffer->length);
memcpy (copy, buffer->data, length);
return copy;
}
else
{
/* Shrink the string before returning it. */
char *contents = buffer->data;
if (buffer->length < buffer->allocated)
if (length < buffer->allocated)
{
contents = realloc (contents, buffer->length);
contents = realloc (contents, length);
if (contents == NULL)
goto fail;
}

View File

@@ -29,6 +29,7 @@
#include <stdlib.h>
#include "attribute.h"
#include "string-desc.h"
typedef char * _GL_ATTRIBUTE_CAPABILITY_TYPE ("memory resource")
sb_heap_allocated_pointer_t;
@@ -51,9 +52,17 @@ extern "C" {
extern void sb_init (struct string_buffer *buffer)
_GL_ATTRIBUTE_ACQUIRE_CAPABILITY (buffer->data);
/* Appends the contents of STR to BUFFER.
/* Appends the character C to BUFFER.
Returns 0, or -1 in case of out-of-memory error. */
extern int sb_append (struct string_buffer *buffer, const char *str);
extern int sb_append1 (struct string_buffer *buffer, char c);
/* Appends the contents of the memory area STR to BUFFER.
Returns 0, or -1 in case of out-of-memory error. */
extern int sb_append_desc (struct string_buffer *buffer, string_desc_t s);
/* Appends the contents of the C string STR to BUFFER.
Returns 0, or -1 in case of out-of-memory error. */
extern int sb_append_c (struct string_buffer *buffer, const char *str);
/* Appends the result of the printf-compatible FORMATSTRING with the argument
list LIST to BUFFER.
@@ -77,7 +86,7 @@ extern int sb_appendvf (struct string_buffer *buffer,
Therefore, if the format string is valid and does not use %ls/%lc
directives nor widths, the only possible error code is ENOMEM. */
extern int sb_appendf (struct string_buffer *buffer,
const char *formatstring, ...)
const char *formatstring, ...)
#if (__GNUC__ + (__GNUC_MINOR__ >= 4) > 4) && !defined __clang__
ATTRIBUTE_FORMAT ((__gnu_printf__, 2, 3))
#else
@@ -89,10 +98,29 @@ extern int sb_appendf (struct string_buffer *buffer,
extern void sb_free (struct string_buffer *buffer)
_GL_ATTRIBUTE_RELEASE_CAPABILITY (buffer->data);
/* Returns the contents of BUFFER, and frees all other memory held
by BUFFER. Returns NULL upon failure or if there was an error earlier.
/* Returns a read-only view of the current contents of BUFFER.
The result is only valid until the next operation on BUFFER. */
extern string_desc_t sb_contents (struct string_buffer *buffer);
/* Ensures the contents of BUFFER is followed by a NUL byte (without
incrementing the length of the contents).
Then returns a read-only view of the current contents of BUFFER,
that is, the current contents of BUFFER as a C string.
Returns NULL upon out-of-memory error.
The result is only valid until the next operation on BUFFER. */
extern const char * sb_contents_c (struct string_buffer *buffer);
/* Returns the contents of BUFFER and frees all other memory held by BUFFER.
Returns NULL upon failure or if there was an error earlier.
It is the responsibility of the caller to string_desc_free() the result. */
extern string_desc_t sb_dupfree (struct string_buffer *buffer)
_GL_ATTRIBUTE_RELEASE_CAPABILITY (buffer->data);
/* Returns the contents of BUFFER (with an added trailing NUL, that is,
as a C string), and frees all other memory held by BUFFER.
Returns NULL upon failure or if there was an error earlier.
It is the responsibility of the caller to free() the result. */
extern char * sb_dupfree (struct string_buffer *buffer)
extern char * sb_dupfree_c (struct string_buffer *buffer)
_GL_ATTRIBUTE_RELEASE_CAPABILITY (buffer->data);
#ifdef __cplusplus

View File

@@ -9,6 +9,7 @@ lib/string-buffer-printf.c
Depends-on:
stdbool
attribute
string-desc
stdarg
vsnzprintf-posix

View File

@@ -44,12 +44,50 @@ char invalid_format_string_2[] = "%^";
int
main ()
{
/* Test accumulation. */
{
struct string_buffer buffer;
sb_init (&buffer);
sb_append1 (&buffer, 'x');
sb_append1 (&buffer, '\377');
char *s = sb_dupfree_c (&buffer);
ASSERT (s != NULL && strcmp (s, "x\377") == 0);
free (s);
}
{
struct string_buffer buffer;
sb_init (&buffer);
sb_append1 (&buffer, 'x');
sb_append1 (&buffer, '\377');
{
string_desc_t sd = sb_contents (&buffer);
ASSERT (string_desc_length (sd) == 2);
ASSERT (string_desc_char_at (sd, 0) == 'x');
ASSERT (string_desc_char_at (sd, 1) == '\377');
}
sb_append1 (&buffer, '\0');
sb_append1 (&buffer, 'z');
{
string_desc_t sd = sb_contents (&buffer);
ASSERT (string_desc_length (sd) == 4);
ASSERT (string_desc_char_at (sd, 0) == 'x');
ASSERT (string_desc_char_at (sd, 1) == '\377');
ASSERT (string_desc_char_at (sd, 2) == '\0');
ASSERT (string_desc_char_at (sd, 3) == 'z');
}
char *s = sb_dupfree_c (&buffer);
ASSERT (s != NULL && memcmp (s, "x\377\0z\0", 5) == 0);
free (s);
}
/* Test simple string concatenation. */
{
struct string_buffer buffer;
sb_init (&buffer);
char *s = sb_dupfree (&buffer);
char *s = sb_dupfree_c (&buffer);
ASSERT (s != NULL && strcmp (s, "") == 0);
free (s);
}
@@ -58,23 +96,35 @@ main ()
struct string_buffer buffer;
sb_init (&buffer);
sb_append (&buffer, "abc");
sb_append (&buffer, "");
sb_append (&buffer, "defg");
char *s = sb_dupfree (&buffer);
sb_append_c (&buffer, "abc");
sb_append_c (&buffer, "");
sb_append_c (&buffer, "defg");
char *s = sb_dupfree_c (&buffer);
ASSERT (s != NULL && strcmp (s, "abcdefg") == 0);
free (s);
}
{
struct string_buffer buffer;
sb_init (&buffer);
sb_append_c (&buffer, "abc");
sb_append_desc (&buffer, string_desc_new_addr (5, "de\0fg"));
sb_append_c (&buffer, "hij");
char *s = sb_dupfree_c (&buffer);
ASSERT (s != NULL && memcmp (s, "abcde\0fghij", 12) == 0);
free (s);
}
/* Test printf-like formatting. */
{
struct string_buffer buffer;
sb_init (&buffer);
sb_append (&buffer, "<");
sb_append_c (&buffer, "<");
sb_appendf (&buffer, "%x", 3735928559U);
sb_append (&buffer, ">");
char *s = sb_dupfree (&buffer);
sb_append_c (&buffer, ">");
char *s = sb_dupfree_c (&buffer);
ASSERT (s != NULL && strcmp (s, "<deadbeef>") == 0);
free (s);
}
@@ -84,10 +134,10 @@ main ()
struct string_buffer buffer;
sb_init (&buffer);
sb_append (&buffer, "<");
sb_append_c (&buffer, "<");
my_appendf (&buffer, "%x", 3735928559U);
sb_append (&buffer, ">");
char *s = sb_dupfree (&buffer);
sb_append_c (&buffer, ">");
char *s = sb_dupfree_c (&buffer);
ASSERT (s != NULL && strcmp (s, "<deadbeef>") == 0);
free (s);
}
@@ -102,7 +152,7 @@ main ()
int ret;
sb_init (&buffer);
sb_append (&buffer, "<");
sb_append_c (&buffer, "<");
ret = sb_appendf (&buffer, "%lc", (wint_t) 0x76543210);
#if !defined _AIX
@@ -110,20 +160,20 @@ main ()
ASSERT (errno == EILSEQ);
#endif
sb_append (&buffer, "|");
sb_append_c (&buffer, "|");
ret = sb_appendf (&buffer, invalid_format_string_1, 1);
ASSERT (ret < 0);
ASSERT (errno == EINVAL);
sb_append (&buffer, "|");
sb_append_c (&buffer, "|");
ret = sb_appendf (&buffer, invalid_format_string_2, 2);
ASSERT (ret < 0);
ASSERT (errno == EINVAL);
sb_append (&buffer, ">");
char *s = sb_dupfree (&buffer);
sb_append_c (&buffer, ">");
char *s = sb_dupfree_c (&buffer);
ASSERT (s == NULL);
}