#ident "$Id: print.c,v 1.6 1997/10/22 21:52:23 gary Exp $"
/*****************************************************************************
 * Copyright (c) 1988-95 Digi International Inc., All Rights Reserved
 * 
 * This  software  contains  proprietary  and  confidential   information   of
 * Digi International  Inc.   By  accepting  transfer  of this copy, Recipient
 * agrees to retain this software in  confidence,  to  prevent  disclosure  to
 * others,  and  to make no  use of this software other than that for which it
 * was delivered.  This is an unpublished copyright work  Digi   International
 * Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is
 * strictly prohibited.
 * 
 * Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc.
 * Confidential  when   combined   with   the   aggregated  modules  for  this
 * product) OBJECT CODE ONLY SOURCE MATERIALS
 * 
 * (C) COPYRIGHT Digi International Inc. 1995
 * 
 * All Rights Reserved
 * 
 * US   Government   Users   Restricted   Rights   -   Use,   duplication   or
 * disclosure  restricted by GSA ADP Schedule Contract with Digi International
 * Inc.
 * 
 *****************************************************************************/


/*
 *  PRINT.C
 */

/*
 *	 /projects/common/PBRAIN/SCCS/pbrainF/dev/embed/common/71/s.print.c
 *	@(#)print.c	1.2
 *
 *	Last delta created	14:47:11 2/3/92
 *	This file extracted	12:55:09 10/29/92
 *
 *	Modifications:
 *
 */

#include "stdarg.h"
#include "types.h"
#include "stream.h"

#ifdef OUTSTR
extern void outstr();
#endif /*OUTSTR*/

#ifdef	GAT
extern void trace();
#endif

#define PRINTBUFSZ 10000

char obuf[PRINTBUFSZ];
char *outp = obuf;

#ifndef SOH
int strlen(s)
char *s;
{
    register char *p = s;
    while (*p) p++;
    return p - s;
}
#endif

#if POWERPC
void dcacheflush() ;
#endif

static void putchar(char c)
{
    static int first_print = 1;

    if (first_print)
    {
        bzero(obuf, PRINTBUFSZ);
#if POWERPC
	dcacheflush(obuf, PRINTBUFSZ) ;
#endif
	/* Cache Flush */
        first_print = 0;
    }


    if (outp<obuf+(PRINTBUFSZ-1)) {

#if POWERPC
	 *outp = c;

	/* Cache Flush */
	dcacheflush(outp, 1) ;

	outp++ ;

#else
	*outp++ = c ;

#endif

    }
    else {
	bzero(obuf, PRINTBUFSZ);

#if POWERPC
	/* Cache Flush */
	dcacheflush(obuf, PRINTBUFSZ) ;
#endif

	outp = obuf;
    }
}

static void puts(s)
char *s;
{
    while (*s) putchar(*s++);
}

static int pow(a, b)
int a, b;
{
    int t = 1;

    while (b--) t = t * a;

    return t;
}

static void phex(num, n)
register unsigned int num, n;
{   /* output n hex digits from ms end of word num */
    static char hexes[]="0123456789abcdef";

    while(n) {
	putchar(hexes[(num/(pow(16, (n-1))))]);
	num %= pow(16, (n-1));
	n--;
    }
}

#ifndef SOH
void putdec(num, width, unsgn, zpad, left_justify)
int num, width, unsgn, zpad;
int left_justify;
{   /* output a (signed) decimal number with a minimum width, padding with */
    /* zeroes if requested */

    int neg, i;
    register unsigned unum = num;
    register char *cp;
    char buffer[6];

    neg = 0;
    if (!unsgn && (int)unum<0)
    {   /* num is signed negative */
	neg = 1;
	width--;		 /* to allow for the '-' sign */
	unum = -unum;
    }
    cp = buffer;
    i = 0;
    for (;;)
    {
	*cp++ = (unum%10) + '0';
	i++;
	if ((unum /= 10) == 0)
	    break;
    }
    if (zpad)
    {
	if (neg) putchar('-');
	while (width-- > i)
	    putchar('0');
    }
    else
    {
	if (! left_justify) {
	    while (width-- > i)
		putchar(' ');
	}

	if (neg) putchar('-');
    }
    width -= i ;

    while (i--)
	putchar(*(--cp));

    if (left_justify) {
	while (width-- > 0)
	    putchar(' ');
    }

}

#endif

