Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/old/lib/printf.c
There are 9 other files named printf.c in the archive. Click here to see a list.
/* <KCC.LIB>PRINTF.C.31,  1-Aug-85 10:18:53, Edit by KRONJ */
/*  needed parens in __px */
/* <KCC.LIB>PRINTF.C.29, 27-Jun-85 12:09:26, Edit by KRONJ */
/*  hex output recursively calls itself (not octal) */
/*  rework to use _doprnt as in UNIX version */
/* <KCC.LIB>PRINTF.C.21,  2-Feb-85 16:11:44, Edit by SATZ */
/*  sprintf() returns its first argument */
/* <KCC.LIB>PRINTF.C.19,  7-Dec-84 22:26:18, Edit by SATZ */
/*  increase character strings which printf uses. shouldn't */
/*  restrict output to a single character string. */
/* <KCC.LIB>PRINTF.C.17, 14-Sep-84 08:08:10, Edit by KRONJ */
/*  give up on unsigned printout for a while (%u now synonym for %d) */
/*  use separate routines to print octal, hex (these are unsigned) */

/*
** printf.c - formatted output
** split from stdio.c, David Eppstein, 20-Jul-84
** reference is Kernighan and Ritchie, pages 145-147, 150, and 152
**
** Variable arguments are handled as follows:
**
** Each function calls a handler routine to do the common work,
** with a pointer to the first of the variable arguments.  Since
** arguments appear in reverse order on the stack, each argument
** can be found by referencing and auto-decrementing the passed
** argument pointer.
**
** This is not guaranteed to work for any compiler other than
** KCC.  A more general scheme is to increment by the difference
** between successive args, rather than merely subtracting one,
** but even that will not always work (e.g. for doubles).
*/

#include "c-env.h"

entry printf, sprintf, fprintf, _doprnt;
char *__pd(), *__po(), *__px();

#include <stdio.h>			/* this is part of standard I/O lib */
/*
** formatted output
*/

printf (format, args)
char *format;
{
    _doprnt (format, &args, stdout);
}


/*
** file formatted output
*/

fprintf (stream, format, args)
FILE *stream;
char *format;
{
    _doprnt (format, &args, stream);
}


/*
** in memory conversion
** done by hacking up a fake fd to point to the string
*/

char *
sprintf (s, format, args)
char *s, *format;
{
    FILE fd;				/* note no star */

    fd._cnt = 32767;			/* make room for a big string */
    fd._ptr = s;			/* output pointer is here */
    fd._flag = _IOWRT + _IOSTRG;	/* we're writing to a string */
    _doprnt (format, &args, &fd);	/* print to fake file descriptor */
    putc ('\0', &fd);			/* append a null to terminate */
    return s;				/* return pointer to start of string */
}
/*
** handler routine for all three forms of printf
** first arg is control string with % expressions in it
** second arg is pointer to first format argument
** third arg is stdio file descriptor to send output to
*/

