]> git.tue.mpg.de Git - paraslash.git/commitdiff
Replace PARA_VSNPRINTF by xvasprintf().
authorAndre Noll <maan@systemlinux.org>
Fri, 6 Jan 2012 03:15:34 +0000 (04:15 +0100)
committerAndre Noll <maan@systemlinux.org>
Fri, 20 Jan 2012 21:57:07 +0000 (22:57 +0100)
The PARA_VSNPRINTF macro is rather clumsy, and too large to be inlined.
Moreover, it does not return the length of the formated string, so
users have to call strlen() after the call to PARA_VSNPRINTF(). This
is extra work which can easily be avoided since the number of bytes
written is returned by the underlying call to vsnprintf().

This patch replaces the macro by the public function xvasprintf(),
which is similar to the non-standard vasprintf() on GNU systems. It
also adds xasprintf(), a similar variant which takes a variable number
of arguments.

Unlike PARA_VSNPRINTF, xasprintf() and xvasprintf() return the number
of bytes written. This relies on vsnprintf() conforming to the C99
standard and breaks in particular on glibc 2.0 systems. Since glibc
2.0 is about 15 years old, this is unlikely to cause problems on
real systems.

All users which called strlen() right after xvasprintf() are changed
to use the return value of xvasprintf() instead.

crypt_common.c
fd.c
gcc-compat.h
gui.c
para.h
string.c
string.h

index 4e9622e4ee773d65c708bbf3f0b624592ed0e27b..5ad4d43d883b498989412182a54e880aa3ba0766 100644 (file)
@@ -350,9 +350,12 @@ __printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc,
 {
        char *msg;
        int ret;
+       va_list ap;
 
-       PARA_VSPRINTF(fmt, msg);
-       ret = sc_send_buffer(scc, msg);
+       va_start(ap, fmt);
+       ret = xvasprintf(&msg, fmt, ap);
+       va_end(ap);
+       ret = sc_send_bin_buffer(scc, msg, ret);
        free(msg);
        return ret;
 }
diff --git a/fd.c b/fd.c
index d2f93611de1e66ad9bbcd8dcd5aada40546f560f..a04232f84b3fd239249c866cb5a109551ad2b926 100644 (file)
--- a/fd.c
+++ b/fd.c
@@ -142,9 +142,11 @@ __printf_2_3 int write_va_buffer(int fd, const char *fmt, ...)
 {
        char *msg;
        int ret;
+       va_list ap;
 
-       PARA_VSPRINTF(fmt, msg);
-       ret = write_buffer(fd, msg);
+       va_start(ap, fmt);
+       ret = xvasprintf(&msg, fmt, ap);
+       ret = write_all(fd, msg, ret);
        free(msg);
        return ret;
 }
index ba1d82ead77ac6ae937a15a4e691ba8afc2f21b2..5d207288359f5b9151c6ca55ab54d00b4669b533 100644 (file)
@@ -5,15 +5,18 @@
 #define __a_aligned(alignment) __attribute__((__aligned__(alignment)))
 
 /*
- * p is the number of the "format string" parameter, and q is
- * the number of the first variadic parameter.
+ * p is the number of the "format string" parameter, and q is the number of the
+ * first variadic parameter. If q is specified as zero, the compiler only
+ * checks the format string for consistency.
  */
 # define __printf(p,q) __attribute__ ((format (printf, p, q)))
 # define __a_const __attribute__ ((const))
+
 /*
- * as direct use of __printf(p,q) confuses doxygen, here are two extra macros
- * for those values p,q that are actually used by paraslash.
+ * As direct use of __printf(p,q) confuses doxygen, here are some extra macros
+ * for those values p,q that are actually used.
  */
+#define  __printf_2_0 __printf(2,0)
 #define  __printf_1_2 __printf(1,2)
 #define  __printf_2_3 __printf(2,3)
 
