Logo Search packages:      
Sourcecode: lanmap version File versions  Download package

misc.c

/* ex: set tabstop=4 noet: */

#include <assert.h>
#include <stdlib.h> /* errno */
#include <stdio.h> /* strncpy */
#include <ctype.h> /* isupper() and friends */
#include <math.h> /* modf */
#include <string.h>
#include <stdarg.h> /* va_list */
#include <limits.h> /* UCHAR_MAX */
#include <errno.h>
#ifndef WIN32
      #include <stdint.h> /* uint32_t and friends */
#endif
#include "types.h"
#include "protocols.h"
#include "misc.h"

union {
      uint16_t n;
      char unsigned c[2];
} Endianness;

/*
 * generate one line hexeditor-style dump of bytes
 *
 * 0         1         2         3         4         5         6         7
 * 01234567890123456789012345678901234567890123456789012345678901234567890123456789
 * 0000  00 11 22 33 44 55 66 77  88 99 AA BB CC DD EE FF  01234567 89ABCDEF\n
 *
 * FIXME: hardcoded magic everywhere, sorry :/
 */
size_t bytes_dump_hex_line(const u_char *bytes, size_t offset, size_t len)
{
      register size_t i = offset, j;
      char linebuf[80];
      const size_t linechars = 16; /* how many bytes per line, #define instead? */

#ifdef _DEBUG
      assert(NULL != bytes);
#endif

      if (0 == len)
            return offset;

      /* one line */
      if (i + 16 > len)
            memset(linebuf, ' ', sizeof linebuf);
      sprintf(linebuf, "%04X  ", (unsigned int) i);
      for (j = 0; i < len && j < linechars; j++, i++) {
            sprintf((char *)(linebuf + 6 + (j * 3) + (j > 7)), "%02X ", bytes[i]);
            sprintf((char *)(linebuf + 56 + j + (j > 7)), "%c",
                  ('%' != bytes[i] && (isalnum(bytes[i]) || ' ' == bytes[i] || ispunct(bytes[i])) ? bytes[i] : '.'));
      }
      linebuf[6 + ((j - 1) * 3) + (j - 1 > 7) + 3] = ' ';
      linebuf[30] = ' ';
      linebuf[55] = ' ';
      linebuf[64] = ' ';
      linebuf[56 + j - 1 + (j - 1 > 7) + 1] = '\n';
      linebuf[56 + j - 1 + (j - 1 > 7) + 2] = '\0';
      printf(linebuf);
#ifdef DEBUG
      if (strlen(linebuf) > 73) {
            fprintf(stderr, "line too long, wtf?!\n");
            assert(0);
      }
#endif

      return i;
}

/**
 * convenience wrapper for bytes_dump_hex_line
 */
void bytes_dump_hex(const u_char *bytes, size_t offset, size_t len)
{
      while (offset < len)
            offset = bytes_dump_hex_line(bytes, offset, len);
}

/**
 *
 */
uint32_t pow_2_up(uint32_t n)
{
      n--;
      n |= n >> 1;
      n |= n >> 2;
      n |= n >> 4;
      n |= n >> 8;
      n |= n >> 16;
      return n++;
}

/**
 * put test val in endianness struct
 */
void endian_init(void)
{
      Endianness.n = 0x0100;
}

/**
 *
 */
int machine_is_big_endian(void)
{
      return (Endianness.c[0] == 0x01);
}

/**
 *
 */
int machine_is_little_endian(void)
{
      return (Endianness.c[0] == 0x00);
}

/********************** string functions ****************************/


/**
 * force all chars in a string to uppercase
 * @param str
 * @return 
 * @see strdown
 */
char * strup(char *str)
{
      char *c;

#ifdef _DEBUG
      assert(NULL != str);
#endif
      
      for (c = str; *c != '\0'; c++)
            *c = toupper(*c);

      return str;
}


/**
 * force string to lowercase
 * @param str
 * @return pointer to arg, now lower-cased
 * @see strup, strdown
 */
char * strdown(char *str)
{
      char *c;

#ifdef _DEBUG
      assert(NULL != str);
#endif
      
      for (c = str; *c != '\0'; c++)
            *c = tolower(*c);

      return str;
}

/**
 *
 */
