/*
 * Copyright Red Hat
 *
 * 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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA. 
 *
 * $Id: //eng/uds-releases/jasper/src/uds/stringUtils.c#2 $
 */

#include "stringUtils.h"

#include "errors.h"
#include "logger.h"
#include "memoryAlloc.h"
#include "permassert.h"
#include "uds.h"

/*****************************************************************************/
int allocSprintf(const char *what, char **strp, const char *fmt, ...)
{
  if (strp == NULL) {
    return UDS_INVALID_ARGUMENT;
  }
  va_list args;
#ifdef __KERNEL__
  // We want the memory allocation to use our own ALLOCATE/FREE wrappers.
  va_start(args, fmt);
  int count = vsnprintf(NULL, 0, fmt, args) + 1;
  va_end(args);
  int result = ALLOCATE(count, char, what, strp);
  if (result == UDS_SUCCESS) {
    va_start(args, fmt);
    vsnprintf(*strp, count, fmt, args);
    va_end(args);
  }
#else
  va_start(args, fmt);
  int result = vasprintf(strp, fmt, args) == -1 ? ENOMEM : UDS_SUCCESS;
  va_end(args);
#endif
  if ((result != UDS_SUCCESS) && (what != NULL)) {
    logError("cannot allocate %s", what);
  }
  return result;
}

/*****************************************************************************/
int wrapVsnprintf(const char *what, char *buf, size_t bufSize,
                  int error, const char *fmt, va_list ap, size_t *needed)
{
  if (buf == NULL) {
    static char nobuf[1];
    buf = nobuf;
    bufSize = 0;
  }
  int n = vsnprintf(buf, bufSize, fmt, ap);
  if (n < 0) {
    return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
                                   "%s: vsnprintf failed", what);
  }
  if (needed) {
    *needed = n;
  }
  if (((size_t) n >= bufSize) && (buf != NULL) && (error != UDS_SUCCESS)) {
    return logErrorWithStringError(error, "%s: string too long", what);
  }
  return UDS_SUCCESS;
}

/*****************************************************************************/
int fixedSprintf(const char *what,
                 char       *buf,
                 size_t      bufSize,
                 int         error,
                 const char *fmt,
                 ...)
{
  if (buf == NULL) {
    return UDS_INVALID_ARGUMENT;
  }
  va_list args;
  va_start(args, fmt);
  int result = wrapVsnprintf(what, buf, bufSize, error, fmt, args, NULL);
  va_end(args);
  return result;
}

/*****************************************************************************/
char *vAppendToBuffer(char       *buffer,
                      char       *bufEnd,
                      const char *fmt,
                      va_list     args)
{
  size_t n = vsnprintf(buffer, bufEnd - buffer, fmt, args);
  if (n >= (size_t) (bufEnd - buffer)) {
    buffer = bufEnd;
  } else {
    buffer += n;
  }
  return buffer;
}

/*****************************************************************************/
char *appendToBuffer(char *buffer, char *bufEnd, const char *fmt, ...)
{
  va_list ap;

  va_start(ap, fmt);
  char *pos = vAppendToBuffer(buffer, bufEnd, fmt, ap);
  va_end(ap);
  return pos;
}

/*****************************************************************************/
int stringToSignedInt(const char *nptr, int *num)
{
  long value;
  int result = stringToSignedLong(nptr, &value);
  if (result != UDS_SUCCESS) {
    return result;
  }
  if ((value < INT_MIN) || (value > INT_MAX)) {
    return ERANGE;
  }
  *num = (int) value;
  return UDS_SUCCESS;
}

/*****************************************************************************/
int stringToUnsignedInt(const char *nptr, unsigned int *num)
{
  unsigned long value;
  int result = stringToUnsignedLong(nptr, &value);
  if (result != UDS_SUCCESS) {
    return result;
  }
  if (value > UINT_MAX) {
    return ERANGE;
  }
  *num = (unsigned int) value;
  return UDS_SUCCESS;
}
