]> Savannah Git Hosting - gnulib.git/commitdiff
string-buffer: Add more API.
authorBruno Haible <bruno@clisp.org>
Wed, 25 Sep 2024 15:19:41 +0000 (17:19 +0200)
committerBruno Haible <bruno@clisp.org>
Wed, 25 Sep 2024 15:19:41 +0000 (17:19 +0200)
* 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.

ChangeLog
NEWS
lib/string-buffer.c
lib/string-buffer.h
modules/string-buffer
tests/test-string-buffer.c

index c001b2899aa6a678a9a2ead96c9dea6852d8cea8..48f6e5e501a801ba37a039e43675f99324509398 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/NEWS b/NEWS
index 40a8da647a32f6dcdf731050998482560853f63d..c3710825dd058eaf879d8a1bc5e1f4678094195e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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>.
 
index ed34e6b78b314adb66f0dfe5950eca7fe81a6ac1..b3759aa3958af98e55c6ddd9d285e6e4d52a006a 100644 (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;
         }
index 5476197d523aed876bb1721ffe885ebab25457a8..02ba90abfba83b75bed649f73505ed51dec34636 100644 (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
index 2010641b2b3d37a7a80c0a22b5f3a44514fe286e..21d3fdcf5be8b8248ce43b2cd23f1827a4663399 100644 (file)
@@ -9,6 +9,7 @@ lib/string-buffer-printf.c
 Depends-on:
 stdbool
 attribute
+string-desc
 stdarg
 vsnzprintf-posix
 
index d492837b39a124e3c36bc07fe76c98b81750c281..580263b6564cad4a4de5469fcdb9d32c5aae3099 100644 (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);
   }