text: #define _GNU_SOURCE
  
  #ifdef DEBUG
  #include <stdio.h>
  #endif
  #include <stdlib.h>
  #include <arpa/inet.h>
  #include <unistd.h>
  #include <errno.h>
  #include <limits.h>
  #include <dirent.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <signal.h>
  
  #include "includes.h"
  #include "util.h"
  #include "table.h"
  
  int util_strlen(char *str)
  {
      int c = 0;
  
      while (*str++ != 0)
          c++;
      return c;
  }
  
  
  BOOL util_strncmp(char *str1, char *str2, int len)
  {
      int l1 = util_strlen(str1), l2 = util_strlen(str2);
  
      if (l1 < len || l2 < len)
          return FALSE;
  
      while (len--)
      {
          if (*str1++ != *str2++)
              return FALSE;
      }
  
      return TRUE;
  }
  
  BOOL util_strcmp(char *str1, char *str2)
  {
      int l1 = util_strlen(str1), l2 = util_strlen(str2);
  
      if (l1 != l2)
          return FALSE;
  
      while (l1--)
      {
          if (*str1++ != *str2++)
              return FALSE;
      }
  
      return TRUE;
  }
  
  int util_strcpy(char *dst, char *src)
  {
      int l = util_strlen(src);
  
      util_memcpy(dst, src, l + 1);
  
      return l;
  }
  
  void util_memcpy(void *dst, void *src, int len)
  {
      char *r_dst = (char *)dst;
      char *r_src = (char *)src;
      while (len--)
          *r_dst++ = *r_src++;
  }
  
  void util_zero(void *buf, int len)
  {
      char *zero = buf;
      while (len--)
          *zero++ = 0;
  }
  
  int util_atoi(char *str, int base)
  {
  	unsigned long acc = 0;
  	int c;
  	unsigned long cutoff;
  	int neg = 0, any, cutlim;
  
  	do {
  		c = *str++;
  	} while (util_isspace(c));
  	if (c == '-') {
  		neg = 1;
  		c = *str++;
  	} else if (c == '+')
  		c = *str++;
  
  	cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
  	cutlim = cutoff % (unsigned long)base;
  	cutoff /= (unsigned long)base;
  	for (acc = 0, any = 0;; c = *str++) {
  		if (util_isdigit(c))
  			c -= '0';
  		else if (util_isalpha(c))
  			c -= util_isupper(c) ? 'A' - 10 : 'a' - 10;
  		else
  			break;
              
  		if (c >= base)
  			break;
  
  		if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
  			any = -1;
  		else {
  			any = 1;
  			acc *= base;
  			acc += c;
  		}
  	}
  	if (any < 0) {
  		acc = neg ? LONG_MIN : LONG_MAX;
  	} else if (neg)
  		acc = -acc;
  	return (acc);
  }
  
  char *util_itoa(int value, int radix, char *string)
  {
      if (string == NULL)
          return NULL;
  
      if (value != 0)
      {
          char scratch[34];
          int neg;
          int offset;
          int c;
          unsigned int accum;
  
          offset = 32;
          scratch[33] = 0;
  
          if (radix == 10 && value < 0)
          {
              neg = 1;
              accum = -value;
          }
          else
          {
              neg = 0;
              accum = (unsigned int)value;
          }
  
          while (accum)
          {
              c = accum % radix;
              if (c < 10)
                  c += '0';
              else
                  c += 'A' - 10;
  
              scratch[offset] = c;
              accum /= radix;
              offset--;
          }
          
          if (neg)
              scratch[offset] = '-';
          else
              offset++;
  
          util_strcpy(string, &scratch[offset]);
      }
      else
      {
          string[0] = '0';
          string[1] = 0;
      }
  
      return string;
  }
  
  int util_memsearch(char *buf, int buf_len, char *mem, int mem_len)
  {
      int i, matched = 0;
  
      if (mem_len > buf_len)
          return -1;
  
      for (i = 0; i < buf_len; i++)
      {
          if (buf[i] == mem[matched])
          {
              if (++matched == mem_len)
                  return i + 1;
          }
          else
              matched = 0;
      }
  
      return -1;
  }
  
  int util_stristr(char *haystack, int haystack_len, char *str)
  {
      char *ptr = haystack;
      int str_len = util_strlen(str);
      int match_count = 0;
  
      while (haystack_len-- > 0)
      {
          char a = *ptr++;
          char b = str[match_count];
          a = a >= 'A' && a <= 'Z' ? a | 0x60 : a;
          b = b >= 'A' && b <= 'Z' ? b | 0x60 : b;
  
          if (a == b)
          {
              if (++match_count == str_len)
                  return (ptr - haystack);
          }
          else
              match_count = 0;
      }
  
      return -1;
  }
  
  ipv4_t util_local_addr(void)
  {
      int fd;
      struct sockaddr_in addr;
      socklen_t addr_len = sizeof (addr);
  
      errno = 0;
      if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
      {
  #ifdef DEBUG
          printf("[util] Failed to call socket(), errno = %d\n", errno);
  #endif
          return 0;
      }
  
      addr.sin_family = AF_INET;
      addr.sin_addr.s_addr = INET_ADDR(8,8,8,8);
      addr.sin_port = htons(53);
  
      connect(fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in));
  
      getsockname(fd, (struct sockaddr *)&addr, &addr_len);
      close(fd);
      return addr.sin_addr.s_addr;
  }
  
  char *util_fdgets(char *buffer, int buffer_size, int fd)
  {
      int got = 0, total = 0;
      do 
      {
          got = read(fd, buffer + total, 1);
          total = got == 1 ? total + 1 : total;
      }
      while (got == 1 && total < buffer_size && *(buffer + (total - 1)) != '\n');
  
      return total == 0 ? NULL : buffer;
  }
  
  static inline int util_isupper(char c)
  {
      return (c >= 'A' && c <= 'Z');
  }
  
  static inline int util_isalpha(char c)
  {
      return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
  }
  
  static inline int util_isspace(char c)
  {
      return (c == ' ' || c == '\t' || c == '\n' || c == '\12');
  }
  
  static inline int util_isdigit(char c)
  {
      return (c >= '0' && c <= '9');
  }
  