* lib/acl.h: Include sys/types.h and sys/stat.h, for mode_t and
[gnulib.git] / lib / snprintf.c
index 92c2652..db1ca9a 100644 (file)
@@ -1,6 +1,6 @@
 /* Formatted output to strings.
-   Copyright (C) 2004 Free Software Foundation, Inc.
-   Written by Simon Josefsson.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+   Written by Simon Josefsson and Paul Eggert.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
 
-/* Specification.  */
 #include "snprintf.h"
 
-/* Get va_list, va_start, va_end. */
+#include <errno.h>
+#include <limits.h>
 #include <stdarg.h>
-/* Get free. */
 #include <stdlib.h>
-/* Get memcpy, size_t. */
 #include <string.h>
 
-/* Get vasnprintf.  */
 #include "vasnprintf.h"
 
-/* Get MIN. */
-#include "minmax.h"
+/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
+#ifndef EOVERFLOW
+# define EOVERFLOW E2BIG
+#endif
 
 /* Print formatted output to string STR.  Similar to sprintf, but
    additional length SIZE limit how much is written into STR.  Returns
@@ -46,22 +43,34 @@ snprintf (char *str, size_t size, const char *format, ...)
 {
   char *output;
   size_t len;
+  size_t lenbuf = size;
   va_list args;
 
   va_start (args, format);
-  output = vasnprintf (NULL, &len, format, args);
+  output = vasnprintf (str, &lenbuf, format, args);
+  len = lenbuf;
   va_end (args);
 
   if (!output)
     return -1;
 
-  if (str)
+  if (output != str)
     {
-      memcpy (str, output, MIN (len + 1, size));
-      str[size - 1] = '\0';
+      if (size)
+       {
+         size_t pruned_len = (len < size ? len : size - 1);
+         memcpy (str, output, pruned_len);
+         str[pruned_len] = '\0';
+       }
+
+      free (output);
     }
 
-  free (output);
+  if (INT_MAX < len)
+    {
+      errno = EOVERFLOW;
+      return -1;
+    }
 
   return len;
 }