/*
** mg_buf.c for  in 
** 
** Made by vianney rancurel
** Login   <vianney@epita.fr>
** 
** Started on  Wed Aug 25 12:16:34 1999 vianney rancurel
** Last update Thu Oct 28 20:16:25 1999 
*/
#include <ctype.h>
#include "mg.h"

/* returns the integer value of an hexadecimal digit */
int			xdigit_value(xdigit)
int			xdigit;
{
  if (isdigit(xdigit))
    return (xdigit - '0');
  if (isupper(xdigit))
    return (10 + xdigit - 'A');
  return (10 + xdigit - 'a');
}

/* converts an hexadecimal str to a buffer.
   Xdata is composed of xdigit pairs.
   Returns 0 or various errors */
t_status		xdata_to_buf(xdata,buf,len,max_len)
char			*xdata;
char			*buf;
int			*len;		/* Length returned	*/
int			max_len;	/* Maximum length allowed	*/
{
  int			i;
  int			val;
  t_boolean		first;
  int			xdata_len;
  
  xdata_len = strlen(xdata);
  (*len) = 0;
  first = FALSE;
  val = 0;
  i = 0;
  while (i < xdata_len)
    {
      if (isxdigit(xdata[i]))
        {
          if (first)
            {
              val += xdigit_value(xdata[i]);
              if ((*len) < max_len)
                {
                  buf[(*len)++] = val;
                  val = 0;
                }
              else
		return (ERR_MG_BO);
	      first = FALSE;
            }
          else
            {
              val = 16 * xdigit_value(xdata[i]);
              first = TRUE;
            }
        }
      else
        if (!isspace(xdata[i]))
          return (ERR_MG_SYNTAX);
      i++;
    }
  return (0);
}

/* converts-and-catenates a buffer to a xdata bridled str.
   This function performs the contrary of xdata_to_buf(3).
   Returns 0 or various errors including ERR_MG_BO. */
t_status		buf_to_xdata_str(buf,len,br,br_str,spc_str,str,max_len)
char			*buf;
int			len;
int			br;	/* Specifies when should a line break occurs */
char			*br_str;/* String used to caracterize a line break */
char			*spc_str;/* String used to caracterize a space */
char			*str;	/* Destination string */
int			max_len;/* Maximum length allowed */
{
  t_status		status;
  int			i;

  i = 0;
  while (i < len)
    {
      if ((status = str_cat_fmt_va(str,
				   max_len,
				   "%02x",
				   (unsigned char)buf[i])) != 0)
	return (status);
      if (((i + 1) % br) == 0)
	{
	  if ((status = str_cat_str(str,
				    max_len,
				    br_str)) != 0)
	    return (status);
	}
      else
	{
	  if ((status = str_cat_str(str,
				    max_len,
				    spc_str)) != 0)
	    return (status);
	}
      i++;
    }
  return (0);
}

/* converts-and-catenates a buffer to a printable bridled str.
   See buf_to_xdata_str(3). This function allows the user to
   specify the strings used for each ASCII character.
   Returns 0 or various errors including ERR_MG_BO. */
t_status		buf_to_printable_str(buf,
					     len,
					     br,
					     br_str,
					     spc_str,
					     nonprint_str,
					     ascii_vec,
					     str,
					     max_len)
char			*buf;
int			len;
int			br;
char			*br_str;
char			*spc_str;
char			*nonprint_str;	/* E.g. "."		*/
t_vec			*ascii_vec;	/* Vec_str of ascii representations */
char			*str;
int			max_len;
{
  t_status		status;
  int			i;

  i = 0;
  while (i < len)
    {
      if (isprint(buf[i]))
	{
	  if (ascii_vec)
	    {
	      if ((status = str_cat_str(str,
					max_len,
					(char *)(VEC_AT(ascii_vec,
							(int)(buf[i]))))) != 0)
		return (status);
	    }
	  else
	    {
	      if ((status = str_cat_char(str,
					 max_len,
					 buf[i])) != 0)
		return (status);
	    }
	}
      else
	{
	  if ((status = str_cat_str(str,
				    max_len,
				    nonprint_str)) != 0)
	    return (status);
	}
      if (((i + 1) % br) == 0)
	{
	  if ((status = str_cat_str(str,
				    max_len,
				    br_str)) != 0)
	    return (status);
	}
      else
	{
	  if ((status = str_cat_str(str,
				    max_len,
				    spc_str)) != 0)
	    return (status);
	}
      i++;
    }
  return (0);
}

t_status		buf_to_cooked_str_i(off,
					    b,
					    l,
					    br,
					    br_str,
					    spc_str,
					    big_spc_str,
					    nonprint_str,
					    ascii_vec,
					    str,
					    max_len)
