/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by Mike Parker.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#include <vax/mtpr.h>
#include <vax/cons.h>

char *panicstr = 0;
char coutbuf[1024];
char cinbuf[1024];
#define XOFF '\23'
#define XON '\21'
int cxoff = 0;
int coutfill = 0;
int coutput = 0;
int coutget = 0;
int cinfill = 0;
int cinput = 0;
int cinget = 0;

ctxint()
{
 int s;
 int c;

 s = splhigh();
 if (! (mfpr(TXCS) & TXCS_RDY))
  { splx(s);
    return;
  }
 if (cxoff || (coutfill == 0))
  { splx(s);
    return;
  }
 c = 0x7f & (int)coutbuf[coutget];
 coutget = (coutget + 1) % sizeof(coutbuf);
 coutfill --;
 mtpr(TXDB,c);
 splx(s);
 return;
}

crxint()
{
 int s;
 int c;

 s = splhigh();
 if (! (mfpr(RXCS) & RXCS_DONE))
  { splx(s);
    return;
  }
 c = 0x7f & mfpr(RXDB);
 if (c == XOFF)
  { cxoff = 1;
  }
 else if (c == XON)
  { cxoff = 0;
    ctxint();
  }
 else if (cinfill >= sizeof(cinbuf))
  { while (! (mfpr(TXCS) & TXCS_RDY)) ;
    mtpr(TXDB,7);
  }
 else
  { cinbuf[cinput] = c;
    cinput = (cinput + 1) % sizeof(cinbuf);
    cinfill ++;
  }
 splx(s);
 return;
}

consflush()
{
 while (coutfill > 0)
  { ctxint();
  }
}

consputs(s)
char *s;
{
 for (;*s;s++)
  { consputchar(*s);
  }
}

consputchar(c)
char c;
{
 if (c == '\n')
  { consputchar_('\r');
  }
 consputchar_(c);
}

consputchar_(c)
char c;
{
 int s;

 s = splhigh();
 if (panicstr || (s >= 0x14))
  { while (coutfill > 0)
     { ctxint();
       crxint();
     }
  }
 while (coutfill >= sizeof(coutbuf))
  { splx(s);
    splhigh();
  }
 coutbuf[coutput] = c;
 coutput = (coutput + 1) % sizeof(coutbuf);
 coutfill ++;
 ctxint();
 if (panicstr || (s >= 0x14))
  { while (coutfill > 0)
     { ctxint();
       crxint();
     }
  }
 splx(s);
}

consgetchar()
{
 int s;
 int c;

 s = splhigh();
 if (panicstr || (s >= 0x14))
  { while (cinfill <= 0) crxint();
  }
 if (cinfill > 0)
  { c = cinbuf[cinget];
    cinget = (cinget + 1) % sizeof(cinbuf);
    cinfill --;
  }
 else
  { while (cinfill == 0)
     { splx(s);
       splhigh();
     }
    c = cinbuf[cinget];
    cinget = (cinget + 1) % sizeof(cinbuf);
    cinfill --;
  }
 splx(s);
 return(0x7f&c);
}

printf(fmt,firstarg)
char *fmt;
int firstarg;
{
 _print(fmt,(char *)&firstarg,consputchar);
}

#define ALL 0x7fffffff