char * strtrim(char *str)
{
      char *c;
#ifdef _DEBUG
      assert(NULL != str);
#endif

      if ('\0' == str[0])
            return str;

      for (c = str; isspace(*c); c++);
      if (c > str)
            memcpy(str, c, strlen(c) + 1);

      for (c = strchr(str, '\0'); c > str && ('\0' == *c || isspace(*c)); c--);
      if (c > str)
            *(c + 1) = '\0';

      return str;
}


/*
 * strcmp that is NULL-tolerant
 */
int xstrcmp(const char *a, const char *b)
{
/* a and b may be NULL, that's the point */

      if (NULL == a) {
            return (NULL == b ? 0 : -1);
      } else if (NULL == b) {
            return (NULL == a ? 0 : 1);
      } else {
            return strcmp(a, b);
      }
      return 0; /* will never happen */
}

/*
 * NULL-tolerant strncmp()
 */
int xstrncmp(const char *a, const char *b, size_t n)
{
/* a and b may be NULL, that's the point */

      if (NULL == a) {
            return (NULL == b ? 0 : -1);
      } else if (NULL == b) {
            return (NULL == a ? 0 : 1);
      } else {
            return strncmp(a, b, n);
      }
      return 0; /* will never happen */
}

/**
 * strcmp() with a "void" signature, mostly for use as a callback
 * @note args MUST NOT be NULL
 * @see xstrcmp, vxstrcmp
 */
int vstrcmp(const void *a, const void *b)
{
      return strcmp(a, b);
}

/*
 * xstrcmp() with a "void" signature, mostly for use as a callback
 */
int vxstrcmp(const void *a, const void *b)
{
/* a and b may be NULL, that's the point */

      if (NULL == a) {
            return (NULL == b ? 0 : -1);
      } else if (NULL == b) {
            return (NULL == a ? 0 : 1);
      } else {
            return strcmp(a, b);
      }
      return 0; /* will never happen */
}

/**
 * returns a duplicate string, and we act smartly if passed a NULL
 * what a novel concept! (i dislike strdup()'s crashiness on NULL)
 */
char * xstrdup(const char *str)
{
      return (NULL == str ? NULL : strdup(str));
}

/*
 * xstrdup() with a "void" signature
 * NOTE: meant for use as a callback that duplicates a string
 */
void * vxstrdup(void *str)
{
      return xstrdup(str);
}


/**
 * Safe openbsd-style string copying. Always appends a nul terminator. Takes in full destination length.
 * @param dest
 * @param src
 * @param size
 * @return
 * @note use this instead of strncpy, which sucks
 */
size_t strlcpy(char *dst, const char *src, size_t size)
{
      char *orig;

#ifdef _DEBUG
      assert(NULL != dst);
      assert(NULL != src);
#endif

      if (0 == size)
            return 0;

      orig = dst;

      /* copy the string leaving room for the zero-termination */
      while (*src != '\0' && --size > 0)
            *dst++ = *src++;
      *dst = '\0';

      /* If we didn't copy the whole string, report error */
      if (*src != '\0') 
            errno = -1;

      return (size_t)(dst - orig);
}

/*
 * purpose: Safe openbsd-style string concatentation. Always
 *                appends a nul terminator. Takes in the full
 *                destination length, not a delta.
 */
size_t strlcat(char *dst, const char *src, size_t size)
{
      char *orig;

#ifdef _DEBUG
      assert(NULL != dst);
      assert(NULL != src);
#endif
      
      if (0 == size)
            return 0;

      orig = dst;

      /* find the end of the destination */
      size--;  
      while (*dst != '\0' && size-- > 0) 
            dst++;

      if (size <= 0) {
            errno = -1;
      } else {
            while (*src != '\0' && size-- > 0)
                  *dst++ = *src++;
            *dst = '\0';

            if (*src != '\0') 
                  errno = -1;
      }
      
      return (size_t)(dst - orig);
}

/**
 * NULL-tolerant strcpy
 * @param dest
 * @param src
 * @return
 */
char * xstrcpy(char *dest, const char *src)
{
#ifdef _DEBUG
      assert(NULL != dest);
      /* src may be NULL */
#endif

      if (NULL == src) {
            dest[0] = '\0';
      } else {
            while ('\0' != (*dest++ = *src++));
      }
      return dest;
}


#if defined(WIN32)
/**
 * WIN32 provides _snprintf, which is a piece of shit
 */
int snprintf(char *buf, size_t size, const char *format, ...)
{
      int bytes;
      va_list     args;

      va_start(args, format);
      bytes = vsnprintf(buf, size, format, args);
      va_end(args);
      return bytes;
}
#endif

