- (djm) [configure.ac openbsd-compat/Makefile.in openbsd-compat/bsd-asprintf.c
   openbsd-compat/bsd-snprintf.c openbsd-compat/openbsd-compat.h] Add an
   asprintf() implementation, after syncing our {v,}snprintf() implementation
   with some extra fixes from Samba's version. With help and debugging from
   dtucker and tim; ok dtucker@
diff --git a/ChangeLog b/ChangeLog
index 1164b77..c869db7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,11 @@
 20051122
+ - (djm) [configure.ac openbsd-compat/Makefile.in openbsd-compat/bsd-asprintf.c 
+   openbsd-compat/bsd-snprintf.c openbsd-compat/openbsd-compat.h] Add an 
+   asprintf() implementation, after syncing our {v,}snprintf() implementation
+   with some extra fixes from Samba's version. With help and debugging from 
+   dtucker and tim; ok dtucker@
+
+20051122
  - (dtucker) OpenBSD CVS Sync
    - deraadt@cvs.openbsd.org 2005/11/12 18:37:59
      [ssh-add.c]
@@ -3333,4 +3340,4 @@
    - (djm) Trim deprecated options from INSTALL. Mention UsePAM
    - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
 
-$Id: ChangeLog,v 1.4002 2005/11/22 08:55:13 dtucker Exp $
+$Id: ChangeLog,v 1.4003 2005/11/24 08:58:19 djm Exp $
diff --git a/configure.ac b/configure.ac
index 2885a69..3965528 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-# $Id: configure.ac,v 1.307 2005/11/12 07:42:37 dtucker Exp $
+# $Id: configure.ac,v 1.308 2005/11/24 08:58:20 djm Exp $
 #
 # Copyright (c) 1999-2004 Damien Miller
 #
@@ -426,6 +426,7 @@
 	;;
 # UnixWare 1.x, UnixWare 2.x, and others based on code from Univel.
 *-*-sysv4.2*)
+	CFLAGS="$CFLAGS -Dva_list=_VA_LIST"
 	AC_DEFINE(USE_PIPES)
 	AC_DEFINE(SETEUID_BREAKS_SETUID)
 	AC_DEFINE(BROKEN_SETREUID)
@@ -1106,6 +1107,7 @@
 dnl    Checks for library functions. Please keep in alphabetical order
 AC_CHECK_FUNCS( \
 	arc4random \
+	asprintf \
 	b64_ntop \
 	__b64_ntop \
 	b64_pton \
@@ -1181,6 +1183,7 @@
 	truncate \
 	unsetenv \
 	updwtmpx \
+	vasprintf \
 	vhangup \
 	vsnprintf \
 	waitpid \
@@ -1299,6 +1302,40 @@
 	)
 fi
 
+# If we don't have a working asprintf, then we strongly depend on vsnprintf
+# returning the right thing on overflow: the number of characters it tried to
+# create (as per SUSv3)
+if test "x$ac_cv_func_asprintf" != "xyes" && \
+   test "x$ac_cv_func_vsnprintf" = "xyes" ; then
+	AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow])
+	AC_RUN_IFELSE(
+		[AC_LANG_SOURCE([[
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+int x_snprintf(char *str,size_t count,const char *fmt,...)
+{
+	size_t ret; va_list ap;
+	va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap);
+	return ret;
+}
+int main(void)
+{
+	char x[1];
+	exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1);
+} ]])],
+		[AC_MSG_RESULT(yes)],
+		[
+			AC_MSG_RESULT(no)
+			AC_DEFINE(BROKEN_SNPRINTF, 1,
+				[Define if your snprintf is busted])
+			AC_MSG_WARN([****** Your vsnprintf() function is broken, complain to your vendor])
+		],
+		[ AC_MSG_WARN([cross compiling: Assuming working vsnprintf()]) ]
+	)
+fi
+
 # Check for missing getpeereid (or equiv) support
 NO_PEERCHECK=""
 if test "x$ac_cv_func_getpeereid" != "xyes" ; then
@@ -1978,7 +2015,10 @@
   LIBS="$LIBS -liberty";
 fi
 
-# Checks for data types
+# Check for  long long datatypes
+AC_CHECK_TYPES([long long, unsigned long long, long double])
+
+# Check datatype sizes
 AC_CHECK_SIZEOF(char, 1)
 AC_CHECK_SIZEOF(short int, 2)
 AC_CHECK_SIZEOF(int, 4)
@@ -2669,6 +2709,32 @@
 	AC_DEFINE(HAVE___func__, 1, [Define if compiler implements __func__])
 fi
 
