#include "gskghelpers.h"
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config.h"

/* --- hashtable => lists --- */

/**
 * gsk_g_ptr_array_foreach:
 * @array: array to iterate over.
 * @func: function to call on each element of @array.
 * @data: second parameter to @func.
 *
 * Like g_slist_foreach(), except it iterates over a GPtrArray instead.
 */
void gsk_g_ptr_array_foreach (GPtrArray *array,
			      GFunc      func,
			      gpointer   data)
{
  guint i;
  for (i = 0; i < array->len; i++)
    (*func) (array->pdata[i], data);
}

static gint
min_search_func (gconstpointer       key,
		 gconstpointer       data)
{
  * (gpointer *) data = (gpointer) key;
  return -1;
}

/**
 * gsk_g_tree_min:
 * @tree: tree to examine.
 *
 * Find the minimum key in the tree.
 *
 * returns: smallest key in the tree.
 */
gpointer gsk_g_tree_min (GTree *tree)
{
  gpointer rv = NULL;
  g_tree_search (tree, min_search_func, &rv);
  return rv;
}

static gint
max_search_func (gconstpointer       key,
		 gconstpointer       data)
{
  * (gpointer *) data = (gpointer) key;
  return +1;
}

/**
 * gsk_g_tree_max:
 * @tree: tree to examine.
 *
 * Find the maximum key in the tree.
 *
 * returns: largest key in the tree.
 */
gpointer gsk_g_tree_max (GTree *tree)
{
  gpointer rv = NULL;
  g_tree_search (tree, max_search_func, &rv);
  return rv;
}

static gint
prepend_key_pointer (gpointer         key,
		     gpointer         value,
		     gpointer         data)
{
  GSList **plist = data;
  *plist = g_slist_prepend (*plist, key);
  return 1;
}

static gint
prepend_value_pointer (gpointer         key,
		       gpointer         value,
		       gpointer         data)
{
  GSList **plist = data;
  *plist = g_slist_prepend (*plist, value);
  return 1;
}

/**
 * gsk_g_tree_key_slist:
 * @tree: the tree to scan.
 *
 * Get a list of all the keys in the trees, sorted.
 *
 * returns: the newly allocated list of pointers to the keys.
 */
GSList *gsk_g_tree_key_slist (GTree *tree)
{
  GSList *rv = NULL;
  g_tree_traverse (tree, prepend_key_pointer, G_IN_ORDER, &rv);
  return g_slist_reverse (rv);
}

/**
 * gsk_g_tree_value_slist:
 * @tree: the tree to scan.
 *
 * Get a list of all the values in the trees, sorted by key.
 *
 * returns: the newly allocated list of pointers to the keys.
 */
GSList *gsk_g_tree_value_slist (GTree *tree)
{
  GSList *rv = NULL;
  g_tree_traverse (tree, prepend_value_pointer, G_IN_ORDER, &rv);
  return g_slist_reverse (rv);
}

/**
 * gsk_g_hash_table_key_slist:
 * @table: the hash table to scan.
 *
 * Accumulate all the keys in the hash table into a big list.
 * You may not assume anything about the order of the list.
 *
 * returns: an allocated GSList of all the keys in the hash-table.
 */
GSList *gsk_g_hash_table_key_slist (GHashTable *table)
{
  GSList *rv = NULL;
  g_hash_table_foreach (table, (GHFunc) prepend_key_pointer, &rv);
  return rv;
}

/**
 * gsk_g_hash_table_value_slist:
 * @table: the hash table to scan.
 *
 * Accumulate all the values in the hash table into a big list.
 * You may not assume anything about the order of the list.
 *
 * returns: an allocated GSList of all the values in the hash-table.
 */
GSList *gsk_g_hash_table_value_slist (GHashTable *table)
{
  GSList *rv = NULL;
  g_hash_table_foreach (table, (GHFunc) prepend_value_pointer, &rv);
  return rv;
}

/**
 * gsk_g_error_add_prefix_valist:
 * @error: the pointer to error to change.
 * @format: printf-like format string.
 * @args: printf-like arguments.
 *
 * If @error is non-NULL, and points to a GError,
 * then modify it to be a GError that has the given
 * printf'd string as a prefix.
 */