int			off;
unsigned char		*b;
int			l;
int			br;
char			*br_str;
char			*spc_str;
char			*big_spc_str;
char			*nonprint_str;
t_vec			*ascii_vec;
char			*str;
int			max_len;
{
   int			i;
   t_status		status;

   if ((status = str_cat_fmt_va(str,
				max_len,
				"%08x%s",
				off - l,
				big_spc_str)) != 0)
     return (status);
   i = 0;
   while (i < br)
     {
       if (i < l)
	 {
	   if ((status = str_cat_fmt_va(str,
					max_len,
					"%02x",
					b[i])) != 0)
	     return (status);
	 }
       else
	 {
	   if ((status = str_cat_str(str,
				     max_len,
				     spc_str)) != 0)
	     return (status);
	   if ((status = str_cat_str(str,
				     max_len,
				     spc_str)) != 0)
	     return (status);
	 }
       if ((status = str_cat_str(str,
				 max_len,
				 spc_str)) != 0)
	 return (status);
       i++;
     }
   if ((status = str_cat_str(str,
			     max_len,
			     big_spc_str)) != 0)
     return (status);
   i = 0;
   while (i < l)
     {
       if (isprint(b[i]))
	 {
	   if (ascii_vec)
	     {
	       if ((status = str_cat_str(str,
					 max_len,
					 (char *)(VEC_AT(ascii_vec,
							 (int)(b[i]))))) != 0)
		 return (status);
	     }
	   else
	     {
	       if ((status = str_cat_char(str,
					  max_len,
					  b[i])) != 0)
		 return (status);
	     }
	 }
       else
	 {
	   if ((status = str_cat_str(str,
				     max_len,
				     nonprint_str)) != 0)
	     return (status);
	 }
       i++;
     }
   if ((status = str_cat_str(str,
			     max_len,
			     br_str)) != 0)
     return (status);
   return (0);
}

/* converts-and-catenates a buffer to a "ala-hexdump" representation.
   A "cooked str" is in the format:
   off <big_spc> xx0 <spc> xx1 <spc> ... xxn <big_spc> a0a1...an <br>
   Example (n = 8):
   00000000  00 00 00 41 00 00 00 00  ...A....
   00000008  00                       .
   Returns 0 or various errors including ERR_MG_BO. */
t_status		buf_to_cooked_str(buf,
					  len,
					  br,
					  br_str,
					  spc_str,
					  big_spc_str,
					  nonprint_str,
					  ascii_vec,
					  str,
					  max_len)
char			*buf;
int			len;
int			br;
char			*br_str;
char			*spc_str;
char			*big_spc_str;	/* Column space */
char			*nonprint_str;
t_vec			*ascii_vec;
char			*str;
int			max_len;
{
  unsigned char		b[BUFSIZ];
  int			i;
  int			l;
  t_status		status;

  if (br >= BUFSIZ)
    return (ERR_MG_INVAL);
  if (ascii_vec)
    if (VEC_COUNT(ascii_vec) != 256)
      return (ERR_MG_BAD_ASCII_VEC);
  l = 0;
  i = 0;
  while (i < len)
    {
      if (l < br)
	b[l++] = buf[i];
      else
	{
	  if ((status = buf_to_cooked_str_i(i,
					    b,
					    br,
					    br,
					    br_str,
					    spc_str,
					    big_spc_str,
					    nonprint_str,
					    ascii_vec,
					    str,
					    max_len)) != 0)
	    return (status);
	  l = 0;
	  b[l++] = buf[i];
	}
      i++;
    }
  if (l > 0)
    if ((status = buf_to_cooked_str_i(i,
				      b,
				      l,
				      br,
				      br_str,
				      spc_str,
				      big_spc_str,
				      nonprint_str,
				      ascii_vec,
				      str,
				      max_len)) != 0)
      return (status);
  return (0);
}

t_status		buf_to_str(buf,len,str,max_len)
char			*buf;
int			len;
char			*str;	/* Destination string */
int			max_len;/* Maximum length allowed */
{
  t_status		status;
  int			i;

  i = 0;
  while (i < len)
    {
      if ((status = str_cat_fmt_va(str,
				   max_len,
				   "%c",
				   (unsigned char)buf[i])) != 0)
	return (status);
      i++;
    }
  return (0);
}

t_status		str_to_buf(str,buf,len,max_len)
char			*str;
char			*buf;
int			*len;
int			max_len;
{
  int			i;

  (*len) = strlen(str);
  i = 0;
  while (i < *len)
    {
      if (i < max_len)
	{
	  buf[i] = str[i];
	}
      else
	return (ERR_MG_BO);
      i++;
    }
  return (0);
}
