Blame | Last modification | View Log | RSS feed
/*
* This code contains changes by
* Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
*
* Conditions 1, 2, and 4 and the no-warranty notice below apply
* to these changes.
*
*
* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* Redistributions of source code and documentation must retain the
* above copyright notice, this list of conditions and the following
* disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed or owned by Caldera
* International, Inc.
* Neither the name of Caldera International, Inc. nor the names of
* other contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
* INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
* LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lint
#ifdef DOSCCS
static char sccsid[] = "@(#)printf.c 1.15 (gritter) 12/1/04";
#endif
#endif
/* from printf.c 7.3 (Berkeley) 6/7/85 */
/* The pwb version this is based on */
/* from printf.c:2.2 6/5/79 */
#include "ex.h"
/*
* This version of printf is compatible with the Version 7 C
* printf. The differences are only minor except that this
* printf assumes it is to print through putchar. Version 7
* printf is more general (and is much larger) and includes
* provisions for floating point.
*/
static int width, sign, fill;
int vprintf(const char *, va_list);
char *p_dconv(long, char *);
static int p_emit(char *, char *);
int
printf(const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
int
vprintf(const char *fmt, va_list ap)
{
int cnt = 0;
int fcode;
int prec;
int length,mask1,nbits,n,m;
long int mask2, num;
register char *bptr;
char *ptr;
char buf[134];
for (;;) {
/* process format string first */
while (nextc(fcode,fmt,m), fmt+=m, fcode!='%') {
/* ordinary (non-%) character */
if (fcode=='\0')
return cnt;
putchar(fcode);
cnt += m;
}
/* length modifier: -1 for h, 1 for l, 0 for none */
length = 0;
/* check for a leading - sign */
sign = 0;
if (*fmt == '-') {
sign++;
fmt++;
}
/* a '0' may follow the - sign */
/* this is the requested fill character */
fill = 1;
if (*fmt == '0') {
fill--;
fmt++;
}
/* Now comes a digit string which may be a '*' */
if (*fmt == '*') {
width = va_arg(ap, int);
if (width < 0) {
width = -width;
sign = !sign;
}
fmt++;
}
else {
width = 0;
while (*fmt>='0' && *fmt<='9')
width = width * 10 + (*fmt++ - '0');
}
/* maybe a decimal point followed by more digits (or '*') */
if (*fmt=='.') {
if (*++fmt == '*') {
prec = va_arg(ap, int);
fmt++;
}
else {
prec = 0;
while (*fmt>='0' && *fmt<='9')
prec = prec * 10 + (*fmt++ - '0');
}
}
else
prec = -1;
/*
* At this point, "sign" is nonzero if there was
* a sign, "fill" is 0 if there was a leading
* zero and 1 otherwise, "width" and "prec"
* contain numbers corresponding to the digit
* strings before and after the decimal point,
* respectively, and "fmt" addresses the next
* character after the whole mess. If there was
* no decimal point, "prec" will be -1.
*/
switch (*fmt) {
case 'L':
case 'l':
length = 2;
/* no break!! */
case 'h':
case 'H':
length--;
fmt++;
break;
}
/*
* At exit from the following switch, we will
* emit the characters starting at "bptr" and
* ending at "ptr"-1, unless fcode is '\0'.
*/
switch (nextc(fcode, fmt, m), fmt += m, fcode) {
/* process characters and strings first */
case 'c':
buf[0] = va_arg(ap, int);
ptr = bptr = &buf[0];
if (buf[0] != '\0')
ptr++;
break;
case 's':
bptr = va_arg(ap,char *);
if (bptr==0)
bptr = catgets(catd, 1, 248,
"(null pointer)");
if (prec < 0)
prec = LRGINT;
for (n=0; *bptr++ && n < prec; n++) ;
ptr = --bptr;
bptr -= n;
break;
case 'O':
length = 1;
fcode = 'o';
/* no break */
case 'o':
case 'X':
case 'x':
if (length > 0)
num = va_arg(ap,long);
else
num = (unsigned)va_arg(ap,int);
if (fcode=='o') {
mask1 = 0x7;
mask2 = 0x1fffffffL;
nbits = 3;
}
else {
mask1 = 0xf;
mask2 = 0x0fffffffL;
nbits = 4;
}
n = (num!=0);
bptr = buf + MAXOCT + 3;
/* shift and mask for speed */
do
if (((int) num & mask1) < 10)
*--bptr = ((int) num & mask1) + 060;
else
*--bptr = ((int) num & mask1) + 0127;
while (num = (num >> nbits) & mask2);
if (fcode=='o') {
if (n)
*--bptr = '0';
}
else
if (!sign && fill <= 0) {
putchar('0');
putchar(fcode);
width -= 2;
}
else {
*--bptr = fcode;
*--bptr = '0';
}
ptr = buf + MAXOCT + 3;
break;
case 'D':
case 'U':
case 'I':
length = 1;
fcode = fcode + 'a' - 'A';
/* no break */
case 'd':
case 'i':
case 'u':
if (length > 0)
num = va_arg(ap,long);
else {
n = va_arg(ap,int);
if (fcode=='u')
num = (unsigned) n;
else
num = (long) n;
}
if (n = (fcode != 'u' && num < 0))
num = -num;
/* now convert to digits */
bptr = p_dconv(num, buf);
if (n)
*--bptr = '-';
if (fill == 0)
fill = -1;
ptr = buf + MAXDIGS + 1;
break;
default:
/* not a control character,
* print it.
*/
ptr = bptr = (char *)&fmt[-m];
ptr++;
break;
}
if (fcode != '\0')
cnt += p_emit(bptr,ptr);
}
}
/* p_dconv converts the unsigned long integer "value" to
* printable decimal and places it in "buffer", right-justified.
* The value returned is the address of the first non-zero character,
* or the address of the last character if all are zero.
* The result is NOT null terminated, and is MAXDIGS characters long,
* starting at buffer[1] (to allow for insertion of a sign).
*
* This program assumes it is running on 2's complement machine
* with reasonable overflow treatment.
*/
char *
p_dconv(long value, char *buffer)
{
register char *bp;
register int svalue;
int n;
long lval;
bp = buffer;
/* zero is a special case */
if (value == 0) {
bp += MAXDIGS;
*bp = '0';
return(bp);
}
/* develop the leading digit of the value in "n" */
n = 0;
while (value < 0) {
value -= BIG; /* will eventually underflow */
n++;
}
while (value >= BIG && (lval = value - BIG) >= 0) {
value = lval;
n++;
}
/* stash it in buffer[1] to allow for a sign */
bp[1] = n + '0';
/*
* Now develop the rest of the digits. Since speed counts here,
* we do it in two loops. The first gets "value" down until it
* is no larger than LRGINT. The second one uses integer divides
* rather than long divides to speed it up.
*/
bp += MAXDIGS + 1;
while (value > LRGINT) {
*--bp = (int)(value % 10) + '0';
value /= 10;
}
/* cannot lose precision */
svalue = value;
while (svalue > 0) {
*--bp = (svalue % 10) + '0';
svalue /= 10;
}
/* fill in intermediate zeroes if needed */
if (buffer[1] != '0') {
while (bp > buffer + 2)
*--bp = '0';
--bp;
}
return(bp);
}
/*
* This program sends string "s" to putchar. The character after
* the end of "s" is given by "send". This allows the size of the
* field to be computed; it is stored in "alen". "width" contains the
* user specified length. If width<alen, the width will be taken to
* be alen. "sign" is zero if the string is to be right-justified
* in the field, nonzero if it is to be left-justified. "fill" is
* 0 if the string is to be padded with '0', positive if it is to be
* padded with ' ', and negative if an initial '-' should appear before
* any padding in right-justification (to avoid printing "-3" as
* "000-3" where "-0003" was intended).
*/
static int
p_emit(register char *s, char *send)
{
char cfill;
register int alen;
int npad;
int cnt = 0;
int c, m;
alen = send - s;
if (alen > width)
width = alen;
cfill = fill>0? ' ': '0';
/* we may want to print a leading '-' before anything */
if (*s == '-' && fill < 0) {
putchar(*s++);
cnt++;
alen--;
width--;
}
npad = width - alen;
/* emit any leading pad characters */
if (!sign)
while (--npad >= 0) {
putchar(cfill);
cnt++;
}
/* emit the string itself */
while (--alen >= 0) {
nextc(c, s, m);
s += m;
putchar(c);
cnt += m;
alen -= m-1;
}
/* emit trailing pad characters */
if (sign)
while (--npad >= 0) {
putchar(cfill);
cnt++;
}
return cnt;
}