/*
** mg_printf.c for  in 
** 
** Made by vianney rancurel
** Login   <vianney@epita.fr>
** 
** Started on  Wed Aug 25 12:14:01 1999 vianney rancurel
** Last update Thu Oct 28 20:15:43 1999 
*/
#include "mg.h"

t_status	my_printf_char(proc,data,c)
t_printf_proc	proc;
VOID_PTR	data;
int		c;
{
  t_status	status;
  char		ch;

  ch = c;
  if (iscntrl(ch) && ch != '\n' && ch != '\t')
    {
      char	ctrl;
      
      ch = '@' + (ch & 0x1f);
      ctrl = '^';
      if ((status = proc(data,&ctrl,1)) != 0)
	return (status);
    }
  if ((status = proc(data,&ch,1)) != 0)
    return (status);
  return (0);
}

t_status	my_printf_str(proc,data,str)
t_printf_proc	proc;
VOID_PTR	data;
char		*str;
{
  t_status	status;

  while (*str)
    {
      if ((status = my_printf_char(proc,
				   data,
				   *str++)) != 0)
	return (status);
    }
  return (0);
}

t_status	my_printf_do_str(proc,data,value,ljust,len,zpad)
t_printf_proc	proc;
VOID_PTR	data;
char		*value;
int		ljust;
int		len;
int		zpad;
{
  int		padlen;
  int		strlen;
  t_status	status;

  if (value == NULL)
    return (ERR_MG_PRINTF_NULL);
  for (strlen = 0;value[strlen];++strlen);
  padlen = len - strlen;
  if (padlen < 0)
    padlen = 0;
  if (ljust) 
    padlen = -padlen;
  while (padlen > 0)
    {
      if ((status = my_printf_char(proc,
				   data,
				   ' ')) != 0)
	return (status);
      --padlen;
    }
  if ((status = my_printf_str(proc,
			      data,
			      value)) != 0)
    return (status);
  while (padlen < 0)
    {
      if ((status = my_printf_char(proc,
				   data,
				   ' ')) != 0)
	return (status);
      ++padlen;
    }
  return (0);
}

t_status	my_printf_do_num(proc,data,value,base,dosign,ljust,len,zpad)
t_printf_proc	proc;
VOID_PTR	data;
long		value;
int		base;
int		dosign;
int		ljust;
int		len;
int		zpad;
{
  int		signvalue;
  unsigned long	uvalue;
  char		convert[STR_BUFSIZ];
  int		place;
  int		padlen;
  int		caps;
  t_status	status;

  signvalue = place = padlen = caps = 0;
  uvalue = value;
  if (dosign)
    {
      if (value < 0)
	{
	  signvalue = '-';
	  uvalue = -value;
	}
    }
  if (base < 0)
    {
      caps = 1;
      base = -base;
    }
  do
    {
      convert[place++] = 
	(caps?"0123456789ABCDEF":"0123456789abcdef")[uvalue % (unsigned)base];
      uvalue = (uvalue / (unsigned)base);
    }
  while (uvalue);
  convert[place] = 0;
  padlen = len - place;
  if (padlen < 0)
    padlen = 0;
  if (ljust)
    padlen = -padlen;
  if (zpad && padlen > 0)
    {
      if (signvalue)
	{
	  if ((status = my_printf_char(proc,
				       data,
				       signvalue)) != 0)
	    return (status);
	  --padlen;
	  signvalue = 0;
	}
      while (padlen > 0)
	{
	  if ((status = my_printf_char(proc,
				       data,
				       zpad)) != 0)
	    return (status);
	  --padlen;
	}
    }
  while (padlen > 0)
    {
      if ((status = my_printf_char(proc,
				   data,
				   ' ')) != 0)
	return (status);
      --padlen;
    }
  if (signvalue)
    {
      if ((status = my_printf_char(proc,
				   data,
				   signvalue)) != 0)
	return (status);
    }
  while (place > 0)
    {
      if ((status = my_printf_char(proc,
				   data,
				   convert[--place])) != 0)
	return (status);
    }
  while (padlen < 0)
    {
      if ((status = my_printf_char(proc,
				   data,
				   ' ')) != 0)
	return (status);
      ++padlen;
    }
  return (0);
}

