#include "fido.h"
#include <ascii.h>
#include "fidomem.h"
#include "proto.h"

/*
	printf() and all it's relatives:


printf		The usual, Control-C able
cprintf		Ditto, not Control-C able
mprintf		Modem printf
lprintf		Logfile
clprintf	Console/Logfile

puts		The usual, Control-C able
cputs		Ditto, not Control-C able
mputs		Modem puts
lputs		Logfile
clputs		Console/Logfile

sprintf()
_fspr()		The format engine; this handles the stringID Fido
		language file text system.

*/

#define MAXSTR 300	/* largest string we'll handle */

  printf(f) char *f; { char buf[MAXSTR]; _fspr(buf,&f);  puts(buf); }
 cprintf(f) char *f; { char buf[MAXSTR]; _fspr(buf,&f); cputs(buf); }
 mprintf(f) char *f; { char buf[MAXSTR]; _fspr(buf,&f); mputs(buf); }
 lprintf(f) char *f; { char buf[MAXSTR]; _fspr(buf,&f); lputs(buf); }
clprintf(f) char *f; { char buf[MAXSTR]; _fspr(buf,&f); clputs(buf); }

  puts(s) 
char *s; 
{ 
	while (*s) { 
		if (*s == 255) {
			 bdos(2,CR); bdos(2,LF); 

		} else bdos(2,*s); ++s;
	}
} 
 cputs(s) char *s; { while (*s) { if (*s == 255) { lconout(CR); lconout(LF); } else lconout(*s); ++s;} } 
 mputs(s) char *s; { while (*s) { if (*s == 255) { mconout(CR); mconout(LF); } else mconoutr(*s); ++s;} } 
clputs(s) char *s; { cputs(s); lputs(s); }
 lputs(s) char *s; { 
	while (*s && (cmtfile != -1)) { 
		if (*s == 255) {
			write(cmtfile,"\r\n",2);

		} else if (write(cmtfile,s,1) != 1) {
			close(cmtfile);
			cmtfile= -1;
			cprintf(SM+115,"FIDO.LOG");	/* "disk full" */
		}
		++s;
	}
}

sprintf(s,f)
char *s,*f;
{
	_fspr(s,&f);
}

#define B32MASK 0x7fffffff	/* strip the long int sign bit */

/*
Format string options:

	"%-0w.p,l{dux}"

		- 	left justified (else right)
		0 	left zero fill
		w 	field width
		,	comma separate 1000's
		l	long
		a	base 36
*/

char _spr_sepchar = ',';	/* 1000's seperator character */

/* Formatted string processor for printf() etc. Will only work on a Lattice
long data model. Gross. Plagiarized from Leor Zolman's STDLIB2
for BDS C 1.42. Brain Damage Software still lives on ...

This is gross, as it uses funny pointers instead of a structure. Oh well. Also,
it is dependent on a char being the same size as an int on the stack.

This handles either the Fido stringID junk or an explicit format string:

	printf(ID,args...);

		or

	printf(0,"format string",args...);

 */