_print(fmt,ap,outfxn)
char *fmt;
char *ap;
int (*outfxn)();
{
 char *fp;
 int atleft;
 char signstyle;
 int width;
 int prec;
 int afterdot;
 char padc;
 char buf[20];

 fp = fmt;
 while (*fp)
  { if (*fp != '%')
     { (*outfxn)(*fp);
       fp ++;
       continue;
     }
    atleft = 0;
    signstyle = '-';
    width = 0;
    prec = ALL;
    afterdot = 0;
    padc = ' ';
    while (1)
     { switch (*++fp)
	{ default:
	     panic("bad printf %% specifier\n");
	     break;
	  case '\0':
	     break;
	  case '0': case '1': case '2': case '3': case '4':
	  case '5': case '6': case '7': case '8': case '9':
	     if (afterdot)
	      { prec = (prec * 10) + (*fp - '0');
	      }
	     else
	      { if ((width == 0) && (*fp == '0'))
		 { padc = '0';
		 }
		width = (width * 10) + (*fp - '0');
	      }
	     continue;
	     break;
	  case '-':
	     atleft = 1;
	     continue;
	     break;
	  case '+':
	     signstyle = '+';
	     continue;
	     break;
	  case ' ':
	     if (signstyle != '+')
	      { signstyle = ' ';
	      }
	     continue;
	     break;
	  case '.':
	     afterdot = 1;
	     prec = 0;
	     continue;
	     break;
	  case '%':
	     printpad(atleft,padc,width,ALL,"%",outfxn);
	     break;
	  case 'c':
	     buf[0] = * (char *) ap;
	     ap += 4;
	     buf[1] = '\0';
	     printpad(atleft,padc,width,ALL,buf,outfxn);
	     break;
	  case 'd':
	     cvtnumber(*(int *)ap,signstyle,10,buf);
	     ap += 4;
	     printpad(atleft,padc,width,ALL,buf,outfxn);
	     break;
	  case 'o':
	     cvtnumber(*(int *)ap,'u',8,buf);
	     ap += 4;
	     printpad(atleft,padc,width,ALL,buf,outfxn);
	     break;
	  case 's':
	     printpad(atleft,padc,width,prec,*(char **)ap,outfxn);
	     ap += 4;
	     break;
	  case 'u':
	     cvtnumber(*(int *)ap,'u',10,buf);
	     ap += 4;
	     printpad(atleft,padc,width,ALL,buf,outfxn);
	     break;
	  case 'x':
	     cvtnumber(*(int *)ap,'u',16,buf);
	     ap += 4;
	     printpad(atleft,padc,width,ALL,buf,outfxn);
	     break;
	}
       break;
     }
    if (*fp)
     { fp ++;
     }
    continue;
  }
}

cvtnumber(n,signtype,base,buf)
int n;
char signtype;
int base;
char *buf;
{
 static char *digits = "0123456789abcdef";
 char cvtbuf[20];
 char *cbp;
 char *bp;
 int i;

 bp = buf;
 i = n;
 if ((signtype != 'u') && (n < 0))
  { *bp++ = '-';
    i = - n;
    if (i == n)
     { switch (base)
	{ case 8:
	     strcpy(cvtbuf,"20000000000");
	     break;
	  case 10:
	     strcpy(cvtbuf,"2147483648");
	     break;
	  case 16:
	     strcpy(cvtbuf,"80000000");
	     break;
	  default:
	     strcpy(cvtbuf,"????");
	     break;
	}
       cbp = cvtbuf;
       goto formatted;
     }
    signtype = '-';
  }
 switch (signtype)
  { case '+':
       *bp++ = '+';
       break;
    case ' ':
       *bp++ = ' ';
       break;
  }
 cbp = cvtbuf + sizeof(cvtbuf);
 *--cbp = '\0';
 if (i < 0)
  { *--cbp = digits[((unsigned int)i)%base];
    i = ((unsigned int)i) / base;
  }
 do
  { *--cbp = digits[i%base];
    i /= base;
  } while (i);
formatted:
 while (*cbp)
  { *bp++ = *cbp++;
  }
 *bp++ = '\0';
}

printpad(atleft,padc,width,maxn,str,outfxn)
int atleft;
char padc;
int width;
int maxn;
char *str;
int (*outfxn)();
{
 int len;

 len = strlen(str);
 if (len > maxn)
  { len = maxn;
  }
 if (! atleft)
  { while (width > len)
     { (*outfxn)(padc);
       width --;
     }
  }
 for (;len>0;len--,width--)
  { (*outfxn)(*str++);
  }
 while (width > len)
  { (*outfxn)(padc);
    width --;
  }
}