_doprnt (format, args, stream)
char *format;
int *args;
FILE *stream;
{
    int ladjust, zfill, width, precision;
    char argbuf[100], *argptr, *s;

    while (1) {
	switch (*format) {
	case '\0':
	    return;
	case '%':
	    format++;
	    if (ladjust = (*format == '-')) format++;
	    if (zfill = (*format == '0')) format++;
	    width = 0;			/* initialize width */
   	    while (*format >= '0' && *format <= '9')
		width = width * 10 + *format++ - '0';
	    precision = -1;		/* no precision given */
	    if (*format == '.') {
		precision = 0;		/* precision given, initialize */
		while (*++format >= '0' && *format <= '9')
		    precision = precision * 10 + *format - '0';
	    }
	    if (*format == 'l') format++; /* ignore long modifier */

	    switch (*format) {
	    case 'c':
		argbuf[0] = *args--;	/* drop char in buffer */
		argbuf[1] = 0;		/* null terminate */
		argptr = argbuf;	/* buffer is where string is */
		break;

	    case 'd':
	    case 'u':
		__pd(argptr = argbuf, *args--); /* decimal */
		break;

	    case 'e':
		args--;			/* only take high order part */
		if (precision < 0) precision = 6; /* digits after point */
#if SYS_T20+SYS_10X
		_flout (argptr = argbuf, * (double *) args,
			(precision<<6)+025300010002);
#endif
		args--;
		break;

	    case 'f':
		args--;			/* point to whole thing */
		if (precision < 0) precision = 6; /* digits after point */
#if SYS_T20+SYS_10X
		_flout (argptr = argbuf, * (double *) args,
		        (precision<<6)+024300770000);
#endif
		args--;
		while (*argptr == ' ') argptr++;
		break;

	    case 'g':
		args--;
		if (precision < 0) precision = 6; /* digits after point */
#if SYS_T20+SYS_10X
		_flout (argptr = argbuf, * (double *) args,
		        (precision<<6)+025300000002);
#endif
		args--;
		break;

	    case 'o':
		__po(argptr = argbuf, *args--); /* octal */
		break;

	    case 's':
		argptr = (char *) *args--; /* get arg */
		if (precision > 0) {
		    s = argbuf;		/* get another ptr */
		    *s = *argptr;	/* copy first char */
		    while (--precision > 0) *++s = *++argptr; /* and rest */
		    *++s = 0;		/* null terminate for sure */
		    argptr = argbuf;	/* now point to start again */
		}
		break;

	    case 'x':
		__px (argptr = argbuf, *args--); /* hex */
		break;

	    default:
		argbuf[0] = *format;	/* just print char */
		argbuf[1] = 0;
		argptr = argbuf;	/* set that as our string */
		break;
	    }				/* end switch(*format) */
	    format++;			/* skip over format char */
	    s = argptr;			/* copy string pointer */
	    while (*s) {
		if (ladjust) putc (*s, stream);	/* send char off */
		s++;			/* skip over it */
		width--;		/* count off in string width */
	    }
	    while (width-- > 0) {	/* while have filler to make */
		if (!zfill) putc (' ', stream);	/* fill with space */
		else {			/* or if want fill with zeroes */ 
		    if (!ladjust && *argptr == '-') putc (*argptr++, stream);
		    putc ('0', stream);	/* float sign and add zero */
		}
	    }
	    if (!ladjust) while (*argptr) putc (*argptr++, stream);
	    break;

	default:
	    putc (*format++, stream);
	}
    }
}
/* ---------------------- */
/*	print number      */
/* ---------------------- */

static char *
__pd (s, n)
char *s;
{
    int q;

    q = n / 10;
    n %= 10;
    if (q) s = __pd(s, q);		/* high order digits */
    if (n < 0) {
	if (q == 0)
	    *s++ = '-';
	n = -n;
    }
    *s++ = n + '0';			/* bottom digit */
    *s = '\0';				/* null-terminate */
    return s;				/* return string for recursive call */
}

/* --------------- */
/*      octal      */
/* --------------- */

static char *
__po(s, n)
char *s;
{
    if (n &~ 07) s = __po(s, n >> 3);	/* do high order digits */
    *s++ = (n & 07) + '0';		/* bottom digit */
    *s = '\0';				/* null-terminate */
    return s;				/* pass back up for recursive call */
}

/* ------------- */
/*      hex      */
/* ------------- */

static char *
__px(s, n)
char *s;
{
    if (n &~ 0xF) s = __px(s, n >> 4);	/* do high order digits */
    if ((n & 0xF) <= 9) *s++ = (n & 0xF) + '0'; /* numeric bottom digit */
    else *s++ = (n & 0xF) - 10 + 'a';	/* alphabetic bottom digit */
    *s = '\0';				/* null-terminate */
    return s;				/* pass back up for recursive call */
}
/* Floating hack for T20+10X */

#if SYS_T20+SYS_10X
static _flout();			/* trick KCC to not emit EXTERN */

#asm
; *************************************************************
;	Floating point output
;	_flout(cp,num,fmt)
;	char *cp; double num; int fmt;
; *************************************************************
	SEARCH MONSYM
.flout:
	%CHRBP	1,-1(17)	;Pick up args
	DMOVE	2,-3(17)	;Double
	MOVE	4,-4(17)	;Format word
	DFOUT%			;Do floating point output
	 ERJMPA	$RETF		;Lost
	JRST	$RETT		;Won
#endasm
#endif /* T20+10X */