mirror of
https://github.com/tildeclub/ex-vi.git
synced 2026-06-15 01:10:17 +00:00
Initial revision
This commit is contained in:
440
printf.c
Normal file
440
printf.c
Normal file
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user