#include "utils.h"

void *
my_malloc (size_t size)
{
  void *buf = malloc (size);
  if (buf == NULL)
    {
      cerr << "PANIC: failed malloc(" << size << ")\n";
      exit (1);
    }
  return buf;
}

void
my_free (void *ptr)
{
  if (ptr != NULL)
    free (ptr);
}

// malloc enough space in <*dest> (up to <maxlen>) to copy <src> into it,
// freeing <*dest> first if not NULL. if malloc() fails, <*dest> is preserved.
// to free() up <*dest>, use a NULL <src>
void
strset (char **dest, c_char src, size_t maxlen)
{
  if (src == NULL || src[0] == 0)
    {
      if (*dest != NULL)
        {
          free (*dest);
          *dest = NULL;
        }
      return;
    }
  size_t len = strlen (src);
  if (len > maxlen)
    len = maxlen;
  char *tmp = (char *)my_malloc (len+2);
  if (tmp == NULL)
    return;
  if (*dest != NULL)
    free (*dest);
  *dest = tmp;
  my_strncpy (*dest, src, len);
}

time_t
get_time (void)
{
  time_t t;
  return time (&t);
}

tm
get_localtime (void)
{
  time_t t = get_time ();
  return *localtime (&t);
}

char *
get_asctime (time_t t, char *buf, size_t len)
{
  my_strncpy (buf, asctime (localtime (&t)), len);
  return strip_crlf (buf);
}

// write in <str> the time <t>, in the format "hh:mm"
void
string_time (time_t t, char *str)
{
  tm time1;
  time1 = *localtime (&t);
  snprintf (str, 6, "%02d:%02d", time1.tm_hour, time1.tm_min);
}

// convert the long integer <n> to the string <buf> up to <len> chars
char *
ltoa (long int n, char *buf, size_t len)
{
  long int n2 = n;
  bool neg = 0;
  size_t i, size = 0;

  if (len == 0)
    {
      buf[0] = 0;
      return buf;
    }

  if (n2 < 0)
    {
      neg = 1; 
      n2 = -n2; 
      buf[0] = '-';
      len--;
    }

  do
    {
      n = n / 10;
      size++; 
    }
  while (n != 0);
  if (size > len)
    size = len;

  for (i = 1; i <= size; i++)
    {
      buf[neg+size-i] = n2%10 + 48;
      n2 =n2 / 10;
    }

  buf[neg+size] = 0;
  return buf;
}

// convert the integer <n> to the string <buf> up to <len> chars
char *
itoa (int n, char *buf, size_t len)
{
  int n2 = n;
  bool neg = 0;
  size_t i, size = 0;

  if (len == 0)
    {
      buf[0] = 0;
      return buf;
    }

  if (n2 < 0)
    {
      neg = 1; 
      n2 = -n2; 
      buf[0] = '-';
      len--;
    }

  do
    {
      n = n / 10;
      size++; 
    }
  while (n != 0);
  if (size > len)
    size = len;

  for (i = 1; i <= size; i++)
    {
      buf[neg+size-i] = n2%10 + 48;
      n2 =n2 / 10;
    }

  buf[neg+size] = 0;
  return buf;
}

// convert the unsigned integer <n> to the string <buf>
char *
u_itoa (u_int n, char *buf)
{
  u_int n2 = n, i, size = 0;

  do
    {
      n = n / 10;
      size++; 
    }
  while (n != 0);

  for (i = 1; i <= size; i++)
    {
      buf[size-i] = n2%10 + 48;
      n2 = n2 / 10;
    }

  buf[size] = 0;
  return buf;
}

void
random_init (void)
{
  time_t t = get_time ();
  struct tm *t2 = localtime (&t);
  srand (t2->tm_sec);
}

long
int random_num (long int max)
{
  if (max == 0)
    return 0;
  return rand () / (RAND_MAX / max);
}

size_t
num_spaces (c_char buf)
{
  size_t i = 0;
  while (buf[i] == ' ')
    i++;
  return i;
}

size_t
num_notspaces (c_char buf)
{
  size_t i = 0;
  while (buf[i] != ' ' && buf[i] != 0)
    i++;
  return i;
}

void
mask2nick (c_char mask, char *buf, size_t len)
{
  size_t i = 0;
  while (mask[i] != '!')
    if (mask[i++] == 0)
      {
        buf[0] = 0;
        return;
      }
  my_strncpy (buf, mask, i > len ? len : i);
}