+AC_CACHE_CHECK([whether va_copy exists], ac_cv_have_va_copy, [
+	AC_TRY_LINK(
+		[#include <stdarg.h>
+		 va_list x,y;],
+	    	[va_copy(x,y);],
+		[ ac_cv_have_va_copy="yes" ],
+		[ ac_cv_have_va_copy="no" ]
+	)
+])
+if test "x$ac_cv_have_va_copy" = "xyes" ; then
+	AC_DEFINE(HAVE_VA_COPY, 1, [Define if va_copy exists])
+fi
+
+AC_CACHE_CHECK([whether __va_copy exists], ac_cv_have___va_copy, [
+	AC_TRY_LINK(
+		[#include <stdarg.h>
+		 va_list x,y;],
+	    	[__va_copy(x,y);],
+		[ ac_cv_have___va_copy="yes" ],
+		[ ac_cv_have___va_copy="no" ]
+	)
+])
+if test "x$ac_cv_have___va_copy" = "xyes" ; then
+	AC_DEFINE(HAVE___VA_COPY, 1, [Define if __va_copy exists])
+fi
+
 AC_CACHE_CHECK([whether getopt has optreset support],
 		ac_cv_have_getopt_optreset, [
 	AC_TRY_LINK(
diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in
index 6f5ee28..89ac6cd 100644
--- a/openbsd-compat/Makefile.in
+++ b/openbsd-compat/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.35 2005/08/26 20:15:20 tim Exp $
+# $Id: Makefile.in,v 1.36 2005/11/24 08:58:21 djm Exp $
 
 sysconfdir=@sysconfdir@
 piddir=@piddir@
@@ -18,7 +18,7 @@
 
 OPENBSD=base64.o basename.o bindresvport.o daemon.o dirname.o getcwd.o getgrouplist.o getopt.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sigact.o strlcat.o strlcpy.o strmode.o strsep.o strtonum.o strtoll.o strtoul.o vis.o
 
-COMPAT=bsd-arc4random.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-snprintf.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-snprintf.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
 
 PORTS=port-irix.o port-aix.o port-uw.o
 
diff --git a/openbsd-compat/bsd-asprintf.c b/openbsd-compat/bsd-asprintf.c
new file mode 100644
index 0000000..5ca01f8
--- /dev/null
+++ b/openbsd-compat/bsd-asprintf.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2004 Darren Tucker.
+ *
+ * Based originally on asprintf.c from OpenBSD:
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_VASPRINTF
+
+#ifndef VA_COPY
+# ifdef HAVE_VA_COPY
+#  define VA_COPY(dest, src) va_copy(dest, src)
+# else
+#  ifdef HAVE___VA_COPY
+#   define VA_COPY(dest, src) __va_copy(dest, src)
+#  else
+#   define VA_COPY(dest, src) (dest) = (src)
+#  endif
+# endif
+#endif
+
+#define INIT_SZ	128
+
+int vasprintf(char **str, const char *fmt, va_list ap)
+{
+	int ret = -1;
+	va_list ap2;
+	char *string, *newstr;
+	size_t len;
+
+	VA_COPY(ap2, ap);
+	if ((string = malloc(INIT_SZ)) == NULL)
+		goto fail;
+
+	ret = vsnprintf(string, INIT_SZ, fmt, ap2);
+	if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
+		*str = string;
+	} else if (ret == INT_MAX) { /* shouldn't happen */
+		goto fail;
+	} else {	/* bigger than initial, realloc allowing for nul */
+		len = (size_t)ret + 1;
+		if ((newstr = realloc(string, len)) == NULL) {
+			free(string);
+			goto fail;
+		} else {
+			va_end(ap2);
+			VA_COPY(ap2, ap);
+			ret = vsnprintf(newstr, len, fmt, ap2);
+			if (ret >= 0 && (size_t)ret < len) {
+				*str = newstr;
+			} else { /* failed with realloc'ed string, give up */
+				free(newstr);
+				goto fail;
+			}
+		}
+	}
+	va_end(ap2);
+	return (ret);
+
+fail:
+	*str = NULL;
+	errno = ENOMEM;
+	va_end(ap2);
+	return (-1);
+}
+#endif
+
+#ifndef HAVE_ASPRINTF
+int asprintf(char **str, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+	
+	*str = NULL;
+	va_start(ap, fmt);
+	ret = vasprintf(str, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+#endif
diff --git a/openbsd-compat/bsd-snprintf.c b/openbsd-compat/bsd-snprintf.c
index b5a7ef7..ca275ab 100644
--- a/openbsd-compat/bsd-snprintf.c
+++ b/openbsd-compat/bsd-snprintf.c
@@ -45,45 +45,82 @@
  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
  *
- *  Ben Lindstrom <mouring@eviladmin.org> 09/27/00 for OpenSSH
- *    Welcome to the world of %lld and %qd support.  With other
- *    long long support.  This is needed for sftp-server to work
- *    right.
+ *  Andrew Tridgell (tridge@samba.org) Oct 1998
+ *    fixed handling of %.0f
+ *    added test for HAVE_LONG_DOUBLE
  *
- *  Ben Lindstrom <mouring@eviladmin.org> 02/12/01 for OpenSSH
- *    Removed all hint of VARARGS stuff and banished it to the void,
- *    and did a bit of KNF style work to make things a bit more
- *    acceptable.  Consider stealing from mutt or enlightenment.
+ * tridge@samba.org, idra@samba.org, April 2001
+ *    got rid of fcvt code (twas buggy and made testing harder)
+ *    added C99 semantics
+ *
+ * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
+ * actually print args for %g and %e
+ * 
+ * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
+ * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
+ * see any include file that is guaranteed to be here, so I'm defining it
+ * locally.  Fixes AIX and Solaris builds.
+ * 
+ * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
+ * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
+ * functions
+ * 
+ * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
+ * Fix usage of va_list passed as an arg.  Use __va_copy before using it
+ * when it exists.
+ * 
+ * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
+ * Fix incorrect zpadlen handling in fmtfp.
+ * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
+ * few mods to make it easier to compile the tests.
+ * addedd the "Ollie" test to the floating point ones.
+ *
+ * Martin Pool (mbp@samba.org) April 2003
+ *    Remove NO_CONFIG_H so that the test case can be built within a source
+ *    tree with less trouble.
+ *    Remove unnecessary SAFE_FREE() definition.
+ *
+ * Martin Pool (mbp@samba.org) May 2003
+ *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
+ *
+ *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
+ *    if the C library has some snprintf functions already.
  **************************************************************/
 
 #include "includes.h"
 
-RCSID("$Id: bsd-snprintf.c,v 1.9 2004/09/23 11:35:09 dtucker Exp $");
+RCSID("$Id: bsd-snprintf.c,v 1.10 2005/11/24 08:58:21 djm Exp $");
 
 #if defined(BROKEN_SNPRINTF)		/* For those with broken snprintf() */
 # undef HAVE_SNPRINTF
 # undef HAVE_VSNPRINTF
 #endif
 
+#ifndef VA_COPY
+# ifdef HAVE_VA_COPY
+#  define VA_COPY(dest, src) va_copy(dest, src)
+# else
+#  ifdef HAVE___VA_COPY
+#   define VA_COPY(dest, src) __va_copy(dest, src)
+#  else
+#   define VA_COPY(dest, src) (dest) = (src)
+#  endif
+# endif
+#endif
+
 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
 
-static void 
-dopr(char *buffer, size_t maxlen, const char *format, va_list args);
+#ifdef HAVE_LONG_DOUBLE
+# define LDOUBLE long double
+#else
+# define LDOUBLE double
+#endif
 
-static void 
-fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
-    int min, int max);
-
-static void 
-fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
-    int min, int max, int flags);
-
-static void 
-fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
-    int min, int max, int flags);
-
-static void
-dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+#ifdef HAVE_LONG_LONG
+# define LLONG long long
+#else
+# define LLONG long
+#endif
 
 /*
  * dopr(): poor man's version of doprintf
@@ -109,28 +146,49 @@
 #define DP_F_UNSIGNED 	(1 << 6)
 
 /* Conversion Flags */
-#define DP_C_SHORT     1
-#define DP_C_LONG      2
-#define DP_C_LDOUBLE   3
-#define DP_C_LONG_LONG 4
+#define DP_C_SHORT   1
+#define DP_C_LONG    2
+#define DP_C_LDOUBLE 3
+#define DP_C_LLONG   4
 
-#define char_to_int(p) (p - '0')
-#define abs_val(p) (p < 0 ? -p : p)
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+# define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
 
+static size_t dopr(char *buffer, size_t maxlen, const char *format, 
+		   va_list args_in);
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+		    char *value, int flags, int min, int max);
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+		    long value, int base, int min, int max, int flags);
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+		   LDOUBLE fvalue, int min, int max, int flags);
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
 
