/*
 * vasprintf.c  -  Print into a malloc'd buffer using variadic args
 *
 * Copyright (C) 2006-2007 Gero Kuhlmann <gero@gkminix.han.de>
 *
 *  Parts of this file have been taken from the GNU libiberty library,
 *  and the original file carries the following copyright:
 *
 *	Copyright (C) 1994 Free Software Foundation, Inc.
 *
 *  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
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: vasprintf.c,v 1.3 2007/01/06 18:31:39 gkminix Exp $
 */

#include <common.h>
#include <nblib.h>


/*
 * Internal routine to be able to copy all variadic parameters into
 * a local buffer
 */
#ifndef HAVE_VASPRINTF
static int int_vasprintf __F((result, format, args),
						char **result AND
						const char *format AND
						va_list *args)
{
  const char *p = format;
  char *c;
  size_t total_width = strlen(format) + 1;
  va_list ap;

  memcpy((voidstar)&ap, (voidstar)args, sizeof(va_list));
  while (*p != '\0') {
	if (*p++ == '%') {
		while (strchr("-+ #0", *p))
			++p;
		if (*p == '*') {
			++p;
			total_width += abs(va_arg(ap, int));
		} else {
			total_width += (unsigned long)strtol(p, &c, 10);
			p = c;
		}
		if (*p == '.') {
			++p;
			if (*p == '*') {
				++p;
				total_width += abs(va_arg(ap, int));
			} else {
				total_width += (unsigned long)strtol(p, &c, 10);
				p = c;
			}
		}
		while (strchr("hlL", *p))
			++p;
		total_width += 30;
		switch (*p) {
			case 'd':
			case 'i':
			case 'o':
			case 'u':
			case 'x':
			case 'X':
			case 'c':
				(void)va_arg(ap, int);
				break;
			case 'f':
			case 'e':
			case 'E':
			case 'g':
			case 'G':
				(void)va_arg(ap, double);
				total_width += 307;
				break;
			case 's':
				total_width += strlen(va_arg(ap, char *));
				break;
			case 'p':
			case 'n':
				(void)va_arg(ap, char *);
				break;
		}
		p++;
	}
  }
  *result = (char *)nbmalloc(total_width);
  if (*result != NULL)
	return(vsprintf(*result, format, *args));
  return(0);
}
#endif



/*
 * Print a string using variadic arguments
 */
#ifndef HAVE_VASPRINTF
int nbvasprintf __F((result, format, args),
					char **result AND
					const char *format AND
					va_list args)
{
  return(int_vasprintf(result, format, &args));
}
#endif