void
mask2user (c_char mask, char *buf)
{
  int i = 0, i2;
  while (mask[i] != '!')
    if (mask[i++] == 0)
      {
        i = -1;
        break;
      }
  i2 = ++i;
  while (mask[i2] != '@')
    if (mask[i2++] == 0)
      {
        buf[0] = 0;
        return;
      }
  if (i2-i <= USER_SIZE)
    my_strncpy (buf, mask + i, i2 - i);
  else
    buf[0] = 0;
}

void
mask2host (c_char mask, char *buf)
{
  int i = 0;
  while (mask[i] != '@')
    if (mask[i++] == 0)
      {
        buf[0] = 0;
        return;
      }
  if (strlen (mask + i + 1) <= HOST_SIZE)
    strcpy (buf, mask + i + 1);
  else
    buf[0] = 0;
}

// only mask1 can have wildcards!
bool
match_mask (c_char mask2, c_char mask1)
{
  size_t i = 0, i2 = 0;

  while (i < strlen (mask1) || i2 < strlen (mask2))
    {
      if (mask1[i] != '*')
        {
          if (mask1[i] != '?')
            {
              if (strncasecmp (mask1 + i, mask2 + i2, 1) != 0)
                return 0;
            }
          else
            if (mask2[i2] == 0)
              return 0;
          i++;
          i2++;
        }
      else
        for (i++; i2 < strlen (mask2) && mask2[i2] != mask1[i]; i2++)
          if (mask1[i] == '?')
            i++;
    }
  return 1;
}

// transform mirage!mirage@darksun.dhis.org into *!*mirage@*.dhis.org
// and mirage!mirage@1.2.3.4 into *!*mirage@1.2.3.*
void
make_generic_mask (c_char mask, char *gen_mask)
{
  int i;
  char user[USER_SIZE+1];
  char host[HOST_SIZE+1];

  mask2user (mask, user);
  mask2host (mask, host);

  if (user[0] == 0 || host[0] == 0 || strlen (mask) > MASK_SIZE)
    {
      gen_mask[0] = 0;
      return;
    }

  snprintf (gen_mask, MASK_SIZE, "*!*%s@", user);
  if (host[strlen (host)-1] >= '0' && host[strlen (host)-1] <= '9')
    {
      strcpy (gen_mask + strlen (gen_mask), host);
      i = strlen (gen_mask) - 1;
      while (gen_mask[i] != '.' && gen_mask[i] != '@')
        i--;
      strcpy (gen_mask+i+1, "*");
    }
  else
    {
      i = 0;
      while (host[i] != '.')
        i++;
      sprintf (gen_mask + strlen (gen_mask), "*%s", host + i);
    }
}

// copy the first n words to dest[0..n-1] and the rest to dest[n]
void
strsplit (c_char src, char dest[][MSG_SIZE+1], u_char n)
{
  size_t i, pos = 0, chars;
  for(i = 0; i < n; i++)
    {
      pos += num_spaces (src + pos);
      chars = num_notspaces (src + pos);
      my_strncpy (dest[i], src + pos, chars);
      pos += chars;
    }
  my_strncpy (dest[i], src + pos + num_spaces (src + pos), MSG_SIZE);
}

// like strncpy, but assumes <dest> has <n>+1 bytes and puts a '\0' at the end
char *
my_strncpy (char *dest, c_char src, size_t n)
{
  size_t i = strlen (src);
  if (i > n)
    i = n;
  memcpy (dest, src, i);
  dest[i] = 0;
  return dest;
}

// return the file in <path>
c_char
fullpath2file (c_char path)
{
  int pos = 0;
  for (int i = 0; i < (int)strlen (path); i++)
    if (path[i] == '/')
      pos = i + 1;
  return path + pos;
}

// remove any CR/LF ('\n' and '\r') from the end of <str> and return it
char *
strip_crlf (char *str)
{
  for (int i = strlen (str) - 1; i >= 0; i--)
    {
      if (str[i] != '\n' && str[i] != '\r')
        break;
      str[i] = 0;
    }
  return str;
}

// apply toupper() to str
void
upper (char *str)
{
  while (str[0] != 0)
    {
      str[0] = toupper (str[0]);
      str++;
    }
}

// apply tolower() to str
void
lower (char *str)
{
  while (str[0] != 0)
    {
      str[0] = tolower (str[0]);
      str++;
    }
}
