#include <locore.h>
#include <bsp.h>
#include <common.h>
#include <kern.h>
#include <sem.h>
#include <string.h>


#define I_AM_UGLY

#ifdef I_AM_UGLY
#include <varargs.h>
#else
#include <stdarg.h>
#endif


#ifdef I_AM_UGLY

void do_printf(void (*do_putc) (char), va_list pvar ) 
{
  char *p;
  int ch;
  unsigned long ul;
  int base, lflag, tmp, width, upper;
  char padc;
  static char buffer[BUFSIZ];
  char *buf = buffer;
  int i, len;

  char *fmt;
  fmt = va_arg(pvar, char *);

  *buf = '\0';
  for (;;) {
    padc = ' ';
    width = 0;
    while ((ch = *(unsigned char *) fmt++) != '%') {
      if (ch == '\0') {
	*buf++ = '\0';
	goto kprintf_exit;
      }
      *buf++ = ch;
    }
    lflag = 0;
    upper 
= 0;

  reswitch:

    switch (ch = *(unsigned char *) fmt++) {
    case '0':
      padc = '0';
      goto reswitch;
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      for (width = 0;; ++fmt) {
	width = width * 10 + ch - '0';
	ch = *fmt;
	if (ch < '0' || ch > '9')
	  break;
      }
      goto reswitch;
    case '.':
      goto reswitch;
    case 'l':
      lflag = 1;
      goto reswitch;
    case 'c':
      *buf++ = va_arg(pvar, int);
      break;
    case '*':	/* only valid for 's' */
      if (*(unsigned char *) fmt != 's')
	panic("kprintf: we're too stupid");
      fmt++;
      width = va_arg(pvar, int);
      /* fall through to the 's' case */
    case 's':
      p = va_arg(pvar, char *);
      while ( (ch = *p++ ) ) {
	*buf++ = ch;
	if (width != 0 && --width == 0)
	  break;
      }
      while (width > 0) {
	width--;
	*buf++ = padc;
      }
      break;
    case 'd':
      ul = lflag ? va_arg(pvar, long) : va_arg(pvar, int);
      if ((long) ul < 0) {
	*buf++ = '-';
	ul = -(long) ul;
      }
      base = 10;
      goto number;
    case 'o':
      ul = lflag ? va_arg(pvar, long) : va_arg(pvar, u_int);
      base = 8;
      goto number;
    case 'u':
      ul = lflag ? va_arg(pvar, u_long) : va_arg(pvar, u_int);
      base = 10;
      goto number;
    case 'h':
      /* FALLTHROUGH */
    case 'H':
      if (*(buf - 1) != 'x' || *(buf - 1) != 'X' || *(buf - 2) != '0') {
	*buf++ = '0';
	*buf++ = ch == 'h' ? 'x' : 'X';
      }
      goto hex_print;
    case 'X':
      upper = 1;
      /* FALLTHROUGH */
    hex_print:
    case 'x':
      ul = lflag ? va_arg(pvar, u_long) : va_arg(pvar, u_int);
      base = 16;
    number:	
      p = ksprintn(ul, base, &tmp);
      if (width && (width -= tmp) > 0)
	while (width--)
	  *buf++ = padc;
      while ( (ch = *p--) )
	*buf++ = (upper ? toupper(ch) : ch);
      *buf = '\0';
      break;
    case '%':
      *buf++ = ch;
      break;
    default:
      panic("kprintf: we're too stupid");
      /* NOTREACHED */
    }
  }
 kprintf_exit:
  len = strlen(buffer);
  for (i = 0; i < len; i++)
    (*do_putc) (buffer[i]);
}


#else

void do_printf(void (*do_putc) (char), char * fmt , ... ) 
{
  char *p;
  int ch;
  unsigned long ul;
  int base, lflag, tmp, width, upper;
  char padc;
  static char buffer[BUFSIZ];
  char *buf = buffer;
  int i, len;

  va_list pvar;
  va_start( pvar , fmt );

  *buf = '\0';
  for (;;) {
    padc = ' ';
    width = 0;
    while ((ch = *(unsigned char *) fmt++) != '%') {
      if (ch == '\0') {
	*buf++ = '\0';
	goto kprintf_exit;
      }
      *buf++ = ch;
    }
    lflag = 0;
    upper 
= 0;

  reswitch:

    switch (ch = *(unsigned char *) fmt++) {
    case '0':
      padc = '0';
      goto reswitch;
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      for (width = 0;; ++fmt) {
	width = width * 10 + ch - '0';
	ch = *fmt;
	if (ch < '0' || ch > '9')
	  break;
      }
      goto reswitch;
    case '.':
      goto reswitch;
    case 'l':
      lflag = 1;
      goto reswitch;
    case 'c':
      *buf++ = va_arg(pvar, int);
      break;
    case '*':	/* only valid for 's' */
      if (*(unsigned char *) fmt != 's')
	panic("kprintf: we're too stupid");
      fmt++;
      width = va_arg(pvar, int);
      /* fall through to the 's' case */
    case 's':
      p = va_arg(pvar, char *);
      while ( (ch = *p++ ) ) {
	*buf++ = ch;
	if (width != 0 && --width == 0)
	  break;
      }
      while (width > 0) {
	width--;
	*buf++ = padc;
      }
      break;
    case 'd':
      ul = lflag ? va_arg(pvar, long) : va_arg(pvar, int);
      if ((long) ul < 0) {
	*buf++ = '-';
	ul = -(long) ul;
      }
      base = 10;
      goto number;
    case 'o':
      ul = lflag ? va_arg(pvar, long) : va_arg(pvar, u_int);
      base = 8;
      goto number;
    case 'u':
      ul = lflag ? va_arg(pvar, u_long) : va_arg(pvar, u_int);
      base = 10;
      goto number;
    case 'h':
      /* FALLTHROUGH */
    case 'H':
      if (*(buf - 1) != 'x' || *(buf - 1) != 'X' || *(buf - 2) != '0') {
	*buf++ = '0';
	*buf++ = ch == 'h' ? 'x' : 'X';
      }
      goto hex_print;
    case 'X':
      upper = 1;
      /* FALLTHROUGH */
    hex_print:
    case 'x':
      ul = lflag ? va_arg(pvar, u_long) : va_arg(pvar, u_int);
      base = 16;
    number:	
      p = ksprintn(ul, base, &tmp);
      if (width && (width -= tmp) > 0)
	while (width--)
	  *buf++ = padc;
      while ( (ch = *p--) )
	*buf++ = (upper ? toupper(ch) : ch);
      *buf = '\0';
      break;
    case '%':
      *buf++ = ch;
      break;
    default:
      panic("kprintf: we're too stupid");
      /* NOTREACHED */
    }
  }
 kprintf_exit:
  len = strlen(buffer);
  for (i = 0; i < len; i++)
    (*do_putc) (buffer[i]);

  va_end(pvar);

}

#endif /* I_AM_UGLY */