_fspr(line,fmt)
char *line, **fmt;
{
char c, base, *sptr, *format, **s;
char lastc, sign, ljflag, zfflag, sepflag;
int width, *args;
int sizearg,islong;
long num;

unsigned li;			/* index into line, above */

char sb[MAXSTR];
char wb[32];			/* room for largest possible digit string */
unsigned si;			/* index to sb[] */
unsigned i,j,l;

long *longarg;
char **charstararg;

/* If the stringID is zero, then a literal format string follows, else
locate the format string. */

	format= *fmt++;				/* ID or format string */
	if (format == 0) format= (char *) *fmt++; /* if 0, a format follows, */
	else format= (char *)string((unsigned)format); /* else its a string ID */
	args = (int *)fmt;
	lastc= si= li= 0;			/* total output line length */

	while (c = *format++)
		if ((c == '%') && (lastc != '\\')) {
			si= 0;		/* output buffer index */
			ljflag = zfflag = sepflag= 0;

			if (*format == '-') {
				format++;
				ljflag++;
			 }

			if (*format == '0') zfflag++;	/* test for zero-fill */

			width = (isdigit(*format)) ? _gv2(&format) : 0;

			c= *format++;
			if (c == ',') {
				c= *format++;
				sepflag= 1;
			}
			longarg= (long *)args;
			charstararg= (char **)args;
			islong= 0;

			if (c == 'l') {			/* if long, */
				c= *format++;		/* skip the L, */
				sizearg= sizeof(long);	/* for bumping pointer */
				longarg= (long *)args;	/* force confusing typing */
				num= *longarg;		/* get the value, */
				islong= 1;

			} else {
				sizearg= sizeof(int);
				num= 0L + *args;
			}
			sign= '\0';
			switch(toupper(c)) {

				case 'D':
					if (num < 0L) {
						sign= '-';
						width--;
						num= 0L - num;
					}
				case 'U': base = 10; goto val;
				case 'X': base = 16; goto val;
				case 'O': base = 8; goto val;
				case 'A': base = 36; goto val;

/* _uspr() builds the plain digit string in wb, the Work Buffer. If using
comma formatting, then separators are added before the string is moved to
sb, the String Buffer. 

Since Lattice doesn't have an unsigned long, we can't have the hi bit set on
positive numbers. Flag overflow with a '*'. */

val:					if (islong) {
						if (num & ~B32MASK) sign= '*';
						num &= B32MASK;

					} else num &= 0x0000ffffL;

					_uspr(wb,&si,num,base);
					if ((si > 4) && sepflag) {
						l = si % 3;
						if (l == 0) l= 3;
/*
				si= raw string length
				wb= raw digit string (ie. "12345")
				sb= working string (ie. "12,345")
				l= 100's digits counter, MOD 3
				i= index into sb[]
				j= index into wb[]
*/
						for (i= j= 0; j < si;) {
							sb[i++]= wb[j++];
							if ((--l == 0) && (j < si))
								sb[i++]= _spr_sepchar;
							if (l <= 0) l= 3;
						}
						si= i;		/* see pad: */

					} else for (i= 0; i < si; i++) sb[i]= wb[i];
					width -= i;

					if (islong) args= (int *) ++longarg;
					else ++args;
					goto pad;

				case 'C':
					sb[si]= *(char *)args;
					if (si < MAXSTR) ++si;
					++args;
					width--;
					goto pad;

				case 'S':
					sptr = *(char **)args;
					args= (int *) ++charstararg;
					while (*sptr) {
						sb[si]= *sptr++;
						if (si < MAXSTR) ++si;
						width--;
					}

pad:					sb[si]= '\0';
					si= 0;
					if (! ljflag) {
						while (width-- > 0) {
							line[li]= (zfflag ? '0' : ' ');
							if (li < MAXSTR) ++li;
						}
					}
					if (sign) {
						line[li]= sign;
						if (li < MAXSTR) ++li;
					}
					while (sb[si]) {
						line[li]= sb[si++];
						if (li < MAXSTR) ++li;
					}

					if (ljflag) {
						while (width-- > 0) {
							line[li]= ' ';
							if (li < MAXSTR) ++li;
						}
					}
					break;

				 default:
					line[li]= c; if (li < MAXSTR) ++li; break;
			 }

		} else {
			lastc= c;		/* for next time through */
			line[li]= c;
			if (li < MAXSTR) ++li;
		}

	line[li]= '\0';
}

/*
	Internal routine used by "_spr" to perform ascii-
	to-decimal conversion and update an associated pointer:
*/

static int _gv2(sptr)
char **sptr;
{
int n;
	n = 0;
	while (isdigit(**sptr)) n = 10 * n + *(*sptr)++ - '0';
	return(n);
}

static char itoctbl[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

static _uspr(buff, buffi, n, base)
char buff[];
unsigned *buffi;
long n;
unsigned base;
{
unsigned length;

	if ((n < base) && (n >= 0L)) {
		buff[*buffi]= itoctbl[n];
		if (*buffi < MAXSTR) ++(*buffi);
		buff[*buffi]= '\0';
		return(1);
	}
	length = _uspr(buff, buffi, (long)(n / base), base);
	_uspr(buff, buffi, (long)(n % base), base);
	return (length + 1);
}
