#include "stdafx.h"
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "asprintf.h"

int
vasprintf (char **result, const char *format, va_list args)
{
//  return int_vasprintf (result, format, &args);
  const char *p = format;
  /* Add one to make sure that it is never zero, which might cause malloc
     to return NULL.  */
  int total_width = strlen (format) + 1;
  va_list ap;

  /* this is not really portable but works under Windows */
  memcpy ( &ap, &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
            {
              char *endp;  
              total_width += strtoul (p, &endp, 10);
              p = endp;
            }
  if (*p == '.')
    {
      ++p;
      if (*p == '*')
{
  ++p;
  total_width += abs (va_arg (ap, int));
}
      else
                {
                  char *endp;
                  total_width += strtoul (p, &endp, 10);
                  p = endp;
                }
    }
  while (strchr ("hlL", *p))
    ++p;
  /* Should be big enough for any format specifier except %s
             and floats.  */
  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);
      /* Since an ieee double can have an exponent of 307, we'll
 make the buffer wide enough to cover the gross case. */
      total_width += 307;
    
    case 's':
      total_width += strlen (va_arg (ap, char *));
      break;
    case 'p':
    case 'n':
      (void) va_arg (ap, char *);
      break;
    }
}
    }
  *result = (char*)malloc (total_width);
  if (*result != NULL)
    return vsprintf (*result, format, args);
  else
    return 0;
}

int
asprintf VPARAMS ((char **buf, const char *fmt, ...))
{
  int status;
  VA_OPEN (ap, fmt);
  VA_FIXEDARG (ap, char **, buf);
  VA_FIXEDARG (ap, const char *, fmt);
  status = vasprintf (buf, fmt, ap);
  VA_CLOSE (ap);
  return status;
}



int
int_vasprintf (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
     to return NULL.  */
  int total_width = strlen (format) + 1;
  va_list ap;

  memcpy ((PTR) &ap, (PTR) 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 += strtoul (p, (char **) &p, 10);
  if (*p == '.')
    {
      ++p;
      if (*p == '*')
{
  ++p;
  total_width += abs (va_arg (ap, int));
}
      else
      total_width += strtoul (p, (char **) &p, 10);
    }
  while (strchr ("hlL", *p))
    ++p;
  /* Should be big enough for any format specifier except %s and floats.  */
  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);
      /* Since an ieee double can have an exponent of 307, we'll
 make the buffer wide enough to cover the gross case. */
      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++;
}
    }
#ifdef TEST
  global_total_width = total_width;
#endif
  *result = (char *) malloc (total_width);
  if (*result != NULL)
    return vsprintf (*result, format, *args);
  else
    return 0;
}