#if defined(WIN32)
/**
 * ensure a NUL-terminated string, as MSFT does not ensure this!
 */
int vsnprintf(char *buf, size_t size, const char *format, va_list args)
{
      int bytes = _vsnprintf(buf, size - 1, format, args);
      buf[(bytes >= (int)size ? size - 1 : (bytes < 0 ? 0 : bytes))] = '\0';
      return bytes;
}
#endif


/*
 *
 */
void bytes_dump_escape(const void *bytes, size_t len)
{
      const char unsigned *b = bytes;
      register size_t i;
      int lasthex = 0;

#ifdef _DEBUG
      assert(NULL != bytes);
#endif

      for (i = 0; i < len; i++) {
            if (isprint(b[i]) && (0 == lasthex || !isxdigit(b[i])) && '\\' != b[i]) {
                  printf("%c", b[i]);
                  lasthex = 0;
            } else {
                  printf("\\x%02x", b[i]);
                  lasthex = 1;
            }
      }
}

/*
 * generate a string version of the dumped, escaped buffer 'bytes'
 */
char * bytes_dump_escape_buf(char *dest, size_t destlen, const void *bytes, size_t len)
{
      const char unsigned *b = bytes;
      register size_t i, j;
      int lasthex = 0;

#ifdef _DEBUG
      assert(NULL != dest);
      assert(destlen >= BYTES_DUMP_ESCAPE_BUFLEN(len));
#endif

      if (NULL == bytes) {
            snprintf(dest, destlen, "NULL");
            return dest;
      }

      for (i = j = 0; i < len && j < destlen; i++) {
            if (isprint(b[i]) && (0 == lasthex || !isxdigit(b[i])) && '\\' != b[i]) {
                  snprintf(dest + j, destlen, "%c", b[i]);
                  j++;
                  lasthex = 0;
            } else {
                  snprintf(dest + j, destlen, "\\x%02x", b[i]);
                  j += 4;
                  lasthex = 1;
            }
      }
      *(dest + j) = '\0';
      return dest;
}

/*
 * generate a string version of the dumped, escaped buffer 'bytes'
 */
char * bytes_dump_hex_buf(char *dest, size_t destlen, const void *bytes, size_t len)
{
      const char unsigned *b = bytes;
      register size_t i, j;

#ifdef _DEBUG
      assert(NULL != dest);
      assert(destlen >= BYTES_DUMP_ESCAPE_BUFLEN(len));
#endif

      if (NULL == bytes) {
            snprintf(dest, destlen, "NULL");
            return dest;
      }

      for (i = j = 0; i < len && j < destlen; i++) {
            snprintf(dest + j, destlen, "\\x%02x", b[i]);
            j += 4;
      }
      *(dest + j) = '\0';
      return dest;
}

/**
 * reported by DJB in comp.lang.c
 * @note many consider this to be an excellent function
 */
int unsigned hash_func_DJB(const void *str)
{
      const char *c;
      register int unsigned hash = 5381;

#ifdef _DEBUG
      assert(NULL != str);
#endif

      for (c = (const char *)str; *c != '\0'; c++)
            hash = ((hash << 5) + hash) + *c;

      return hash;
}

/**
 * an ugly but hopefully fast hash for a struct ip
 */
int unsigned hash_func_ip(const void *vip)
{
      const struct ip *ip = vip;
      int unsigned i, hash = 5381;
#ifdef _DEBUG
      assert(NULL != vip);
#endif
      for (i = 0; i < 4; i++)
            hash = ((hash << 5) + hash) + ip->addr.v4[i];
      if (IPV6 != ip->version)
            return hash;
      for (i = 4; i < 16; i++)
            hash = ((hash << 5) + hash) + ip->addr.v4[i];
      return hash;
}


/**
 */
int unsigned hash_func_int(const void *vi)
{
      return *(int unsigned *)vi;
}


/**
 * an ugly but hopefully fast hash for a struct ip
 */
int unsigned hash_func_mac(const void *vm)
{
      const struct mac *m = vm;
      int unsigned i, hash = 5381;

#ifdef _DEBUG
      assert(NULL != vm);
#endif

      for (i = 0; i < sizeof m->addr; i++)
            hash = ((hash << 5) + hash) + m->addr[i];

      return hash;
}


Generated by  Doxygen 1.6.0   Back to index