/*

  sshdsprintf.c

  Author:
        Sami Lehtinen <sjl@ssh.fi>

  Copyright (C) 1999 SSH Communications Security Oy, Espoo, Finland
  All rights reserved.
*/

#include "sshincludes.h"
#include "sshdsprintf.h"

#define SSH_DEBUG_MODULE "SshDSprintf"

int ssh_dsprintf(char **str, const char *format, ...)
{
  va_list ap;
  int result;

  va_start(ap, format);
  result = ssh_dvsprintf(str, format, ap);
  va_end(ap);

  return result;
}

int ssh_dvsprintf(char **str, const char *format, va_list ap)
{
  int ret;
  char *buffer;
  unsigned long size = 100L;

  SSH_PRECOND(str != NULL);
  SSH_PRECOND(format != NULL);

  /* Guess 100 characters length. */
  buffer = ssh_xcalloc(size, sizeof(char));

  do
    {
      ret = vsnprintf(buffer, size, format, ap);

      /* ret > size is for broken vsnprintf-implementations. If the
         output is truncated by vsnprintf, it should return -1. At
         least my linux glibc 2.1.1 system didn't return this. */
      if (ret < 0 || ret >= size - 1)
        {
          /* Some implementations of vsnprintf give a return value of
             given buffer size + 1, if the sting wouldn't fit to the
             buffer. */
          if (ret > (signed long) size + 1)
            {
              SSH_DEBUG(5, ("vsnprintf gave return value %d, when given " \
                            "buffer size is only %d.", ret, size));
              /* if ret > size, the vsnprintf has told us the required
                 buffer size. So we use it. */
              size = ret + 1;
              ret = -1;
            }
          else
            {
              /* If it wasn't enough, double the buffer's size. */
              ret = -1;
              size *= 2L;
            }

          buffer = ssh_xrealloc(buffer, size);
        }
    }
  while(ret < 0);

  *str = buffer;
  return ret;
}