static void putlong(num, width, zpad)
register long num;
int width, zpad;
{   /* output a signed long number with a minimum width, padding with */
    /* zeroes if requested */

    int neg,i;
    register char *cp;
    char buffer[12];

    neg = 0;
    if (num < 0)
    {
	neg = 1;
	num -= 2000000000l;
	if (num < 0)
	{
	    neg = 2;
	    num -= 1000000000l;
	}
    }
    cp = buffer;
    i = 0;
    for (;;)
    {
	*cp++ = ((char)num%10) + '0';
	i++;
	if ((num /= 10) == 0)
	    break;
    }
    if (neg != 0)
    {
	while (i < 10)
	{
	    *cp++ = '0';
	    i++;
	}
	*(cp-1) += (neg + 1);
    }
    if (zpad)
    {
	while (width-- > i)
	    putchar('0');
    }
    else
    {
	while (width-- > i)
	    putchar(' ');
    }
    while (i--)
	putchar(*(--cp));
}

static void puthstr(strptr,length)
register char *strptr;
register int length;
{ /* This routine will print 'length' hex bytes starting from    */
  /* strptr.							  */

    while (length--)
	phex(*strptr++<<8, 2);
}

static void puthex(num, width)
register unsigned num, width;
{   /* This routine will print a hex number. If the width parameter  */
    /* is zero then a four character hex number will be output with  */
    /* leading zeroes. If the width is not zero and is greater than  */
    /* the number of digits in the number then it is padded with     */
    /* leading zeroes. Otherwise (ie. width <= actual width) the     */
    /* actual width is used.					     */

    if ((width >= 8) || (width == 0) || (num > 16777215))
	phex(num, 8);
    else
	if ((width == 6) || (num > 65535))
	    phex(num, 6);
	else
    	    if ((width == 4) || (num > 4095))
		phex(num, 4);
	    else
		if ((width == 3) || (num > 255))
		    phex(num, 3);
		else
		    if ((width == 2) || (num > 15))
			phex(num, 2);
		    else
			phex(num, 1);
}


#ifndef SOH
printf(char const *format, ...)
{   /* This routine is a restricted form of the original printf.    */
    /* It, at the moment, handles %x, %c, %s, %d and %u. It allows  */
    /* a single digit before a 'd' or 'u' in the %d and %u options  */
    /* to denote the minimum field width. If the number to be print-*/
    /* ed has fewer digits than the minimum then it is padded with  */
    /* leading spaces. A digit before any of the other options is   */
    /* ignored.*/
    /* Now handles longs  and hex strings (%l %h )		  */

    va_list ap;
    int width;      /* Indicates the min width of decimal number */

    int negative ;
    int zero_fill ;

    va_start(ap, format);
#ifdef OUTSTR
    outp = obuf;
#endif /* OUTSTR */

    while (*format != '\0')
    {   /* until the end of the format string */
	if (*format != '%')
	{   /* just an ordinary character to be output */
	    putchar(*format++);
	}
	else
	{   /* may be the start of a descriptor or the % character */
	    /* If the next character is a digit then store as the  */
	    /* width for possible use if the next char is 'd'.   */

	    if (*++format == '-')
	    {
		negative = 1;
		++format;
	    }
	    else
		negative = 0;

	    if (*format-'0' < 10)
	    {   /* digit */

		/* Test for zero fill for decimals */
		zero_fill = (*format == '0');

		/* set up width and pass to next character */
		width = *format++ - '0';
		if (*format-'0' < 10)
		    width = (width * 10) + (*format++ - '0');
	    }
	    else
	    {   /* not digit */
		width     = 1 ;
		zero_fill = 0 ;
	    }

	    switch (*format)
	    { /* look at next character */
		case 'c' : putchar(va_arg(ap, unsigned long));
			   break;
		case 's' : {   /* string */
			       register char *s = va_arg(ap, char *);
			       width -= strlen(s);

			       if (negative) puts(s);
			       while (width-- > 0) putchar(' ');
			       if (!negative) puts(s);
			   }
			   break;
		case 'x' : puthex(va_arg(ap, unsigned long), width);
			   break;
		case 'd' : putdec(va_arg(ap, unsigned long), width, 0, zero_fill, negative);
			   break;
		case 'u' : putdec(va_arg(ap, unsigned long), width, 1, zero_fill, negative);
			   break;
		case 'l' : if (format[1]!='d') break;
			   format++;
			   putlong(va_arg(ap, long), width,0);
			   break;
		case 'h' : puthstr(va_arg(ap, char *), width);
			   break;
		case '%' : putchar('%');
			   break;
	    }
	    format++;
	}
    }
#ifdef	GAT
    *outp = 0;
#endif
    if (outp>obuf && *obuf)
#ifdef	GAT
    trace(obuf);
#else
	{
#ifdef OUTSTR
	outstr(obuf, outp);

	/* How's THIS for a line discipline!?? */
	if (outp[-1] == '\n')
	{
	    outp[-1] = '\r';
	    outstr(outp-1, outp);
	}
#else
	*outp++ = '\0';
#endif /*OUTSTR*/
	}
#endif
	va_end(ap);
}
#endif	/* SOH */
