/* CSL - Common Sound Layer
 * Copyright (C) 1997, 2000-2001 Stefan Westerfeld and Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include	"cslutils.h"

#include	<stdlib.h>
#include	<stdio.h>
#include	<string.h>
#include	<stdarg.h>


/* --- functions --- */

/**
 * Display an error message on standard error and then exit using abort().
 *
 * @param format A printf() style format string optionally followed by
 * additional arguments. Does not return.
 * @see csl_warning
 * @see csl_message
 * @short Display error message
 */
void
csl_error (const char *format,
	   ...)
{
  va_list args;

  va_start (args, format);
  fprintf (stderr, "\n** CSL-Error **: ");
  vfprintf (stderr, format, args);
  fprintf (stderr, "\n");
  va_end (args);
  abort ();
}

/**
 * Display a warning message on standard error.
 *
 * @param format A printf() style format string optionally followed by
 * additional arguments.
 * @return none
 * @see csl_error
 * @see csl_message
 * @short Display warning message
 */
void
csl_warning (const char *format,
	     ...)
{
  static int warnabort = 2;
  va_list args;

  va_start (args, format);
  fprintf (stderr, "\n** CSL-Warning **: ");
  vfprintf (stderr, format, args);
  fprintf (stderr, "\n");
  va_end (args);

  if (warnabort == 2)
    {
      char *v = getenv ("CSL_ABORT");

      warnabort = atoi (v ? v : "0") ? TRUE : FALSE;
    }
  if (warnabort)
    abort ();
}

/**
 * Display an informational message on standard error.
 *
 * @param format A printf() style format string optionally followed by
 * additional arguments.
 * @return none
 * @see csl_error
 * @see csl_warning
 * @short Display informational message
 */
void
csl_message (const char *format,
	     ...)
{
  va_list args;

  va_start (args, format);
  fprintf (stderr, "\nCSL-Message: ");
  vfprintf (stderr, format, args);
  fprintf (stderr, "\n");
  va_end (args);
}

static unsigned int csl_debug_mask = 0;

/**
 * Set level of debug messages to be displayed.
 * e.g. csl_set_debug_mask(CSL_DEBUG_PCM|CSL_DEBUG_MISC);
 *
 * @param debug_mask Debug flags, one or more of the elements of the enumerated type CslDebugFlags, ORed together.
 * @see csl_check_debug
 * @see csl_debug
 * @short Set debugging level.
 */
void
csl_set_debug_mask (unsigned int debug_mask)
{
  csl_debug_mask = debug_mask;
}

/**
 * Return whether the specified debug level is enabled.
 * e.g. csl_check_debug(CSL_DEBUG_PCM);
 *
 * @param debug_key One of the elements of the enumerated type CslDebugFlags.
 * @return TRUE if the given debug level is enabled, otherwise FALSE.
 * @see csl_set_debug_mask
 * @see csl_debug
 * @short Check debug level.
 */
CslBool
csl_check_debug (unsigned int debug_key)
{
  return csl_debug_mask & debug_key;
}

/**
 * Free memory previously allocated by csl_malloc, csl_malloc0, csl_malloc0, csl_new, or csl_new0.
 *
 * @param mem Pointer to previously allocated memory.
 * @return none
 * @see csl_malloc
 * @see csl_malloc0
 * @see csl_realloc
 * @see csl_new
 * @see csl_new0
 * @short Free dynamically allocated memory
 */
void
csl_free (void *mem)
{
  if (mem)
    free (mem);
}

/**
 * Dynamically allocate storage. Calls csl_error if memory cannot be allocated.
 * @param n_bytes The number of bytes of storage to be dynamically allocated.
 * @return A pointer to the allocated memory.
 * @see csl_free
 * @see csl_malloc0
 * @see csl_realloc
 * @see csl_new
 * @see csl_new0
 * @short Dynamically allocate memory
 */
void*
csl_malloc (unsigned int n_bytes)
{
  void *mem = NULL;

  if (n_bytes)
    {
      mem = malloc (n_bytes);
      if (!mem)
	csl_error ("unable to allocate %u bytes", n_bytes);
    }
  return mem;
}

/**
 * Dynamically allocate storage. Calls csl_error if memory cannot be allocated.
 * Sets the allocated memory to all zeroes.
 * @param n_bytes The number of bytes of storage to be dynamically allocated.
 * @return A pointer to the allocated memory.
 * @see csl_free
 * @see csl_malloc0
 * @see csl_realloc
 * @see csl_new
 * @see csl_new0
 * @short Dynamically allocate and clear memory.
 */
void*
csl_malloc0 (unsigned int n_bytes)
{
  void *mem = NULL;

  if (n_bytes)
    {
      mem = malloc (n_bytes);
      if (!mem)
	csl_error ("unable to allocate %u bytes", n_bytes);
      memset (mem, 0, n_bytes);
    }
  return mem;
}

/**
 * Changes the size of dynamically allocate storage. Calls csl_error if memory cannot be allocated.
 * @param mem Pointer to the start of the previously allocated storage. If NULL, the call is equivalent
 * to calling csl_malloc.
 * @param n_bytes The new size of the area of storage to be dynamically allocated, which can be
 * greater or smaller than the current size. If n_bytes is zero, then the call is equivalent to
 * calling csl_free.
 * @return A pointer to the new area of allocated memory.
 * @see csl_free
 * @see csl_malloc
 * @see csl_malloc0
 * @see csl_new
 * @see csl_new0
 * @short Change size of dynamically allocated memory.
 */
void*
csl_realloc (void         *mem,
	     unsigned int  n_bytes)
{
  if (n_bytes && mem)
    {
      mem = realloc (mem, n_bytes);
      if (!mem)
	csl_error ("unable to allocate %u bytes", n_bytes);
    }
  else if (n_bytes)	/* some systems fail for realloc (0, n); */
    {
      mem = malloc (n_bytes);
      if (!mem)
	csl_error ("unable to allocate %u bytes", n_bytes);
    }
  else if (mem)
    {
      free (mem);
      mem = NULL;
    }
  
  return mem;
}

void*
csl_memdup (void const  *mem,
	    unsigned int n_bytes)
{
  void *block;

  if (mem)
    {
      block = csl_malloc (n_bytes);
      memcpy (block, mem, n_bytes);
    }
  else
    block = NULL;

  return block;
}

/**
 * Returns a pointer to a new string which is a duplicate of
 * string. Memory for the new string is obtained with csl_malloc and
 * can be freed with csl_free.
 *
 * @param string Pointer to the original string
 * @return A pointer to the new string
 * @see csl_free
 * @see csl_strfreevn
 * @short Duplicate a string
 */
char*
csl_strdup (const char *string)
{
  return string ? strdup (string) : NULL;
}

/**
 * A group of strings pointed to by pointers stored sequentially in
 * memory are freed using csl_free.
 *
 * @param n Number of string pointers to be freed.
 * @param str_p Pointer to start of a series of pointers to strings to be freed.
 * @see csl_free
 * @short Free a group of strings.  */
void
csl_strfreevn (unsigned int n,
	       char       **str_p)
{
  unsigned int i;

  for (i = 0; i < n; i++)
    csl_free (str_p[i]);
  csl_free (str_p);
}
