Hi!

I've been wondering why there are ways to append to a strbuf but no way to 
create one from scratch providing a format string and arguments. Actually, 
I've found a few places where a strbuf is created (with its default size) and 
then appended to, possibly causing a reallocation. I think the code overhead 
of doing it in two steps and the runtime overhead for the reallocation are 
unnecessary. They are even dangerous in out-of-memory situations if not done 
correctly.

Please have a look at the attached patch. It provides two new functions, 
eina_strbuf_new_printf() and eina_strbuf_new_vprintf(). I'm aware that the 
implementation is far from ideal, since it doesn't avoid the useless double 
allocation. Also, the version for wide character strings is missing. Still, I 
wanted to ask if there is any interest in such an eina extension and whether 
the interface is acceptable.

Cheers!

Uli
Index: src/tests/eina_test_strbuf.c
===================================================================
--- src/tests/eina_test_strbuf.c	(revision 63441)
+++ src/tests/eina_test_strbuf.c	(working copy)
@@ -375,7 +375,7 @@
    eina_init();
 
    buf = eina_strbuf_new();
-        fail_if(!buf);
+   fail_if(!buf);
 
    for (i = 0; i < runs; i++)
      {
@@ -428,12 +428,35 @@
    for (i = 0; i < runs; i++, str += target_pattern_size)
         fail_if(memcmp(str, target_pattern, target_pattern_size));
 
-        eina_strbuf_free(buf);
+   eina_strbuf_free(buf);
 
    eina_shutdown();
 }
 END_TEST
 
+START_TEST(strbuf_new_printf)
+{
+   Eina_Strbuf *buf;
+
+   eina_init();
+
+   // simple case, nothing to format, just copy the string
+   buf = eina_strbuf_new_printf("abc");
+   fail_if(!buf);
+   fail_if(strcmp(eina_strbuf_string_get(buf), "abc"));
+   eina_strbuf_free(buf);
+
+   // format an int and a string
+   buf = eina_strbuf_new_printf("abc(%d)%s", 20, "xyz");
+   fail_if(!buf);
+   fail_if(strcmp(eina_strbuf_string_get(buf), "abc(20)xyz"));
+   eina_strbuf_free(buf);
+
+   eina_shutdown();
+}
+END_TEST
+
+
 void
 eina_test_strbuf(TCase *tc)
 {
@@ -446,4 +469,5 @@
    tcase_add_test(tc, strbuf_append_realloc);
    tcase_add_test(tc, strbuf_prepend_realloc);
    tcase_add_test(tc, strbuf_manage_simple);
+   tcase_add_test(tc, strbuf_new_printf);
 }
Index: src/include/eina_strbuf.h
===================================================================
--- src/include/eina_strbuf.h	(revision 63441)
+++ src/include/eina_strbuf.h	(working copy)
@@ -80,6 +80,43 @@
 EAPI Eina_Strbuf *eina_strbuf_new(void) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
 
 /**
+ * @brief Create a new string buffer
+ *
+ * @param fmt The format string.
+ * @return Newly allocated string buffer instance.
+ *
+ * This function creates a new string buffer and formats it according to the
+ * format specifier given in printf() format. On error, @c NULL is returned
+ * and Eina error is set to #EINA_ERROR_OUT_OF_MEMORY. To free the resources,
+ * use eina_strbuf_free().
+ *
+ * @see eina_strbuf_free()
+ * @see eina_strbuf_new()
+ * @see eina_strbuf_new_vprintf()
+ * @since 1.1
+ */
+EAPI Eina_Strbuf *eina_strbuf_new_printf(char const* fmt, ...) EINA_PRINTF(1, 2);
+
+/**
+ * @brief Create a new string buffer
+ *
+ * @param fmt The format string.
+ * @param args The variable arguments.
+ * @return Newly allocated string buffer instance.
+ *
+ * This function creates a new string buffer and formats it according to the
+ * format specifier given in printf() format. On error, @c NULL is returned
+ * and Eina error is set to #EINA_ERROR_OUT_OF_MEMORY. To free the resources,
+ * use eina_strbuf_free().
+ *
+ * @see eina_strbuf_free()
+ * @see eina_strbuf_new()
+ * @see eina_strbuf_new_vprintf()
+ * @since 1.1
+ */
+EAPI Eina_Strbuf *eina_strbuf_new_vprintf(char const* fmt, va_list args);
+
+/**
  * @brief Create a new string buffer using the passed string. The passed
  * string is used directly as the buffer, it's somehow the opposite function of
  * @ref eina_strbuf_string_steal . The passed string must be malloced.
Index: src/lib/eina_strbuf.c
===================================================================
--- src/lib/eina_strbuf.c	(revision 63441)
+++ src/lib/eina_strbuf.c	(working copy)
@@ -81,6 +81,38 @@
  *============================================================================*/
 
 
+EAPI Eina_Strbuf*
+eina_strbuf_new_printf(const char *fmt, ...)
+{
+   va_list args;
+   Eina_Strbuf *buf;
+
+   va_start(args, fmt);
+   buf = eina_strbuf_new_vprintf(fmt, args);
+   va_end(args);
+
+   return buf;
+}
+
+EAPI Eina_Strbuf*
+eina_strbuf_new_vprintf(const char *fmt, va_list args)
+{
+   Eina_Strbuf *buf;
+
+   /* TODO: Instead of default-allocating a stringbuffer here, we could
+   use vasprintf() and then create the stringbuffer with the exact size
+   that we need. */
+   buf = eina_strbuf_new();
+   if (buf == NULL)
+      return NULL;
+
+   if (eina_strbuf_append_vprintf(buf, fmt, args))
+      return buf;
+
+   eina_strbuf_free(buf);
+   return NULL;
+}
+
 EAPI Eina_Bool
 eina_strbuf_append_printf(Eina_Strbuf *buf, const char *fmt, ...)
 {
------------------------------------------------------------------------------
BlackBerry&reg; DevCon Americas, Oct. 18-20, San Francisco, CA
http://p.sf.net/sfu/rim-devcon-copy2
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to