diff --git a/src/xpdev/xpprintf.c b/src/xpdev/xpprintf.c
index 2a7db4133c2c341fbea70caccb482769f9115762..2c66bba7d29d1997162f8729d865e97677216a71 100644
--- a/src/xpdev/xpprintf.c
+++ b/src/xpdev/xpprintf.c
@@ -15,6 +15,217 @@
 /* Maximum length of a format specifier including the % */
 #define MAX_FORMAT_LEN	256
 
+static int xp_printf_get_type(const char *format)
+{
+	const char	*p;
+	int		modifier=0;
+	int		j;
+	int		correct_type;
+
+	if(!*(size_t *)format)
+		return(0);
+	p=format+*(size_t *)format;
+	if(*p!='%')
+		return(0);
+	p++;
+
+	/*
+	 * Skip flags (zero or more)
+	 */
+	j=1;
+	while(j) {
+		switch(*p) {
+			case '#':
+				p++;
+				break;
+			case '-':
+				p++;
+				break;
+			case '+':
+				p++;
+				break;
+			case ' ':
+				p++;
+				break;
+			case '0':
+				p++;
+				break;
+			case '\'':
+				p++;
+				break;
+			default:
+				j=0;
+				break;
+		}
+	}
+	if(*p=='*')
+		return(XP_PRINTF_TYPE_INT);
+	while(*p>= '0' && *p <= '9')
+		p++;
+	if(*p=='.') {
+		p++;
+		if(*p=='*')
+			return(XP_PRINTF_TYPE_INT);
+	}
+	while(*p>= '0' && *p <= '9')
+		p++;
+	switch(*p) {
+		case 'h':
+			modifier='h';
+			p++;
+			if(*p=='h') {
+				p++;
+				modifier+='h'<<8;
+			}
+			break;
+		case 'l':
+			modifier='h';
+			p++;
+			if(*p=='l') {
+				p++;
+				modifier+='l'<<8;
+			}
+			break;
+		case 'j':
+			modifier='j';
+			p++;
+			break;
+		case 't':
+			modifier='t';
+			p++;
+			break;
+		case 'z':
+			modifier='z';
+			p++;
+			break;
+		case 'L':
+			modifier='L';
+			p++;
+			break;
+	}
+	/*
+	 * The next char is now the type... if type is auto, 
+	 * set type to what it SHOULD be
+	 */
+	switch(*p) {
+		/* INT types */
+		case 'd':
+		case 'i':
+			switch(modifier) {
+				case 'h'|'h'<<8:
+					correct_type=XP_PRINTF_TYPE_SCHAR;
+					break;
+				case 'h':
+					correct_type=XP_PRINTF_TYPE_SHORT;
+					break;
+				case 'l':
+					correct_type=XP_PRINTF_TYPE_LONG;
+					break;
+				case 'l'|'l'<<8:
+					correct_type=XP_PRINTF_TYPE_LONGLONG;
+					break;
+				case 'j':
+					correct_type=XP_PRINTF_TYPE_INTMAX;
+					break;
+				case 't':
+					correct_type=XP_PRINTF_TYPE_PTRDIFF;
+					break;
+				case 'z':
+					/*
+					 * ToDo this is a signed type of same size
+					 * as size_t
+					 */
+					correct_type=XP_PRINTF_TYPE_LONG;
+					break;
+				default:
+					correct_type=XP_PRINTF_TYPE_INT;
+					break;
+			}
+			break;
+		case 'o':
+		case 'u':
+		case 'x':
+		case 'X':
+			switch(modifier) {
+				case 'h'|'h'<<8:
+					correct_type=XP_PRINTF_TYPE_UCHAR;
+					break;
+				case 'h':
+					correct_type=XP_PRINTF_TYPE_USHORT;
+					break;
+				case 'l':
+					correct_type=XP_PRINTF_TYPE_ULONG;
+					break;
+				case 'l'|'l'<<8:
+					correct_type=XP_PRINTF_TYPE_ULONGLONG;
+					break;
+				case 'j':
+					correct_type=XP_PRINTF_TYPE_UINTMAX;
+					break;
+				case 't':
+					/*
+					 * ToDo this is an unsigned type of same size
+					 * as ptrdiff_t
+					 */
+					correct_type=XP_PRINTF_TYPE_ULONG;
+					break;
+				case 'z':
+					correct_type=XP_PRINTF_TYPE_SIZET;
+					break;
+				default:
+					correct_type=XP_PRINTF_TYPE_UINT;
+					break;
+			}
+			break;
+		case 'a':
+		case 'A':
+		case 'e':
+		case 'E':
+		case 'f':
+		case 'F':
+		case 'g':
+		case 'G':
+			switch(modifier) {
+				case 'L':
+					correct_type=XP_PRINTF_TYPE_LONGDOUBLE;
+					break;
+				case 'l':
+				default:
+					correct_type=XP_PRINTF_TYPE_DOUBLE;
+					break;
+			}
+			break;
+		case 'C':
+			/* ToDo wide chars... not yet supported */
+			correct_type=XP_PRINTF_TYPE_CHAR;
+			break;
+		case 'c':
+			switch(modifier) {
+				case 'l':
+					/* ToDo wide chars... not yet supported */
+				default:
+					correct_type=XP_PRINTF_TYPE_CHAR;
+			}
+			break;
+		case 'S':
+			/* ToDo wide chars... not yet supported */
+			correct_type=XP_PRINTF_TYPE_CHARP;
+			break;
+		case 's':
+			switch(modifier) {
+				case 'l':
+					/* ToDo wide chars... not yet supported */
+				default:
+					correct_type=XP_PRINTF_TYPE_CHARP;
+			}
+			break;
+		case 'p':
+			correct_type=XP_PRINTF_TYPE_VOIDP;
+			break;
+	}
+	return(correct_type);
+}
+
 /*
  * Performs the next replacement in format using the variable
  * specified as the only vararg which is currently the type
@@ -44,6 +255,7 @@ char *xp_asprintf_next(char *format, int type, ...)
 	void*			pntr;
 	size_t			s;
 	unsigned long	offset=0;
+	unsigned long	offset2=0;
 	size_t			format_len;
 	size_t			this_format_len;
 	size_t			tail_len;
@@ -60,21 +272,7 @@ char *xp_asprintf_next(char *format, int type, ...)
 	 */
 	if(!*(size_t *) format)
 		return(format);
