2003-09-14 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / vasprintf.c
index dbef4eb..0159867 100644 (file)
@@ -26,12 +26,30 @@ Boston, MA 02111-1307, USA.  */
 #include <stdlib.h>
 #include <stdarg.h>
 
+
+#ifndef va_copy /* accroding to POSIX, va_copy is a macro */
+#if defined (__GNUC__) && defined (__PPC__) \
+     && (defined (_CALL_SYSV) || defined (_WIN32))
+#define va_copy(d, s) (*(d) = *(s))
+#elif defined (MUST_COPY_VA_BYVAL)
+#define va_copy(d, s) ((d) = (s))
+#else 
+#define va_copy(d, s) memcpy ((d), (s), sizeof (va_list))
+#endif 
+#endif 
+
+
 #ifdef TEST
 int global_total_width;
 #endif
 
-int
-vasprintf (char **result, const char *format, va_list *args)
+static int int_vasprintf (char **, const char *, va_list *);
+
+static int
+int_vasprintf (result, format, args)
+     char **result;
+     const char *format;
+     va_list *args;
 {
   const char *p = format;
   /* Add one to make sure that it is never zero, which might cause malloc
@@ -39,8 +57,7 @@ vasprintf (char **result, const char *format, va_list *args)
   int total_width = strlen (format) + 1;
   va_list ap;
 
-  /* FIXME: use va_copy() */
-  memcpy (&ap, args, sizeof (va_list));
+  va_copy (ap, *args);
 
   while (*p != '\0')
     {
@@ -54,7 +71,7 @@ vasprintf (char **result, const char *format, va_list *args)
              total_width += abs (va_arg (ap, int));
            }
          else
-           total_width += strtoul (p, (char**)&p, 10);
+           total_width += strtoul (p, (char **) &p, 10);
          if (*p == '.')
            {
              ++p;
@@ -64,7 +81,7 @@ vasprintf (char **result, const char *format, va_list *args)
                  total_width += abs (va_arg (ap, int));
                }
              else
-             total_width += strtoul (p, (char**)&p, 10);
+             total_width += strtoul (p, (char **) &p, 10);
            }
          while (strchr ("hlL", *p))
            ++p;
@@ -92,13 +109,20 @@ vasprintf (char **result, const char *format, va_list *args)
              total_width += 307;
              break;
            case 's':
-             total_width += strlen (va_arg (ap, char *));
+              {
+                char *tmp = va_arg (ap, char *);
+                if (tmp)
+                  total_width += strlen (tmp);
+                else /* in case the vsprintf does prints a text */
+                  total_width += 25; /* e.g. "(null pointer reference)" */
+              }
              break;
            case 'p':
            case 'n':
              (void) va_arg (ap, char *);
              break;
            }
+         p++;
        }
     }
 #ifdef TEST
@@ -111,6 +135,19 @@ vasprintf (char **result, const char *format, va_list *args)
     return 0;
 }
 
+int
+vasprintf (result, format, args)
+     char **result;
+     const char *format;
+#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
+     _BSD_VA_LIST_ args;
+#else
+     va_list args;
+#endif
+{
+  return int_vasprintf (result, format, &args);
+}
+
 
 int
 asprintf (char **buf, const char *fmt, ...)