-static void 
-dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
 {
-	char *strvalue, ch;
-	long value;
-	long double fvalue;
-	int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;
-	size_t currlen = 0;
-  
-	ch = *format++;
+	char ch;
+	LLONG value;
+	LDOUBLE fvalue;
+	char *strvalue;
+	int min;
+	int max;
+	int state;
+	int flags;
+	int cflags;
+	size_t currlen;
+	va_list args;
 
+	VA_COPY(args, args_in);
+	
+	state = DP_S_DEFAULT;
+	currlen = flags = cflags = min = 0;
+	max = -1;
+	ch = *format++;
+	
 	while (state != DP_S_DONE) {
-		if ((ch == '\0') || (currlen >= maxlen)) 
+		if (ch == '\0') 
 			state = DP_S_DONE;
 
 		switch(state) {
@@ -138,7 +196,7 @@
 			if (ch == '%') 
 				state = DP_S_FLAGS;
 			else 
-				dopr_outch(buffer, &currlen, maxlen, ch);
+				dopr_outch (buffer, &currlen, maxlen, ch);
 			ch = *format++;
 			break;
 		case DP_S_FLAGS:
@@ -170,34 +228,37 @@
 			break;
 		case DP_S_MIN:
 			if (isdigit((unsigned char)ch)) {
-				min = 10 * min + char_to_int (ch);
+				min = 10*min + char_to_int (ch);
 				ch = *format++;
 			} else if (ch == '*') {
 				min = va_arg (args, int);
 				ch = *format++;
 				state = DP_S_DOT;
-			} else 
+			} else {
 				state = DP_S_DOT;
+			}
 			break;
 		case DP_S_DOT:
 			if (ch == '.') {
 				state = DP_S_MAX;
 				ch = *format++;
-			} else 
+			} else { 
 				state = DP_S_MOD;
+			}
 			break;
 		case DP_S_MAX:
 			if (isdigit((unsigned char)ch)) {
 				if (max < 0)
 					max = 0;
-				max = 10 * max + char_to_int(ch);
+				max = 10*max + char_to_int (ch);
 				ch = *format++;
 			} else if (ch == '*') {
 				max = va_arg (args, int);
 				ch = *format++;
 				state = DP_S_MOD;
-			} else 
+			} else {
 				state = DP_S_MOD;
+			}
 			break;
 		case DP_S_MOD:
 			switch (ch) {
@@ -208,15 +269,11 @@
 			case 'l':
 				cflags = DP_C_LONG;
 				ch = *format++;
-				if (ch == 'l') {
-					cflags = DP_C_LONG_LONG;
+				if (ch == 'l') {	/* It's a long long */
+					cflags = DP_C_LLONG;
 					ch = *format++;
 				}
 				break;
-			case 'q':
-				cflags = DP_C_LONG_LONG;
-				ch = *format++;
-				break;
 			case 'L':
 				cflags = DP_C_LDOUBLE;
 				ch = *format++;
@@ -231,37 +288,37 @@
 			case 'd':
 			case 'i':
 				if (cflags == DP_C_SHORT) 
-					value = va_arg(args, int);
+					value = va_arg (args, int);
 				else if (cflags == DP_C_LONG)
-					value = va_arg(args, long int);
-				else if (cflags == DP_C_LONG_LONG)
-					value = va_arg (args, long long);
+					value = va_arg (args, long int);
+				else if (cflags == DP_C_LLONG)
+					value = va_arg (args, LLONG);
 				else
 					value = va_arg (args, int);
-				fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
+				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
 				break;
 			case 'o':
 				flags |= DP_F_UNSIGNED;
 				if (cflags == DP_C_SHORT)
-					value = va_arg(args, unsigned int);
+					value = va_arg (args, unsigned int);
 				else if (cflags == DP_C_LONG)
-					value = va_arg(args, unsigned long int);
-				else if (cflags == DP_C_LONG_LONG)
-					value = va_arg(args, unsigned long long);
+					value = (long)va_arg (args, unsigned long int);
+				else if (cflags == DP_C_LLONG)
+					value = (long)va_arg (args, unsigned LLONG);
 				else
-					value = va_arg(args, unsigned int);
-				fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
+					value = (long)va_arg (args, unsigned int);
+				fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
 				break;
 			case 'u':
 				flags |= DP_F_UNSIGNED;
 				if (cflags == DP_C_SHORT)
-					value = va_arg(args, unsigned int);
+					value = va_arg (args, unsigned int);
 				else if (cflags == DP_C_LONG)
-					value = va_arg(args, unsigned long int);
-				else if (cflags == DP_C_LONG_LONG)
-					value = va_arg(args, unsigned long long);
+					value = (long)va_arg (args, unsigned long int);
+				else if (cflags == DP_C_LLONG)
+					value = (LLONG)va_arg (args, unsigned LLONG);
 				else
-					value = va_arg(args, unsigned int);
+					value = (long)va_arg (args, unsigned int);
 				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
 				break;
 			case 'X':
@@ -269,79 +326,86 @@
 			case 'x':
 				flags |= DP_F_UNSIGNED;
 				if (cflags == DP_C_SHORT)
-					value = va_arg(args, unsigned int);
+					value = va_arg (args, unsigned int);
 				else if (cflags == DP_C_LONG)
-					value = va_arg(args, unsigned long int);
-				else if (cflags == DP_C_LONG_LONG)
-					value = va_arg(args, unsigned long long);
+					value = (long)va_arg (args, unsigned long int);
+				else if (cflags == DP_C_LLONG)
+					value = (LLONG)va_arg (args, unsigned LLONG);
 				else
-					value = va_arg(args, unsigned int);
-				fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
+					value = (long)va_arg (args, unsigned int);
+				fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
 				break;
 			case 'f':
 				if (cflags == DP_C_LDOUBLE)
-					fvalue = va_arg(args, long double);
+					fvalue = va_arg (args, LDOUBLE);
 				else
-					fvalue = va_arg(args, double);
+					fvalue = va_arg (args, double);
 				/* um, floating point? */
-				fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
+				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
 				break;
 			case 'E':
 				flags |= DP_F_UP;
 			case 'e':
 				if (cflags == DP_C_LDOUBLE)
-					fvalue = va_arg(args, long double);
+					fvalue = va_arg (args, LDOUBLE);
 				else
-					fvalue = va_arg(args, double);
+					fvalue = va_arg (args, double);
+				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
 				break;
 			case 'G':
 				flags |= DP_F_UP;
 			case 'g':
 				if (cflags == DP_C_LDOUBLE)
-					fvalue = va_arg(args, long double);
+					fvalue = va_arg (args, LDOUBLE);
 				else
-					fvalue = va_arg(args, double);
+					fvalue = va_arg (args, double);
+				fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
 				break;
 			case 'c':
-				dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
+				dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
 				break;
 			case 's':
-				strvalue = va_arg(args, char *);
-				if (max < 0) 
-					max = maxlen; /* ie, no max */
-				fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
+				strvalue = va_arg (args, char *);
+				if (!strvalue) strvalue = "(NULL)";
+				if (max == -1) {
+					max = strlen(strvalue);
+				}
+				if (min > 0 && max >= 0 && min > max) max = min;
+				fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
 				break;
 			case 'p':
-				strvalue = va_arg(args, void *);
-				fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+				strvalue = va_arg (args, void *);
+				fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
 				break;
 			case 'n':
 				if (cflags == DP_C_SHORT) {
 					short int *num;
-					num = va_arg(args, short int *);
+					num = va_arg (args, short int *);
 					*num = currlen;
 				} else if (cflags == DP_C_LONG) {
 					long int *num;
-					num = va_arg(args, long int *);
-					*num = currlen;
-				} else if (cflags == DP_C_LONG_LONG) {
-					long long *num;
-					num = va_arg(args, long long *);
-					*num = currlen;
+					num = va_arg (args, long int *);
+					*num = (long int)currlen;
+				} else if (cflags == DP_C_LLONG) {
+					LLONG *num;
+					num = va_arg (args, LLONG *);
+					*num = (LLONG)currlen;
 				} else {
 					int *num;
-					num = va_arg(args, int *);
+					num = va_arg (args, int *);
 					*num = currlen;
 				}
 				break;
 			case '%':
-				dopr_outch(buffer, &currlen, maxlen, ch);
+				dopr_outch (buffer, &currlen, maxlen, ch);
 				break;
-			case 'w': /* not supported yet, treat as next char */
+			case 'w':
+				/* not supported yet, treat as next char */
 				ch = *format++;
 				break;
-			default: /* Unknown, skip */
-			break;
+			default:
+				/* Unknown, skip */
+				break;
 			}
 			ch = *format++;
 			state = DP_S_DEFAULT;
@@ -350,24 +414,33 @@
 			break;
 		case DP_S_DONE:
 			break;
-		default: /* hmm? */
+		default:
+			/* hmm? */
 			break; /* some picky compilers need this */
 		}
 	}
