/*
 *	KPRINTF -- "kernel" formatted print routines for DeSmet C
 *
 *	Copyright 1985 by John McNamee.
 *	This software may be freely copied for non-commercial use.
 *	Commercial use requires the written permission of the author.
 *
 *		John McNamee
 *		7560 McLaren Ave.
 *		Canoga Park, CA 91307
 *
 *		CompuServe: 70235,1345
 *		Usenet: decvax!philabs!sbcs!bnl!jpm
 *		Internet: jpm@BNL.ARPA
 */

/*
 *			Overview of this package:
 *
 * kprintf() and ksprintf() should act exactly like printf and sprintf, except
 * they don't do floating point. The idea is to avoid bringing in the floating
 * point and file handling library routines that get loaded every time the
 * normal printf or sprintf are called. My routines add less than 2K to
 * program size, while normal printf adds over 6K. Of course, if you are going
 * to do file I/O or floating point you mind as well use the normal routines.
 * These functions are for writing programs programs that wouldn't otherwise
 * bring in all that code.
 *
 * I'm sure this code could be made smaller and faster. This was done "quick
 * and dirty" and I don't want to hear from anybody about bad coding style.
 * This really should be written in assembly language, but who has the time?
 */

/*
 *	Notes on converting to something other than DeSmet C:
 *
 * It shouldn't be too hard to move these routines to another C compiler.
 * The main thing you will have to do is check if calling putchar() brings
 * in the whole file I/O library of your compiler. It doesn't on DeSmet.
 * If yours does, write something that does tha same thing (its just a simple
 * call to MSDOS), and use it instead of putchar in the kprintf() function.
 */

/* "FAST" is the type that produces the fastest local variables. */
/* It is normally "register", but Intel chips are very braindamaged and */
/* don't have enough registers, so you must use "static". */
#define FAST register

static int left_flag, do_padding, num1, num2;
static char outbuf[32], *sp_ptr, pad_character;
static int wrow,wcol,wstart,wend;

/*
 *	Print on terminal
 */

extern int _row1,_row2,_col1,_col2,_attr,g_row,g_col,g_fore,g_back;
#include <ctype.h>
wprintf(ctrl, args)
char *ctrl, *args;
{
	int putachar();

	jzgetcur(&wrow,&wcol,&wstart,&wend);
	doprint(putachar, ctrl, &args);
}

store_chr(ch)
int ch;
{
	*sp_ptr++ = ch;
}

/*
 *	Generalized routine
 */

static doprint(outfunc, ctrl, argp)
int (*outfunc)();
char *ctrl, *argp;
{
	FAST int long_flag;
	FAST char *cp, ch;
	FAST int dot_flag;

	for (;*ctrl;ctrl++) {
		if (*ctrl!='%') {
			(*outfunc)(*ctrl);
			continue;
		}
		dot_flag=long_flag=left_flag=do_padding=0;
		num2=32767;
		pad_character=' ';

try_next:	ch = *(++ctrl);

		if (isdigit(ch)) {
			if (dot_flag)
				num2=getnum(&ctrl);
			else {
				if (ch=='0')
					pad_character='0';
				num1=getnum(&ctrl);
				do_padding=1;
			}
			ctrl--;
			goto try_next;
		}

		switch (tolower(ch)) {
		case 0:
			return;
		case '%':
			(*outfunc)('%');
			continue;
		case '-':
			left_flag=1;
			break;
		case '.':
			dot_flag=1;
			break;
		case 'l':
			long_flag=1;
			break;
		case 'd':
			if (long_flag || ch=='D') {
				outnum(outfunc, *((long *)argp), 10L);
				argp+=sizeof(long);
				continue;
			} else {
				outnum(outfunc, (long)(*((int *)argp)), 10L);
				argp+=sizeof(int);
				continue;
			}
		case 'x':
			if (long_flag || ch=='X') {
				outnum(outfunc, *((long *)argp), 16L);
				argp+=sizeof(long);
				continue;
			} else {
				outnum(outfunc, (long)(*((int *)argp)), 16L);
				argp+=sizeof(int);
				continue;
			}
		case 'o':
			if (long_flag || ch=='X') {
				outnum(outfunc, *((long *)argp), 8L);
				argp+=sizeof(long);
				continue;
			} else {
				outnum(outfunc, (long)(*((int *)argp)), 8L);
				argp+=sizeof(int);
				continue;
			}
		case 's':
			outs(outfunc, *((char **)argp));
			argp+=sizeof(char *);
			continue;
		case 'c':
			(*outfunc)(*((int *)argp));
			argp+=sizeof(int);
			continue;
		case 'f':
		case 'e':
		case 'g':
			do_padding=0;
			num2=32767;
			outs(outfunc, "*No floating point in kprintf!*");
			continue;
		default:
			continue;
		}
		goto try_next;
	}
}

/*
 *	Function used to output a line
 */

static outs(outfunc, lp)
int (*outfunc)();
char *lp;
{
	FAST int i, len;

	/* Blank pad on left if needed */
	if (do_padding && !left_flag && (len=strlen(lp))<num1)
		for (i=len; i<num1; i++)
			(*outfunc)(pad_character);

	/* Now output string */
	while (*lp && num2--)
		(*outfunc)(*lp++);

	/* Blank pad on right if needed */
	if (do_padding && left_flag && (len=strlen(lp))<num1)
		for (i=len; i<num1; i++)
			(*outfunc)(pad_character);
}

/*
 *	Output a number
 */

static outnum(outfunc, num, base)
int (*outfunc)();
long num, base;
{
	FAST char *cp;
	FAST int i, len, negative;
	static char digits[]="0123456789ABCDEF";

	/* Build number (backwards) in outbuf */
	if (num<0L) {
		negative = 1;
		num = -num;
	} else
		negative = 0;

	cp=outbuf;
	do {
		*cp++ = digits[num%base];
	} while ((num/=base) > 0);
	if (negative)
		*cp++ = '-';
	*cp-- = 0;
	len=strlen(outbuf);

	/* Blank pad on left if needed */
	if (do_padding && !left_flag && len<num1)
		for (i=len; i<num1; i++)
			(*outfunc)(pad_character);

	/* Now output the buffer in reverse order */
	while (cp>=outbuf)
		(*outfunc)(*cp--);

	/* Blank pad on right if needed */
	if (do_padding && left_flag && len<num1)
		for (i=len; i<num1; i++)
			(*outfunc)(pad_character);
}

/*
 *	Get a number from the control string.
 *
 *	This function takes a pointer to a character pointer (which it
 *	updates to point to the character after the end of the number)
 *	and returns an integer result.
 */

static getnum(linep)
char **linep;
{
	FAST int n;
	FAST char *cp;

	cp = *linep;
	n = 0;

	while (isdigit(*cp))
		n = n*10 + ((*cp++)-'0');

	*linep = cp;
	return(n);
}

static putachar(fch)
char fch;
{

  if (wcol > _col2) {
    wcol = _col1;
    if (wrow == _row2)
      jzscrlup(_row1 << 8 | _col1,_row2 << 8 | _col2,1,_attr);
    else
      ++ wrow;
  }

  if (fch) {
    jzwrtchr(fch,_attr,1);
    ++ wcol;
  }

  g_row=wrow;
  g_col=wcol;

  jzloccur(wrow,wcol);
}
