text: #include <stdio.h>
  #include <string.h>
  #include <stdlib.h>
  #include <ctype.h>
  
  #include "stringx.h"
  /*
      Gets the offset of one string in another string
  */
  int str_index_of(const char *a, char *b)
  {
      char *offset = (char*)strstr(a, b);
      return offset - a;
  }
  
  /*
      Checks if one string contains another string
  */
  int str_contains(const char *haystack, const char *needle)
  {
      char *pos = (char*)strstr(haystack, needle);
      if(pos)
          return 1;
      else
          return 0;
  }
  
  /*
      Removes last character from string
  */
  char* trim_end(char *string, char to_trim)
  {
      char last_char = string[strlen(string) -1];
      if(last_char == to_trim)
      {
          char *new_string = string;
          new_string[strlen(string) - 1] = 0;
          return new_string;
      }
      else
      {
          return string;
      }
  }
  
  /*
      Concecates two strings, a wrapper for strcat from string.h, handles the resizing and copying
  */
  char* str_cat(char *a, char *b)
  {
      char *target = (char*)malloc(strlen(a) + strlen(b) + 1);
      strcpy(target, a);
      strcat(target, b);
      return target;
  }
  
  /* 
      Converts an integer value to its hex character
  */
  char to_hex(char code) 
  {
      static char hex[] = "0123456789abcdef";
      return hex[code & 15];
  }
  
  /*
      URL encodes a string
  */
  char *urlencode(char *str) 
  {
      char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf;
      while (*pstr) 
      {
          if (isalnum((int)*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') 
              *pbuf++ = *pstr;
          else if (*pstr == ' ') 
              *pbuf++ = '+';
          else 
              *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
          pstr++;
      }
      *pbuf = '\0';
      return buf;
  }
  
  /*
      Replacement for the string.h strndup, fixes a bug
  */
  char *str_ndup (const char *str, size_t max)
  {
      size_t len = strnlen (str, max);
      char *res = (char*)malloc (len + 1);
      if (res)
      {
          memcpy (res, str, len);
          res[len] = '\0';
      }
      return res;
  }
  
  /*
      Replacement for the string.h strdup, fixes a bug
  */
  char *str_dup(const char *src)
  {
      char *tmp = (char*)malloc(strlen(src) + 1);
      if(tmp)
          strcpy(tmp, src);
      return tmp;
  }
  
  /*
      Search and replace a string with another string , in a string
  */
  char *str_replace(char *search , char *replace , char *subject)
  {
      char  *p = NULL , *old = NULL , *new_subject = NULL ;
      int c = 0 , search_size;
      search_size = strlen(search);
      for(p = strstr(subject , search) ; p != NULL ; p = strstr(p + search_size , search))
      {
          c++;
      }   
      c = ( strlen(replace) - search_size )*c + strlen(subject);
      new_subject = (char*)malloc( c );
      strcpy(new_subject , "");
      old = subject;  
      for(p = strstr(subject , search) ; p != NULL ; p = strstr(p + search_size , search))
      {
          strncpy(new_subject + strlen(new_subject) , old , p - old);
          strcpy(new_subject + strlen(new_subject) , replace);
          old = p + search_size;
      }
      strcpy(new_subject + strlen(new_subject) , old);    
      return new_subject;
  }
  
  /*
      Get's all characters until '*until' has been found
  */
  char* get_until(char *haystack, char *until)
  {
      int offset = str_index_of(haystack, until);
      return str_ndup(haystack, offset);
  }
  
  
  /* decodeblock - decode 4 '6-bit' characters into 3 8-bit binary bytes */
  void decodeblock(unsigned char in[], char *clrstr) 
  {
      unsigned char out[4];
      out[0] = in[0] << 2 | in[1] >> 4;
      out[1] = in[1] << 4 | in[2] >> 2;
      out[2] = in[2] << 6 | in[3] >> 0;
      out[3] = '\0';
      strncat((char *)clrstr, (char *)out, sizeof(out));
  }
  
  /*
      Decodes a Base64 string
  */
  char* base64_decode(char *b64src) 
  {
      char *clrdst = (char*)malloc( ((strlen(b64src) - 1) / 3 ) * 4 + 4 + 50);
      char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      int c, phase, i;
      unsigned char in[4];
      char *p;
      clrdst[0] = '\0';
      phase = 0; i=0;
      while(b64src[i]) 
      {
          c = (int) b64src[i];
          if(c == '=') 
          {
              decodeblock(in, clrdst); 
              break;
          }
          p = strchr(b64, c);
          if(p) 
          {
              in[phase] = p - b64;
              phase = (phase + 1) % 4;
              if(phase == 0) 
              {
                  decodeblock(in, clrdst);
                  in[0]=in[1]=in[2]=in[3]=0;
              }
          }
          i++;
      }
      clrdst = (char*)realloc(clrdst, strlen(clrdst) + 1);
      return clrdst;
  }
  
  /* encodeblock - encode 3 8-bit binary bytes as 4 '6-bit' characters */
  void encodeblock( unsigned char in[], char b64str[], int len ) 
  {
      char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      unsigned char out[5];
      out[0] = b64[ in[0] >> 2 ];
      out[1] = b64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
      out[2] = (unsigned char) (len > 1 ? b64[ ((in[1] & 0x0f) << 2) |
               ((in[2] & 0xc0) >> 6) ] : '=');
      out[3] = (unsigned char) (len > 2 ? b64[ in[2] & 0x3f ] : '=');
      out[4] = '\0';
      strncat((char *)b64str, (char *)out, sizeof(out));
  }
  
  /* 
      Encodes a string with Base64
  */
  char* base64_encode(char *clrstr) 
  {
      char *b64dst = (char*)malloc(strlen(clrstr) + 50);
      //char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      unsigned char in[3];
      int i, len = 0;
      int j = 0;
  
      b64dst[0] = '\0';
      while(clrstr[j]) 
      {
          len = 0;
          for(i=0; i<3; i++) 
          {
              in[i] = (unsigned char) clrstr[j];
              if(clrstr[j]) 
              {
                  len++; j++;
              }
              else in[i] = 0;
          }
          if( len ) 
          {
              encodeblock( in, b64dst, len );
          }
      }
      b64dst = (char*)realloc(b64dst, strlen(b64dst) + 1);
      return b64dst;
  }
  
  