-	if (currlen < maxlen - 1) 
-		buffer[currlen] = '\0';
-	else 
-		buffer[maxlen - 1] = '\0';
+	if (maxlen != 0) {
+		if (currlen < maxlen - 1) 
+			buffer[currlen] = '\0';
+		else if (maxlen > 0) 
+			buffer[maxlen - 1] = '\0';
+	}
+	
+	return currlen;
 }
 
-static void
-fmtstr(char *buffer, size_t *currlen, size_t maxlen,
-    char *value, int flags, int min, int max)
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+		    char *value, int flags, int min, int max)
 {
-	int cnt = 0, padlen, strln;     /* amount to pad */
-  
-	if (value == 0) 
+	int padlen, strln;     /* amount to pad */
+	int cnt = 0;
+
+#ifdef DEBUG_SNPRINTF
+	printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+	if (value == 0) {
 		value = "<NULL>";
+	}
 
 	for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
 	padlen = min - strln;
@@ -375,18 +448,18 @@
 		padlen = 0;
 	if (flags & DP_F_MINUS) 
 		padlen = -padlen; /* Left Justify */
-
+	
 	while ((padlen > 0) && (cnt < max)) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
+		dopr_outch (buffer, currlen, maxlen, ' ');
 		--padlen;
 		++cnt;
 	}
 	while (*value && (cnt < max)) {
-		dopr_outch(buffer, currlen, maxlen, *value++);
+		dopr_outch (buffer, currlen, maxlen, *value++);
 		++cnt;
 	}
 	while ((padlen < 0) && (cnt < max)) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