t_status		my_vprintf(proc,data,fmt,args)
t_printf_proc		proc;
VOID_PTR		data;
char			*fmt;
va_list			args;
{
  int			c;
  long			value;
  int			longflag;
  char			*strvalue;
  int			ljust;
  int			len;
  int			zpad;
  t_status		status;

  longflag = 0;
  while ((c = *fmt++))
    {
      switch (c)
	{
	case '%':
	  ljust = len = zpad = 0;
	nextchar:
	  c = *fmt++;
	  switch (c)
	    {
	    case 0:
	      return (ERR_MG_PRINTF_END);
	    case '-':
	      ljust = 1; 
	      goto nextchar;
	    case '0':
	      if (len == 0)
		zpad = '0';
	    case '1': case '2': case '3':
	    case '4': case '5': case '6':
	    case '7': case '8': case '9':
	      len = len * 10 + c - '0';
	      goto nextchar;
	    case 'l': 
	      longflag = 1;
	      goto nextchar;
	    case 'u': case 'U':
	      if (longflag)
		value = va_arg(args,long);
	      else 
		value = va_arg(args,int);
	      if ((status = my_printf_do_num(proc,
					     data,
					     value,
					     10,
					     0,
					     ljust,
					     len,
					     zpad)) != 0)
		return (status);
	      break;
	    case 'o': case 'O':
	      if (longflag)
		value = va_arg(args,long);
	      else
		value = va_arg(args,int);
	      if ((status = my_printf_do_num(proc,
					     data,
					     value,
					     8,
					     0,
					     ljust,
					     len,
					     zpad)) != 0)
		return (status);
	      break;
	    case 'd': case 'D':
	      if (longflag)
		value = va_arg(args,long);
	      else
		value = va_arg(args,int);
	      if ((status = my_printf_do_num(proc,
					     data,
					     value,
					     10,
					     1,
					     ljust,
					     len,
					     zpad)) != 0)
		return (status);
	      break;
	    case 'p':
	    case 'x':
	      if (longflag)
		value = va_arg(args,long);
	      else
		value = va_arg(args,int);
	      if ((status = my_printf_do_num(proc,
					     data,
					     value,
					     16,
					     0,
					     ljust,
					     len,
					     zpad)) != 0)
		return (status);
	      break;
	    case 'X':
	      if (longflag)
		value = va_arg(args,long);
	      else
		value = va_arg(args,int);
	      if ((status = my_printf_do_num(proc,
					     data,
					     value,
					     -16,
					     0,
					     ljust,
					     len,
					     zpad)) != 0)
		return (status);
	      break;
	    case 's':
	      strvalue = va_arg(args,char *);
	      if ((status = my_printf_do_str(proc,
					     data,
					     strvalue,
					     ljust,
					     len,
					     zpad)) != 0)
		return (status);
	      break;
	    case 'c':
	      c = va_arg(args,int);
	      if ((status = my_printf_char(proc,
					   data,
					   c)) != 0)
		return (status);
	      break;
	    case '%': 
	      if ((status = my_printf_char(proc,
					   data,
					   c)) != 0)
		return (status);
	      continue;
	    default:
	      return (ERR_MG_PRINTF_BAD_FMT);
	    }
	  longflag = 0;
	  break;
	default:
	  if ((status = my_printf_char(proc,
				       data,
				       c)) != 0)
	    return (status);
	  break;
	}
    }
  return (0);
}

#ifdef HAVE_STDARG_H
t_status		my_printf(t_printf_proc proc,
				  VOID_PTR data,
				  char *fmt,
				  ...)
#else
t_status		my_printf(proc,data,fmt,va_alist)
t_printf_proc		proc;
VOID_PTR		data;
char			*fmt;
va_dcl
#endif
{
  va_list		args;
  t_status		status;

#ifdef HAVE_STDARG_H
  va_start(args,fmt);
#else
  va_start(args);
  va_arg(args,t_printf_proc);
  va_arg(args,VOID_PTR);
  va_arg(args,char *);
#endif
  status = my_vprintf(proc,data,fmt,args);
  va_end(args);
  return (status);
}