diff --git a/gui.c b/gui.c
index b7823f0d96697131d79df38de17bcfe6599ea3d4..0316e3653eecf8e0507a5615e42124178c2f9b87 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -336,11 +336,14 @@ static int align_str(WINDOW* win, char *str, unsigned int len,
 __printf_2_3 static void print_in_bar(int color, const char *fmt,...)
 {
        char *msg;
+       va_list ap;
 
        if (!curses_active)
                return;
        wattron(in.win, COLOR_PAIR(color));
-       PARA_VSPRINTF(fmt, msg);
+       va_start(ap, fmt);
+       xvasprintf(&msg, fmt, ap);
+       va_end(ap);
        wmove(in.win, 0, 0);
        align_str(in.win, msg, sb.cols, LEFT);
        free(msg);
@@ -471,10 +474,13 @@ static void rb_add_entry(int color, char *msg)
 __printf_2_3 static void outputf(int color, const char* fmt,...)
 {
        char *msg;
+       va_list ap;
 
        if (!curses_active)
                return;
-       PARA_VSPRINTF(fmt, msg);
+       va_start(ap, fmt);
+       xvasprintf(&msg, fmt, ap);
+       va_end(ap);
        rb_add_entry(color, msg);
        wrefresh(bot.win);
 }
@@ -493,6 +499,7 @@ __printf_2_3 void curses_log(int ll, const char *fmt,...)
 {
        int color;
        char *msg;
+       va_list ap;
 
        if (ll < loglevel || !curses_active)
                return;
@@ -505,7 +512,9 @@ __printf_2_3 void curses_log(int ll, const char *fmt,...)
                default:
                        color = COLOR_ERRMSG;
        }
-       PARA_VSPRINTF(fmt, msg);
+       va_start(ap, fmt);
+       xvasprintf(&msg, fmt, ap);
+       va_end(ap);
        chop(msg);
        rb_add_entry(color, msg);
        wrefresh(bot.win);
diff --git a/para.h b/para.h
index 25cbd16ac663a30d15121c15bf3e287a97211c09..3b9559e1beb93062c7cd7cb1cd0daace402b85ae 100644 (file)
--- a/para.h
+++ b/para.h
@@ -113,38 +113,9 @@ extern const char *status_item_list[];
 int for_each_stat_item(char *item_buf, size_t num_bytes,
        int (*item_handler)(int, char *));
 
-/**
- * Write a log message to a dynamically allocated string.
- *
- * \param fmt Usual format string.
- * \param p Result pointer.
- *
- * \sa printf(3). */
-#define PARA_VSPRINTF(fmt, p) \
-{ \
-       int n; \
-       size_t size = 100; \
-       p = para_malloc(size); \
-       while (1) { \
-               va_list ap; \
-               /* Try to print in the allocated space. */ \
-               va_start(ap, fmt); \
-               n = vsnprintf(p, size, fmt, ap); \
-               va_end(ap); \
-               /* If that worked, return the string. */ \
-               if (n > -1 && n < size) \
-                       break; \
-               /* Else try again with more space. */ \
-               if (n > -1) /* glibc 2.1 */ \
-                       size = n + 1; /* precisely what is needed */ \
-               else /* glibc 2.0 */ \
-                       size *= 2; /* twice the old size */ \
-               p = para_realloc(p, size); \
-       } \
-}
 
 /**
- *  Return a random non-negative integer in an interval.
+ * Return a random non-negative integer in an interval.
  *
  * \param max Determines maximal possible return value.
  *
index 8c8c50ac6ef30e51ec86751837e44e0e2a4ef95f..a1f2a43c65756dc6ce066a5b6707c91b94f4c7d4 100644 (file)
--- a/string.c
+++ b/string.c
@@ -114,6 +114,64 @@ __must_check __malloc char *para_strdup(const char *s)
        exit(EXIT_FAILURE);
 }
 
+/**
+ * Print a formated message to a dynamically allocated string.
+ *
+ * \param result The formated string is returned here.
+ * \param fmt The format string.
+ * \param ap Initialized list of arguments.
+ *
+ * This function is similar to vasprintf(), a GNU extension which is not in C
+ * or POSIX. It allocates a string large enough to hold the output including
+ * the terminating null byte. The allocated string is returned via the first
+ * argument and must be freed by the caller. However, unlike vasprintf(), this
+ * function calls exit() if insufficient memory is available, while vasprintf()
+ * returns -1 in this case.
+ *
+ * \return Number of bytes written, not including the terminating '\0'.
+ *
+ * \sa printf(3), vsnprintf(3), va_start(3), vasprintf(3), \ref xasprintf().
+ */
+__printf_2_0 unsigned xvasprintf(char **result, const char *fmt, va_list ap)
+{
+       int ret;
+       size_t size;
+       va_list aq;
+
+       va_copy(aq, ap);
+       ret = vsnprintf(NULL, 0, fmt, aq);
+       va_end(aq);
+       assert(ret >= 0);
+       size = ret + 1;
+       *result = para_malloc(size);
+       va_copy(aq, ap);
+       ret = vsnprintf(*result, size, fmt, aq);
+       va_end(aq);
+       assert(ret >= 0 && ret < size);
+       return ret;
+}
+
+/**
+ * Print to a dynamically allocated string, variable number of arguments.
+ *
+ * \param result See \ref xvasprintf().
+ * \param fmt Usual format string.
+ *
+ * \return The return value of the underlying call to \ref xvasprintf().
+ *
+ * \sa \ref xvasprintf() and the references mentioned there.
+ */
+__printf_2_3 unsigned xasprintf(char **result, const char *fmt, ...)
+{
+       va_list ap;
+       unsigned ret;
+
+       va_start(ap, fmt);
+       ret = xvasprintf(result, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+
 /**
  * Allocate a sufficiently large string and print into it.
  *
@@ -125,13 +183,16 @@ __must_check __malloc char *para_strdup(const char *s)
  * \return This function either returns a pointer to a string that must be
  * freed by the caller or aborts without returning.
  *
- * \sa printf(3).
+ * \sa printf(3), xasprintf().
  */
 __must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...)
 {
        char *msg;
+       va_list ap;
 
-       PARA_VSPRINTF(fmt, msg);
+       va_start(ap, fmt);
+       xvasprintf(&msg, fmt, ap);
+       va_end(ap);
        return msg;
 }
 
index e5a4f9dbb4ae90b9196d6671b342879f976a5ac2..cdc55d2da64cef1da942543608602b0a6592af2e 100644 (file)
--- a/string.h
+++ b/string.h
@@ -60,6 +60,9 @@ __must_check __malloc void *para_realloc(void *p, size_t size);
 __must_check __malloc void *para_malloc(size_t size);
 __must_check __malloc void *para_calloc(size_t size);
 __must_check __malloc char *para_strdup(const char *s);
+
+__printf_2_0 unsigned xvasprintf(char **result, const char *fmt, va_list ap);
+__printf_2_3 unsigned xasprintf(char **result, const char *fmt, ...);
 __must_check __malloc __printf_1_2 char *make_message(const char *fmt, ...);
 __must_check __malloc char *para_strcat(char *a, const char *b);
 __must_check __malloc char *para_dirname(const char *name);