+		dopr_outch (buffer, currlen, maxlen, ' ');
 		++padlen;
 		++cnt;
 	}
@@ -394,49 +467,49 @@
 
 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
 
-static void 
-fmtint(char *buffer, size_t *currlen, size_t maxlen,
-    long value, int base, int min, int max, int flags)
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+		    long value, int base, int min, int max, int flags)
 {
+	int signvalue = 0;
 	unsigned long uvalue;
 	char convert[20];
-	int signvalue = 0, place = 0, caps = 0;
+	int place = 0;
 	int spadlen = 0; /* amount to space pad */
 	int zpadlen = 0; /* amount to zero pad */
-  
+	int caps = 0;
+	
 	if (max < 0)
 		max = 0;
-
+	
 	uvalue = value;
-
-	if (!(flags & DP_F_UNSIGNED)) {
-		if (value < 0) {
+	
+	if(!(flags & DP_F_UNSIGNED)) {
+		if( value < 0 ) {
 			signvalue = '-';
 			uvalue = -value;
-		} else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
-			signvalue = '+';
-		else if (flags & DP_F_SPACE)
-			signvalue = ' ';
+		} else {
+			if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+				signvalue = '+';
+			else if (flags & DP_F_SPACE)
+				signvalue = ' ';
+		}
 	}
   
-	if (flags & DP_F_UP) 
-		caps = 1; /* Should characters be upper case? */
+	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
 	do {
 		convert[place++] =
-		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
-		    [uvalue % (unsigned)base];
+			(caps? "0123456789ABCDEF":"0123456789abcdef")
+			[uvalue % (unsigned)base  ];
 		uvalue = (uvalue / (unsigned)base );
-	} while (uvalue && (place < 20));
-	if (place == 20) 
-		place--;
+	} while(uvalue && (place < 20));
+	if (place == 20) place--;
 	convert[place] = 0;
 
 	zpadlen = max - place;
 	spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
-	if (zpadlen < 0)
-		zpadlen = 0;
-	if (spadlen < 0)
-		spadlen = 0;
+	if (zpadlen < 0) zpadlen = 0;
+	if (spadlen < 0) spadlen = 0;
 	if (flags & DP_F_ZERO) {
 		zpadlen = MAX(zpadlen, spadlen);
 		spadlen = 0;
@@ -444,27 +517,32 @@
 	if (flags & DP_F_MINUS) 
 		spadlen = -spadlen; /* Left Justifty */
 
+#ifdef DEBUG_SNPRINTF
+	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+	       zpadlen, spadlen, min, max, place);
+#endif
+
 	/* Spaces */
 	while (spadlen > 0) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
+		dopr_outch (buffer, currlen, maxlen, ' ');
 		--spadlen;
 	}
 
 	/* Sign */
 	if (signvalue) 