void
gsk_g_error_add_prefix_valist  (GError   **error,
                                const char *format,
                                va_list     args)
{
  if (error && *error)
    {
      char *s = g_strdup_vprintf (format, args);
      GError *e = g_error_new ((*error)->domain,(*error)->code,
                               "%s: %s", s, (*error)->message);
      g_free (s);
      g_error_free (*error);
      *error = e;
    }
}

/**
 * gsk_g_error_add_prefix:
 * @error: the pointer to error to change.
 * @format: printf-like format string.
 * @...: printf-like arguments.
 *
 * If @error is non-NULL, and points to a GError,
 * then modify it to be a GError that has the given
 * printf'd string as a prefix.
 */
void
gsk_g_error_add_prefix  (GError   **error,
                         const char *format,
                         ...)
{
  va_list args;
  va_start (args, format);
  gsk_g_error_add_prefix_valist (error, format, args);
  va_end (args);
}

/**
 * gsk_strtoll:
 * @str: the string to parse a longlong integer (gint64) from.
 * @endp: optional place to store the character right past
 * the number in @str.  If *endp == @str, then you may assume an error
 * occurred.
 * @base: the assumed base for the number to parse.  eg "2" to
 * parse a binary, "8" for octal, "10" for decimal, "16" for hexidecimal.
 * Also, "0" is autodetects the C-style base.
 *
 * Like strtol, but for 64-bit integers.
 *
 * returns: the parsed integer.
 */
gint64
gsk_strtoll  (const char *str,
	      char      **endp,
	      int         base)
{
#if HAVE_STRTOQ
  return strtoq (str, endp, base);
#elif HAVE_STRTOLL
  return strtoll (str, endp, base);
#else
  return strtol (str, endp, base);
#endif
}

/**
 * gsk_strtoull:
 * @str: the string to parse a longlong unsigned integer (guint64) from.
 * @endp: optional place to store the character right past
 * the number in @str.  If *endp == @str, then you may assume an error
 * occurred.
 * @base: the assumed base for the number to parse.  eg "2" to
 * parse a binary, "8" for octal, "10" for decimal, "16" for hexidecimal.
 * Also, "0" is autodetects the C-style base.
 *
 * Like strtol, but for 64-bit unsigned integers.
 *
 * returns: the parsed unsigned integer.
 */
guint64
gsk_strtoull (const char *str,
	      char      **endp,
	      int         base)
{
#if HAVE_STRTOUQ
  return strtouq (str, endp, base);
#elif HAVE_STRTOULL
  return strtoull (str, endp, base);
#else
  return strtoul (str, endp, base);
#endif
}

/**
 * gsk_strnlen:
 * @ptr: the string to find the length of.
 * @max_len: the maximum length the string could be.
 *
 * Find the length of a string, which is only allocated
 * @max_len bytes, and does not need to be NUL-terminated.
 *
 * returns: the length.
 */
guint
gsk_strnlen (const char *ptr, guint max_len)
{
  guint rv = 0;
  while (max_len-- != 0 && *ptr++ != 0)
    rv++;
  return rv;
}

/**
 * gsk_fd_set_nonblocking:
 * @fd: the file-descriptor to make non-blocking.
 *
 * Make a file-descriptor non-blocking.
 * When it is non-blocking, operations that would
 * cause it to block should instead return
 * EAGAIN.  (Although you should use gsk_errno_is_ignorable()
 * to test, since windoze uses a different code, EWOULDBLOCK,
 * and you should always ignore EINTR.)
 *
 * returns: whether it was able to set the file descriptor non-blocking.
 */
gboolean
gsk_fd_set_nonblocking(int fd)
{
  int flags = fcntl (fd, F_GETFL);
  if (flags < 0)
    return FALSE;
  fcntl (fd, F_SETFL, flags | O_NONBLOCK);
  return TRUE;
}

gboolean
gsk_fd_clear_nonblocking(int fd)
{
  int flags = fcntl (fd, F_GETFL);
  if (flags < 0)
    return FALSE;
  fcntl (fd, F_SETFL, flags & (~O_NONBLOCK));
  return TRUE;
}

gboolean
gsk_fd_is_nonblocking(int fd)
{
  int flags = fcntl (fd, F_GETFL);
  if (flags < 0)
    return FALSE;
  return (flags & O_NONBLOCK) == O_NONBLOCK;
}


syntax highlighted by Code2HTML, v. 0.9.1