home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 4
/
DATAFILE_PDCD4.iso
/
unix
/
unixlib36d
/
src
/
stdio
/
c
/
print
< prev
next >
Wrap
Text File
|
1994-03-08
|
18KB
|
1,046 lines
static char sccs_id[] = "@(#) print.c 3.3 " __DATE__ " HJR";
/* print.c (c) Copyright 1990 H.Rogers */
/* Implements __printf(buf,format,argp) which is called by
* all printf() functions to perform formatted output. */
/* A conversion is of the form "%[flags][width][.prec][size]function".
* For full details RTFM for printf(3). */
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
__STDIOLIB__
/* To avoid truncation PRBUFSIZ should be 256+.
* This library will *not* buffer overflow unless PRBUFSIZ < 4.
* ANSI requires at least 509 - 512 sounds sensible (SJC). */
#define PRBUFSIZ 4096
/* The floating point functions are the most efficient they can be without
* resorting to assuming IEEE 'D' or some other internal representation. */
/* Unfortunately most software FP units are *inaccurate* - it
* is probably worth changing these constants for architectures
* with built in hardware FP units - make MAXPREC larger &
* FPERR smaller for higher quality. Note that MAXPREC = 16
* corresponds to the limits of IEEE Packed Decimal format. */
#define MAXPREC 16 /* max. decimal precision for %feEgG */
#define FPERR 1e-14 /* cutoff value for zero test */
/* It's probably best to leave POINT alone... It works. */
#define POINT 0.01 /* offset to compensate for rounding errors */
/* the prototypes for the output functions */
static char *__p_nout (char *, va_list *);
static char *__p_char (char *, va_list *);
static char *__p_str (char *, va_list *);
static char *__p_sdec (char *, va_list *);
static char *__p_uoct (char *, va_list *);
static char *__p_udec (char *, va_list *);
static char *__p_uhex (char *, va_list *);
static char *__p_ffix (char *, va_list *);
static char *__p_fexp (char *, va_list *);
static char *__p_fmin (char *, va_list *);
static char *__p_ptr (char *, va_list *);
/* the buffer __prpad has to be prior to __prbuf in memory -
* __prjust() avoids having to do any buffer copying by being
* able to back into the __prpad area from __prbuf */
static char __prpad[(PRBUFSIZ << 1) + 2];
static char *__prbuf = __prpad + PRBUFSIZ + 1;
/* __prebuf is set to the start of the output buffer passed to __printf() and
* is used by __p_nout() to calculate the number of characters output */
static char *__prebuf;
#define P_FLAG0 0x0001 /* '-' */
#define P_FLAG1 0x0002 /* '0' */
#define P_FLAG2 0x0004 /* '+' */
#define P_FLAG3 0x0008 /* ' ' */
#define P_FLAG4 0x0010 /* '#' */
#define P_FLAG5 0x0020 /* 'h' */
#define P_FLAG6 0x0040 /* 'l' */
#define P_FLAG7 0x0080 /* 'L' */
static int __prflag;
static unsigned int __prwidth; /* width */
static int __prprec; /* -1 = unspecified; precision */
static char __prfc; /* function character */
static signed char __prfnc[32] = /* conversions */
{
-1, -1,
1, /* %c */
3, /* %d */
9, /* %eE */
8, /* %f */
10, /* %gG */
-1,
4, /* %i */
-1, -1, -1, -1,
0, /* %n */
5, /* %o */
11, /* %p */
-1, -1,
2, /* %s */
-1,
6, /* %u */
-1, -1,
7, /* %xX */
-1, -1, -1, -1, -1, -1, -1, -1
};
/* __prfn[] is the array of output functions called by __printf() -
* they return a pointer to the end of the string (which is *not*
* necessarily 0 terminated) */
static char *(*__prfn[]) (char *, va_list *) =
{
__p_nout, /* %n no. of characters output so far */
__p_char, /* %c character */
__p_str, /* %s string */
__p_sdec, /* %d signed decimal */
__p_sdec, /* %i signed decimal */
__p_uoct, /* %o unsigned octal */
__p_udec, /* %u unsigned decimal */
__p_uhex, /* %xX unsigned hex */
__p_ffix, /* %f fixed notation double */
__p_fexp, /* %eE exponential notation double */
__p_fmin, /* %gG minimised space notation double */
__p_ptr /* %p unsigned hex value of pointer */
};
/* __printf() */
int
__printf (char *buf, const char *format, va_list ap)
{
register const char *s1 = format;
register char *s2 = buf;
__prebuf = buf; /* for __p_nout() */
while (*s1)
{
if (*s1 != '%' || *++s1 == '%') /* left to right evaluation */
{
*s2++ = *s1++;
continue;
}
{ /* we now have a % conversion */
register int i;
char *s;
/* looking for "%[flags][width][.prec][size]function" */
/* set flags */
__prflag = 0;
flag:
if (*s1 == '-')
{
__prflag |= P_FLAG0, s1++;
goto flag;
}
if (*s1 == '0')
{
__prflag |= P_FLAG1, s1++;
goto flag;
}
if (*s1 == '+')
{
__prflag |= P_FLAG2, s1++;
goto flag;
}
if (*s1 == ' ')
{
__prflag |= P_FLAG3, s1++;
goto flag;
}
if (*s1 == '#')
{
__prflag |= P_FLAG4, s1++;
goto flag;
}
/* set __prwidth */
__prwidth = 0;
if (isdigit (*s1))
{
__prwidth = (unsigned int) strtoul (s1, &s, 0);
s1 = s;
}
else
{
if (*s1 == '*')
{
__prwidth = va_arg (ap, int);
s1++;
}
}
if (__prwidth > PRBUFSIZ)
__prwidth = PRBUFSIZ;
/* set __prprec */
__prprec = -1;
if (*s1 == '.')
{
s1++;
if (isdigit (*s1))
{
__prprec = (int) strtol (s1, &s, 0);
s1 = s;
}
else
{
if (*s1 == '*')
{
__prprec = va_arg (ap, int);
s1++;
}
}
}
/* set size */
if (*s1 == 'h')
__prflag |= P_FLAG5, s1++;
else if (*s1 == 'l')
__prflag |= P_FLAG6, s1++;
else if (*s1 == 'L')
__prflag |= P_FLAG7, s1++;
/* call appropriate output function */
i = __prfnc[(_tolower (*s1) - 'a') & 31];
if (i >= 0)
{
__prfc = *s1;
s2 = (*__prfn[i]) (s2, (va_list *) (&ap));
}
s1++;
}
}
*s2 = 0;
return ((size_t) (s2 - buf)); /* number of characters output */
}
/* __prjust() */
/* __prjust() justifies the string at __prbuf according to __prwidth etc.
* it's argument is the *end* of the string at __prbuf - it returns the
* start of the justified string. */
static char *
__prjust (register char *e)
{
register char *s1, *s2;
register char p;
s1 = __prbuf;
p = (__prflag & P_FLAG1) ? '0' : ' ';
if (__prflag & P_FLAG0)
{
s2 = s1 + __prwidth;
while (e < s2)
*e++ = ' ';
*e = 0;
return (s1);
}
else
{
if ((e -= __prwidth) < s1)
{
s2 = e;
while (e < s1)
*e++ = p;
return (s2);
}
return (s1);
}
}
/* __prdec() */
/* __prdec() is a subroutine (called by __p_...() functions) that writes
* a decimal number <x> backwards from <e> towards <b>, digit by digit */
static char *
__prdec (register char *b, register char *e, register unsigned int x)
{
*e = 0;
do
{
*--e = (x % 10) + '0';
x /= 10;
}
while (x && e > b);
return (e);
}
/* __prexp() */
/* __prexp() normalises <x> to a number of the form n.nnnn...
* and stores the exponent in *<e> */
static double
__prexp (register double x, register int *e)
{
register int h;
h = 0;
if (x != 0)
{
if (x >= 10)
{
register double l = 0, m = 10;
while (x >= m)
{
l = m, m *= 10;
h++;
}
if (l)
x /= l;
}
else
{
while (x < 1)
{
x *= 10;
h--;
}
}
}
/* x is now n.nnnn... */
*e = h;
return (x);
}
/* __p_nout() */
static char *
__p_nout (register char *s, register va_list * ap) /* %n */
{
if (__prflag & P_FLAG5)
*va_arg (*ap, short *) = (short) (s - __prebuf);
else if (__prflag & P_FLAG6)
*va_arg (*ap, long *) = (long) (s - __prebuf);
else
*va_arg (*ap, int *) = (int) (s - __prebuf);
return (s);
}
/* __p_char() */
static char *
__p_char (register char *s, register va_list * ap) /* %c */
{
register char *b;
if (!__prwidth)
*s++ = va_arg (*ap, char);
else
{
b = __prbuf;
*b++ = va_arg (*ap, char);
*b = 0;
b = __prjust (b);
while (*s = *b)
s++, b++;
}
return (s);
}
/* __p_str() */
static char *
__p_str (register char *s, register va_list * ap) /* %s */
{
register char *_s;
register char *b, *e;
register int p;
p = (__prprec < 0) ? 0 : __prprec;
if (p > PRBUFSIZ)
p = PRBUFSIZ;
_s = va_arg (*ap, char *);
/* tolerance */
if (!