-		dopr_outch(buffer, currlen, maxlen, signvalue);
+		dopr_outch (buffer, currlen, maxlen, signvalue);
 
 	/* Zeros */
 	if (zpadlen > 0) {
 		while (zpadlen > 0) {
-			dopr_outch(buffer, currlen, maxlen, '0');
+			dopr_outch (buffer, currlen, maxlen, '0');
 			--zpadlen;
 		}
 	}
 
 	/* Digits */
 	while (place > 0) 
-		dopr_outch(buffer, currlen, maxlen, convert[--place]);
+		dopr_outch (buffer, currlen, maxlen, convert[--place]);
   
 	/* Left Justified spaces */
 	while (spadlen < 0) {
@@ -473,11 +551,20 @@
 	}
 }
 
-static long double 
-pow10(int exp)
+static LDOUBLE abs_val(LDOUBLE value)
 {
-	long double result = 1;
+	LDOUBLE result = value;
 
+	if (value < 0)
+		result = -value;
+	
+	return result;
+}
+
+static LDOUBLE POW10(int exp)
+{
+	LDOUBLE result = 1;
+	
 	while (exp) {
 		result *= 10;
 		exp--;
@@ -486,28 +573,69 @@
 	return result;
 }
 
-static long 
-round(long double value)
+static LLONG ROUND(LDOUBLE value)
 {
-	long intpart = value;
+	LLONG intpart;
 
-	value -= intpart;
-	if (value >= 0.5)
-		intpart++;
-
+	intpart = (LLONG)value;
+	value = value - intpart;
+	if (value >= 0.5) intpart++;
+	
 	return intpart;
 }
 
-static void 
-fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
-      int min, int max, int flags)
+/* a replacement for modf that doesn't need the math library. Should
+   be portable, but slow */
+static double my_modf(double x0, double *iptr)
 {
-	char iconvert[20], fconvert[20];
-	int signvalue = 0, iplace = 0, fplace = 0;
+	int i;
+	long l;
+	double x = x0;
+	double f = 1.0;
+
+	for (i=0;i<100;i++) {
+		l = (long)x;
+		if (l <= (x+1) && l >= (x-1)) break;
+		x *= 0.1;
+		f *= 10.0;
+	}
+
+	if (i == 100) {
+		/* yikes! the number is beyond what we can handle. What do we do? */
+		(*iptr) = 0;
+		return 0;
+	}
+
+	if (i != 0) {
+		double i2;
+		double ret;
+
+		ret = my_modf(x0-l*f, &i2);
+		(*iptr) = l*f + i2;
+		return ret;
+	} 
+
+	(*iptr) = l;
+	return x - (*iptr);
+}
+
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+		   LDOUBLE fvalue, int min, int max, int flags)
+{
+	int signvalue = 0;
+	double ufvalue;
+	char iconvert[311];
+	char fconvert[311];
+	int iplace = 0;
+	int fplace = 0;
 	int padlen = 0; /* amount to pad */
-	int zpadlen = 0, caps = 0;
-	long intpart, fracpart;
-	long double ufvalue;
+	int zpadlen = 0; 
+	int caps = 0;
+	int idx;
+	double intpart;
+	double fracpart;
+	double temp;
   
 	/* 
 	 * AIX manpage says the default is 0, but Solaris says the default
@@ -516,137 +644,159 @@
 	if (max < 0)
 		max = 6;
 
-	ufvalue = abs_val(fvalue);
+	ufvalue = abs_val (fvalue);
 
-	if (fvalue < 0)
+	if (fvalue < 0) {
 		signvalue = '-';
-	else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
-		signvalue = '+';
-	else if (flags & DP_F_SPACE)
-		signvalue = ' ';
+	} else {
+		if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+			signvalue = '+';
+		} else {
+			if (flags & DP_F_SPACE)
+				signvalue = ' ';
+		}
+	}
 
-	intpart = ufvalue;
+#if 0
+	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+	 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
 
 	/* 
-	 * Sorry, we only support 9 digits past the decimal because of our 
+	 * Sorry, we only support 16 digits past the decimal because of our 
 	 * conversion method
 	 */
-	if (max > 9)
-		max = 9;
+	if (max > 16)
+		max = 16;
 
 	/* We "cheat" by converting the fractional part to integer by
 	 * multiplying by a factor of 10
 	 */
-	fracpart = round((pow10 (max)) * (ufvalue - intpart));
 
-	if (fracpart >= pow10 (max)) {
+	temp = ufvalue;
+	my_modf(temp, &intpart);
+
+	fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+	
+	if (fracpart >= POW10(max)) {
 		intpart++;
-		fracpart -= pow10 (max);
+		fracpart -= POW10(max);
 	}
 
 	/* Convert integer part */
 	do {
+		temp = intpart*0.1;
+		my_modf(temp, &intpart);
+		idx = (int) ((temp -intpart +0.05)* 10.0);
+		/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+		/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
 		iconvert[iplace++] =
-		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
-		    [intpart % 10];
-		intpart = (intpart / 10);
-	} while(intpart && (iplace < 20));
-	if (iplace == 20) 
-		iplace--;
+			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+	} while (intpart && (iplace < 311));
+	if (iplace == 311) iplace--;
 	iconvert[iplace] = 0;
 
 	/* Convert fractional part */
-	do {
-		fconvert[fplace++] =
-		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
-		    [fracpart % 10];
-		fracpart = (fracpart / 10);
-	} while(fracpart && (fplace < 20));
-	if (fplace == 20) 
-		fplace--;
+	if (fracpart)
+	{
+		do {
+			temp = fracpart*0.1;
+			my_modf(temp, &fracpart);
+			idx = (int) ((temp -fracpart +0.05)* 10.0);
+			/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
+			/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+			fconvert[fplace++] =
+			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+		} while(fracpart && (fplace < 311));
+		if (fplace == 311) fplace--;
+	}
 	fconvert[fplace] = 0;
-
+  
 	/* -1 for decimal point, another -1 if we are printing a sign */
 	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
 	zpadlen = max - fplace;
-	if (zpadlen < 0)
-		zpadlen = 0;
+	if (zpadlen < 0) zpadlen = 0;
 	if (padlen < 0) 
 		padlen = 0;
 	if (flags & DP_F_MINUS) 
 		padlen = -padlen; /* Left Justifty */
-
+	
 	if ((flags & DP_F_ZERO) && (padlen > 0)) {
 		if (signvalue) {
-			dopr_outch(buffer, currlen, maxlen, signvalue);
+			dopr_outch (buffer, currlen, maxlen, signvalue);
 			--padlen;
 			signvalue = 0;
 		}
 		while (padlen > 0) {
-			dopr_outch(buffer, currlen, maxlen, '0');
+			dopr_outch (buffer, currlen, maxlen, '0');
 			--padlen;
 		}
 	}
 	while (padlen > 0) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
+		dopr_outch (buffer, currlen, maxlen, ' ');
 		--padlen;
 	}
 	if (signvalue) 
