/**************************************************************************** 
** File: utilities.c
**
** Author: Mike Borella
**
** Comments: General utility functions that are not tied to IPgrab in any
** particular way.
**
** $Id: utilities.c,v 1.13 2007/06/25 10:14:49 farooq-i-azam Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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 Library General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/

#define BUF_SIZE      128

#include "utilities.h"
#include "error.h"
#include <sys/socket.h> /* These headers must follow the global includes */
#include <netinet/in.h> /* otherwise FREEBESD barfs */
#include <arpa/inet.h>

#define SPACESTR_SIZE 128

char space_str[SPACESTR_SIZE];

/*----------------------------------------------------------------------------
**
** reverse_byte_order()
**
** Reverses the byte order of an arbitrarily long byte string
**
**----------------------------------------------------------------------------
*/

inline void reverse_byte_order(u_int8_t *s, int len)
{
  u_int8_t * temp;
  int i;

  temp = (u_int8_t *) my_malloc(len);
  for (i = 0; i < len; i++)
      temp[len-i-1] = s[i];
  memcpy(s, temp, len);
  my_free(temp);
}

/*----------------------------------------------------------------------------
**
** isspace_str(char *s, int len)
**
** Returns 1 if the first len bytes of s are whitespace, 0 otherwise.
**
**----------------------------------------------------------------------------
*/

inline int isspace_str(char *s, int len)
{
  int i;

  for (i = 0; i < len; i++)
    {
      if (!isspace(s[i]))
	return 0;
    }
  return 1;
}

/*----------------------------------------------------------------------------
**
** isprint_str(char *s, int len)
**
** Returns 1 if the first len bytes of s are printable, 0 otherwise.
**
**----------------------------------------------------------------------------
*/

inline int isprint_str(char *s, int len)
{
  int i;

  for (i = 0; i < len; i++)
    {
      if (!(isprint(s[i]) || isspace(s[i])))
	return 0;
    }
  return 1;
}

/*----------------------------------------------------------------------------
**
** argv2str(char **)
**
** Converts an argv[][] style array of strings into a single string, with
** the original string separated by spaces
**
**----------------------------------------------------------------------------
*/

inline char * argv2str(char **argv)
{
  char **p;
  u_int len = 0;
  char *buf;
  char *src, *dst;
  
  p = argv;
  if (*p == 0) return 0;

  while (*p)
    len += strlen(*p++) + 1;

  buf = (char *) my_malloc (len);
      
  p = argv;
  dst = buf;
  while ((src = *p++) != NULL) 
    {
      while ((*dst++ = *src++) != '\0');
      dst[-1] = ' ';
    }
  dst[-1] = '\0';
  
  return buf;  
}

/*----------------------------------------------------------------------------
**
** my_malloc()
**
** Performs a malloc but tests for error conditions.
**
**----------------------------------------------------------------------------
*/

inline void * my_malloc(size_t n)
{
  void * p;

  /* make sure that we always allocate something in the zero case */
  if (n == 0)
    n = 1;

  /* do it */
  p = malloc(n);
  if (p == NULL)
    error_fatal("can't allocate memory: %d bytes", n);

  return p;
}

/*----------------------------------------------------------------------------
**
** my_free()
**
** Frees memory safely by checking for the viability of the pointer
**
**----------------------------------------------------------------------------
*/

inline void my_free(void * p)
{
  if (p)
    free(p);
}


/*----------------------------------------------------------------------------
**
** dump_hex_and_text()
**
** Displays a buffer in split hex and text format.  Kind of like DOS debug :)
**
**----------------------------------------------------------------------------
*/

inline void dump_hex_and_text(char * buffer, int len)
{
  char   hexbuf  [BUF_SIZE];
  char   charbuf [BUF_SIZE];
  char * buf_ptr;
  char * buf_end;
  int    i;

  /* Set the start and end pointers */
  buf_ptr = buffer;
  buf_end = buffer+len-1;

  /* Scan each subset and display in hex and ascii format */
  do
    {
      memset(hexbuf, 0, BUF_SIZE);
      memset(charbuf, 0, BUF_SIZE);

      for(i=0;i<18;i++)
	{
	  if(buf_ptr < buf_end)
            {
	      snprintf(hexbuf+(i*3), BUF_SIZE-1,"%.2X ",buf_ptr[0] & 0xFF);
	      
	      if(*buf_ptr > 0x1F && *buf_ptr < 0x7E)
		snprintf(charbuf+i, BUF_SIZE-1,"%c",buf_ptr[0]);
	      else
		snprintf(charbuf+i, BUF_SIZE-1, ".");
	      
	      buf_ptr++;
            }
	}
      printf("%-54s %s\n",hexbuf,charbuf);
    }
  while(buf_ptr < buf_end);
}

/*----------------------------------------------------------------------------
**
** ipaddr_space()
**
** Takes an IP address in network byte order, and figures out how many
** spaces are needed to pretty print it so that it lines up with other
** addresses in minimal mode.
**
** Returns -1 on error.
**----------------------------------------------------------------------------
*/

inline int ipaddr_space(u_int32_t ipaddr)
{
  char * ptr;
  struct in_addr * ip_holder;

  ip_holder = (struct in_addr *) &ipaddr;
  ptr = inet_ntoa(*ip_holder);

  if (ptr)
    return 15-strlen(ptr);
  else
    return -1;
}

/*----------------------------------------------------------------------------
**
** make_space_str()
**
** Given a number of bytes, returns a string of that size.  Note that this 
** string is a global, defined above.
**
** Returns NULL if the number of sapces requested is not sane (smaller than 0
** or bigger than SPACESTR_SIZE).
**
**----------------------------------------------------------------------------
*/

inline char * make_space_str(int n)
{
  int i;
  
  if (n < 0 || n > SPACESTR_SIZE-1)
    return NULL;

  for (i=0; i<n; i++)
    space_str[i] = ' ';
  space_str[n] = '\0';

  return space_str;
}