-	/*
-	 * Find the next non %% format, leaving %% as it is
-	 */
-	for(p=format+*(size_t *)format; *p; p++) {
-		if(*p=='%') {
-			if(*(p+1) == '%')
-				p++;
-			else
-				break;
-		}
-	}
-	if(!*p) {
-		*(size_t *)format=0;
-		return(format);
-	}
+	p=format+*(size_t *)format;
 	offset=p-format;
 	format_len=strlen(format+sizeof(size_t))+sizeof(size_t);
 	this_format[0]=0;
@@ -113,24 +311,24 @@ char *xp_asprintf_next(char *format, int type, ...)
 	}
 
 	/*
-	 * If width is '*' then the argument is an unsigned int
+	 * If width is '*' then the argument is an int
 	 * which specifies the width.
 	 */
 	if(*p=='*') {		/* The argument is this width */
 		va_start(vars, type);
-		i=sprintf(entry_buf,"%u", va_arg(vars, int));
+		i=sprintf(entry_buf,"%d", va_arg(vars, int));
 		va_end(vars);
 		if(i > 1) {
 			/*
 			 * We must calculate this before we go mucking about
 			 * with format and p
 			 */
-			offset=p-format;
+			offset2=p-format;
 			newbuf=(char *)realloc(format, format_len+i /* -1 for the '*' that's already there, +1 for the terminator */);
 			if(newbuf==NULL)
 				return(NULL);
 			format=newbuf;
-			p=format+offset;
+			p=format+offset2;
 			/*
 			 * Move trailing end to make space... leaving the * where it
 			 * is so it can be overwritten
@@ -151,24 +349,24 @@ char *xp_asprintf_next(char *format, int type, ...)
 	if(*p=='.') {
 		*(fmt++)=*(p++);
 		/*
-		 * If the precision is '*' then the argument is an unsigned int which
+		 * If the precision is '*' then the argument is an int which
 		 * specifies the precision.
 		 */
 		if(*p=='*') {
 			va_start(vars, type);
-			i=sprintf(entry_buf,"%u", va_arg(vars, int));
+			i=sprintf(entry_buf,"%d", va_arg(vars, int));
 			va_end(vars);
 			if(i > 1) {
 				/*
 				 * We must calculate this before we go mucking about
 				 * with format and p
 				 */
-				offset=p-format;
+				offset2=p-format;
 				newbuf=(char *)realloc(format, format_len+i /* -1 for the '*' that's already there, +1 for the terminator */);
 				if(newbuf==NULL)
 					return(NULL);
 				format=newbuf;
-				p=format+offset;
+				p=format+offset2;
 				/*
 				 * Move trailing end to make space... leaving the * where it
 				 * is so it can be overwritten
@@ -903,17 +1101,32 @@ char *xp_asprintf_next(char *format, int type, ...)
 	return(format);
 }
 
-char *xp_asprintf_start(char *format)
+char *xp_asprintf_start(const char *format)
 {
+	char	*ret;
 	char	*p;
 
-	p=(char *)malloc(strlen(format)+1+(sizeof(size_t)));
-	if(p==NULL)
+	ret=(char *)malloc(strlen(format)+1+(sizeof(size_t)));
+	if(ret==NULL)
 		return(NULL);
 	/* Place current offset at the start of the buffer */
-	*(int *)p=sizeof(size_t);
-	strcpy(p+sizeof(size_t),format);
-	return(p);
+	strcpy(ret+sizeof(size_t),format);
+	/*
+	 * Find the next non %% format, leaving %% as it is
+	 */
+	for(p=ret+sizeof(size_t); *p; p++) {
+		if(*p=='%') {
+			if(*(p+1) == '%')
+				p++;
+			else
+				break;
+		}
+	}
+	if(!*p)
+		*(size_t *)ret=0;
+	else
+		*(size_t *)ret=p-ret;
+	return(ret);
 }
 
 char *xp_asprintf_end(char *format)
@@ -930,6 +1143,92 @@ char *xp_asprintf_end(char *format)
 	return(format);
 }
 
+char *xp_vasprintf(const char *format, va_list va)
+{
+	char	*working;
+	char	*next;
+	int		type;
+	int				i,j;
+	unsigned int	ui;
+	long int		l;
+	unsigned long int	ul;
+	long long int	ll;
+	unsigned long long int	ull;
+	double			d;
+	long double		ld;
+	char*			cp;
+	void*			pntr;
+	size_t			s;
+
+	next=xp_asprintf_start(format);
+	if(next==NULL)
+		return(NULL);
+	working=next;
+	while(*(size_t *)working) {
+		type=xp_printf_get_type(working);
+		switch(type) {
+			case 0:
+				free(working);
+				return(NULL);
+			case XP_PRINTF_TYPE_INT:	/* Also includes char and short */
+				next=xp_asprintf_next(working, type, va_arg(va, int));
+				break;
+			case XP_PRINTF_TYPE_UINT:	/* Also includes char and short */
+				next=xp_asprintf_next(working, type, va_arg(va, unsigned int));
+				break;
+			case XP_PRINTF_TYPE_LONG:
+				next=xp_asprintf_next(working, type, va_arg(va, long));
+				break;
+			case XP_PRINTF_TYPE_ULONG:
+				next=xp_asprintf_next(working, type, va_arg(va, unsigned long));
+				break;
+			case XP_PRINTF_TYPE_LONGLONG:
+				next=xp_asprintf_next(working, type, va_arg(va, long long));
+				break;
+			case XP_PRINTF_TYPE_ULONGLONG:
+				next=xp_asprintf_next(working, type, va_arg(va, unsigned long long));
+				break;
+			case XP_PRINTF_TYPE_CHARP:
+				next=xp_asprintf_next(working, type, va_arg(va, char *));
+				break;
+			case XP_PRINTF_TYPE_DOUBLE:
+				next=xp_asprintf_next(working, type, va_arg(va, double));
+				break;
+			case XP_PRINTF_TYPE_LONGDOUBLE:
+				next=xp_asprintf_next(working, type, va_arg(va, long double));
+				break;
+			case XP_PRINTF_TYPE_VOIDP:
+				next=xp_asprintf_next(working, type, va_arg(va, void *));
+				break;
+			case XP_PRINTF_TYPE_SIZET:
+				next=xp_asprintf_next(working, type, va_arg(va, size_t));
+				break;
+		}
+		if(next==NULL) {
+			free(working);
+			return(NULL);
+		}
+		working=next;
+	}
+	next=xp_asprintf_end(working);
+	if(next==NULL) {
+		free(working);
+		return(NULL);
+	}
+	return(next);
+}
+
+char *xp_asprintf(const char *format, ...)
+{
+	char	*ret;
+	va_list	va;
+
+	va_start(va, format);
+	ret=xp_vasprintf(format, va);
+	va_end(va);
+	return(ret);
+}
+
 int main(int argc, char *argv[])
 {
 	char	*format;
@@ -942,6 +1241,9 @@ int main(int argc, char *argv[])
 	float f;
 	long double D;
 
+	p=xp_asprintf("%%%%%*.*f %% %%%ss %cs %*.*lu",3,3,123.123456789,"%llutesting%",32,3,3,123);
+	printf("%s\n",p);
+	free(p);
 	if(argc < 2)
 		return(1);
 
diff --git a/src/xpdev/xpprintf.h b/src/xpdev/xpprintf.h
index 19bf2cc08238e24b51868103ff6c40b8e16c8c94..f177816f27e99bb39ac7e4532dc8126cc072f32f 100644
--- a/src/xpdev/xpprintf.h
+++ b/src/xpdev/xpprintf.h
@@ -1,6 +1,8 @@
 #ifndef _XPPRINTF_H_
 #define _XPPRINTF_H_
 
+#include <stdarg.h>
+
 /* Supported printf argument types */
 #define XP_PRINTF_TYPE_AUTO			0
 #define XP_PRINTF_TYPE_INT			1
@@ -29,9 +31,11 @@
 #if defined(__cplusplus)
 extern "C" {
 #endif
-char *xp_asprintf_start(char *format);
+char *xp_asprintf_start(const char *format);
 char *xp_asprintf_next(char *format, int type, ...);
 char *xp_asprintf_end(char *format);
+char *xp_asprintf(const char *format, ...);
+char *xp_vasprintf(const char *format, va_list va);
 #if defined(__cplusplus)
 }
 #endif