-		dopr_outch(buffer, currlen, maxlen, signvalue);
-
+		dopr_outch (buffer, currlen, maxlen, signvalue);
+	
 	while (iplace > 0) 
-		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+		dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+#ifdef DEBUG_SNPRINTF
+	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
 
 	/*
-	 * Decimal point.  This should probably use locale to find the 
-	 * correct char to print out.
+	 * Decimal point.  This should probably use locale to find the correct
+	 * char to print out.
 	 */
-	dopr_outch(buffer, currlen, maxlen, '.');
+	if (max > 0) {
+		dopr_outch (buffer, currlen, maxlen, '.');
+		
+		while (zpadlen > 0) {
+			dopr_outch (buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
 
-	while (fplace > 0) 
-		dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
-
-	while (zpadlen > 0) {
-		dopr_outch(buffer, currlen, maxlen, '0');
-		--zpadlen;
+		while (fplace > 0) 
+			dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
 	}
 
 	while (padlen < 0) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
+		dopr_outch (buffer, currlen, maxlen, ' ');
 		++padlen;
 	}
 }
 
-static void 
-dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
 {
-	if (*currlen < maxlen)
-		buffer[(*currlen)++] = c;
+	if (*currlen < maxlen) {
+		buffer[(*currlen)] = c;
+	}
+	(*currlen)++;
 }
 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
 
-#ifndef HAVE_VSNPRINTF
-int 
-vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+#if !defined(HAVE_VSNPRINTF)
+int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
 {
-	str[0] = 0;
-	dopr(str, count, fmt, args);
-
-	return(strlen(str));
+	return dopr(str, count, fmt, args);
 }
-#endif /* !HAVE_VSNPRINTF */
+#endif
 
-#ifndef HAVE_SNPRINTF
-int 
-snprintf(char *str,size_t count,const char *fmt,...)
+#if !defined(HAVE_SNPRINTF)
+int snprintf(char *str,size_t count,const char *fmt,...)
 {
+	size_t ret;
 	va_list ap;
 
 	va_start(ap, fmt);
-	(void) vsnprintf(str, count, fmt, ap);
+	ret = vsnprintf(str, count, fmt, ap);
 	va_end(ap);
-
-	return(strlen(str));
+	return ret;
 }
+#endif
 
-#endif /* !HAVE_SNPRINTF */
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index dda558f..fe0c36d 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -1,4 +1,4 @@
-/* $Id: openbsd-compat.h,v 1.31 2005/09/29 23:55:50 dtucker Exp $ */
+/* $Id: openbsd-compat.h,v 1.32 2005/11/24 08:58:21 djm Exp $ */
 
 /*
  * Copyright (c) 1999-2003 Damien Miller.  All rights reserved.
@@ -142,6 +142,10 @@
 void arc4random_stir(void);
 #endif /* !HAVE_ARC4RANDOM */
 
+#ifndef HAVE_ASPRINTF
+int asprintf(char **, const char *, ...);
+#endif 
+
 #ifndef HAVE_OPENPTY
 int openpty(int *, int *, char *, struct termios *, struct winsize *);
 #endif /* HAVE_OPENPTY */
@@ -160,6 +164,10 @@
 long long strtonum(const char *, long long, long long, const char **);
 #endif
 
+#ifndef HAVE_VASPRINTF
+int vasprintf(char **, const char *, va_list);
+#endif
+
 #ifndef HAVE_VSNPRINTF
 int vsnprintf(char *, size_t, const char *, va_list);
 #endif