/**************************************************************************
 *
 * local_strings -- provides some extra string routines
 * Copyright (C) 1994  Authors
 *
 * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **************************************************************************/

#include "sysfuncs.h"

#include "local_strings.h"
#include "memlib.h"

/* =========================================================================
 * Function: arg_atoi
 * Description: 
 *      Converts an ascii string to an integer
 *      but allows a scale string immediately following.
 *      i.e. "10Mb" or "20Kb" or "40Megabytes"
 *      There must be no gap between the last digit and the scale.
 *      Only the fist letter is significant.
 *      K = Kilo
 *      M = Mega
 *      G = Giga
 * Input: 
 *      string of form: xxxxxxK or xxxxxxxM or xxxxxxxG
 *      where x is a digit
 * Output: 
 *      a scaled integer
 * ========================================================================= */

#define KILO 	1024
#define MEGA	1024*1024
#define GIGA	1024*1024*1024

int 
arg_atoi (char *str)
{
  char *str_ptr = str;
  char ch = '\0';
  mg_s_long scale = 1;

  /* find any scale letter immediately after digits */
  ch = *str_ptr;
  while (!isalpha (ch) && (ch != '\0'))
    ch = *str_ptr++;

  /* replace scale letter by end-of-string character */
  *str_ptr = '\0';

  /* set scale appropriately */
  switch (ch)
    {
    case 'K':
      scale = KILO;
      break;
    case 'M':
      scale = MEGA;
      break;
    case 'G':
      scale = GIGA;
      break;
    default:
      scale = 1;
      break;
    }

  return (atoi (str) * scale);

}

/* ===============================================================================
 * Function: compare
 * Description: Compare two strings. 
 * Input: Two binary strings, first byte of string indicates length. 
 * Output: Like standard strcmp.
 *      = 0 if s1 = s2
 *      < 0 if s1 < s2
 *      > 0 if s1 > s2
 * =============================================================================== */
int 
compare (u_char * s1, u_char * s2)
{
  int l1 = *s1, l2 = *s2;
  int l = (l1 < l2) ? l1 : l2;

  while (l--)
    if (*++s1 != *++s2)
      return (*s1 - *s2);
  return (l1 - l2);

}

/*
 * This array is designed for mapping upper and lower case letter
 * together for a case independent comparison.  The mappings are
 * based upon ascii character sequences.
 */
static unsigned char casecharmap[] = {
	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
};

/* ===============================================================================
 * Function: casecompare   [RPAP - Jan 97: Stem Index Change]
 * Description: Compare two strings in dictionary order
 * Input: Two binary strings, first byte of string indicates length. 
 * Output:
 *      = 0 if s1 = s2
 *      < 0 if s1 < s2
 *      > 0 if s1 > s2
 * =============================================================================== */
int 
casecompare (u_char * s1, u_char * s2)
{
  int l1 = *s1, l2 = *s2;
  int l = (l1 < l2) ? l1 : l2;
  int pos = 0;
  register int diff = 0;

  while (l--)
    if ((diff = casecharmap[*++s1] - casecharmap[*++s2]) != 0)
      return (diff);
    else if ((diff = *s1 - *s2) != 0)
      if (!pos)
	pos = diff;

  return ((l1 - l2) ? (l1 - l2) : (pos));

}

/* =========================================================================
 * Function: copy_string
 * Description: 
 *      Copies a string with the len in 1st byte
 * Input: 
 * Output: 
 * ========================================================================= */

u_char *
copy_string (u_char * src_str)
{
  u_char *copy = new u_char(src_str[0] + 1);

  if (!copy)
    return NULL;

  memcpy (copy, src_str, src_str[0] + 1);
  return copy;

}


/* ===============================================================================
 * Function: prefixlen
 * Description: Returns length of common prefix string between s1 and s2.
 * Input: two binary strings
 * Output: prefix length
 * =============================================================================== */
int 
prefixlen (u_char * s1, u_char * s2)
{
  int l = (*s1 < *s2) ? *s1 : *s2;
  int i = 0;

  while (i < l && *++s1 == *++s2)
    ++i;
  return (i);
}


