summaryrefslogtreecommitdiff
path: root/printf.c
diff options
context:
space:
mode:
Diffstat (limited to 'printf.c')
-rw-r--r--printf.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/printf.c b/printf.c
new file mode 100644
index 0000000..1c95186
--- /dev/null
+++ b/printf.c
@@ -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;
+}