/* vprintf replacement for Checker.
   Copyright 1993 Tristan Gingold
		  Written September 1993 Tristan Gingold

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 library 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; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address marc@david.saclay.cea.fr,
   or (US/French mail) as Tristan Gingold 
   			  8 rue Parmentier
   			  F91120 PALAISEAU
   			  FRANCE
*/

#include "config.h"   			     			
#include "malloc.h"
#include "chkrlib.h"
#include <stdarg.h>
#include "dmstrings.h"

int chkr_out = 2; 	/* File where all error are written. 2 is stderr */
static char buffer[2048];
static int Bindex=0;
static void add_to_buf(int sign, int base, int m_f, int size, unsigned int);
extern void check_output_spec(void);

void chkr_vprintf(const char *message, void **param)
{
 int i;
 int must_fill;
 int size;
 int len;
  
 Bindex = 0;
 len = strlen(message);
 for(i=0; i < len; i++)
 {
   if (message[i] != '%')
   {
     buffer[Bindex++] = message[i];
     continue;
   }
   i++;
   if (message[i] == '\0')
     continue;	/* forget the '%' at the end */
   if (message[i] == '%')
   {
     buffer[Bindex++] = '%';
     continue;
   }
   must_fill = 0;
   size = 0;
   if (message[i] == '0')
   {
     must_fill = 1;
     i++;
   }
   while (message[i] >= '0' && message[i] <= '9')
   {
     size *= 10;
     size += message[i++] - '0';
   }
   switch(message[i])
   {
     case 'd':
     	add_to_buf(0,10,must_fill,size,(int)*param);
     	param++;
     	break;
     case 'u':
     	add_to_buf(1,10,must_fill,size,(unsigned int)*param);
     	param++;
     	break;
     case 'p':
     case 'x':
        add_to_buf(0,16,must_fill,size,(unsigned int)*param);
        param++;
        break;
     case 's':
        if ((char*)*param == (char*)0)
          (char*)*param = "(null)";
        if(size == 0)
        {
          strcpy(&buffer[Bindex], (char*)*param);
          Bindex += strlen((char*)*param);
        }
        else
          if (must_fill)
          {
            memset(&buffer[Bindex], ' ', size);
     	    strncpy(&buffer[Bindex], (char*)*param, size);
     	    Bindex += size;
     	  }
     	  else
     	  {
     	    strncpy(&buffer[Bindex], (char*)*param, size);
     	    must_fill = strlen((char*)*param);
     	    Bindex += must_fill > size ? size : must_fill;
     	  }
     	param++;
     	break;
     default:
        break;
   }
 }
 buffer[Bindex] = '\0';
 (*__chkr_trap)(buffer);
} 	
     	
static void add_to_buf(int sign, int base, int m_f, int size, unsigned int p)
{
 static char buf[40];
 int ind=0;
 int digit;
 
 if(sign && (signed int)p < 0)
   p = abs((signed int)p);
 else
   sign = 0;
 
 while(p > 0)
 {
   digit = p % base;
   p /= base;
   if (digit < 10)
     buf[ind++] = '0' + digit;
   else
     buf[ind++] = 'a' + (digit - 10);
 }
 if(ind == 0)	/* special case for p = 0 */
   buf[ind++] = '0';
 if (m_f)
   for(; ind < size; ind++)
     buf[ind]= '0';
 if (sign)
     buf[ind++] = '-';
 /* reverse copy to buffer */
 if (size > 0 && ind > size)
   ind = size;
 for(digit = ind -1; digit >= 0; digit--)
   buffer[Bindex++] = buf[digit];
}

void chkr_printf(const char *message, ...)
{
 va_list param;
 va_start(param,message);
 chkr_vprintf(message,param);
 va_end(param);
}

void chkr_header(const char *message)
{
  chkr_printf(M_FROM_CHECKER);
  chkr_printf(message);
}

void __default_chkr_trap(const char *message)
{
  check_output_spec();
  write(chkr_out, message, strlen(message)); 
}

void (*__chkr_trap) __P((const char *message)) =
			 __default_chkr_trap;