/* ===============================================================================
 * Function: char2str
 * Description: 
 *      Ensures that non-printable characters are converted to a string
 *      which is printable i.e. it indentifies the character.
 *      e.g. carriage-return = "\n".
 * Input: character (may be non-printable)
 * Output: pointer to static string
 * =============================================================================== */

char *
char2str (u_char c)
{
  static char buf[10];
  switch (c)
    {
    case '\n':
      sprintf (buf, "\\n");
      break;
    case '\b':
      sprintf (buf, "\\b");
      break;
    case '\f':
      sprintf (buf, "\\f");
      break;
    case '\t':
      sprintf (buf, "\\t");
      break;
    default:
	if (c >= ' ' && c <= 126)
	switch (c)
	  {
	  case '\\':
	    sprintf (buf, "\\\\");
	    break;
	  case '\"':
	    sprintf (buf, "\\\"");
	    break;
	  case '\'':
	    sprintf (buf, "\\\'");
	    break;
	  default:
	    buf[0] = c;
	    buf[1] = '\0';
	    break;
	  }
      else
	sprintf (buf, "\\x%02x", c);
      break;
    }
  return buf;
}

/* ===============================================================================
 * Function: word2str
 * Description: 
 *      Converts a string with possible non-printable characters into a string
 *      consisting entirely of printable characters.
 * Input: string, length stored in first byte
 * Output: pointer to static string
 * =============================================================================== */

char *
word2str (u_char * s)
{
  static char buf[1024];
  char *p = buf;
  int i, len = (int) *s++;

  memset (buf, '\0', sizeof(buf));
  for (i = 0; i < len; ++i)
    {
      strcpy (p, char2str (s[i]));
      p = strchr (p, '\0');
    }
  return buf;
}


/* =========================================================================
 * Function: de_escape_string
 * Description: 
 *      Turn a string containing \ escapes into real characters
 *      Note this destroys the string s in the process
 * Input: string to de-escape 
 * Output: the de-escaped string
 * ========================================================================= */
char *
de_escape_string (char *s)
{
  char *org = s;
  char *d = s;
  while (*s)
    {
      if (*s == '\\')
	{
	  ++s;
	  switch (*s++)
	    {
	    case '\0':
	      *d++ = '\\';
	      --s;
	      break;
	    case '\\':
	      *d++ = '\\';
	      break;
	    case 'b':
	      *d++ = '\b';
	      break;
	    case 'f':
	      *d++ = '\f';
	      break;
	    case 'n':
	      *d++ = '\n';
	      break;
	    case 'r':
	      *d++ = '\r';
	      break;
	    case 't':
	      *d++ = '\r';
	      break;
	    case '\"':
	      *d++ = '\"';
	      break;
	    case '\'':
	      *d++ = '\'';
	      break;
	    case 'x':
	      {
		int num = 0;
		if (isxdigit (*s))
		  {
		    char ch = toupper (*s++);
		    num = ch <= '9' ? ch - '0' : ch - 'A' + 10;
		  }
		if (isxdigit (*s))
		  {
		    char ch = toupper (*s++);
		    num = (num << 4) + (ch <= '9' ? ch - '0' : ch - 'A' + 10);
		  }
		*d++ = num;
		break;
	      }
	    case '0':
	    case '1':
	    case '2':
	    case '3':
	    case '4':
	    case '5':
	    case '6':
	    case '7':
	      {
		int num = *(s - 1) - '0';
		if (*s >= '0' && *s <= '7')
		  num = (num << 3) + *s++ - '0';
		if (*s >= '0' && *s <= '7')
		  num = (num << 3) + *s++ - '0';
		*d++ = num;
		break;
	      }
	    }
	}
      else
	*d++ = *s++;
    }
  *d = '\0';
  return (org);
}

/* =========================================================================
 * Function: str255_to_string 
 * Description: 
 * Input: 
 * Output: 
 * ========================================================================= */

char *
str255_to_string (u_char * str255, char *str)
{
  static char buf[256];
  char *str_base = NULL;
  int len = *str255++;
  int i = 0;

  /* if haven't been given a str to write to then use local buffer */
  if (!str)
    str = &(buf[0]);

  str_base = str;
  for (i = 0; i < len; ++i)
    {
      *str++ = *str255++;
    }
  *str = '\0';

  return str_base;
}
