/*- * Copyright (c) 1986, 1988, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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. * * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 * $FreeBSD: src/lib/libstand/printf.c,v 1.4 1999/12/27 08:45:14 peter Exp $ */ /* This file was scaled down a LOT from the original * * -- Brian */ #include #include int strlen(const char *str); static char *ksprintn (u4 num, int base, int *len, char *p); int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap); static const char h2a[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; static char hex2ascii(int c) { return h2a[c&0xf]; } int sprintf(char *buf, const char *cfmt, ...) { int retval; va_list ap; va_start(ap, cfmt); retval = kvprintf(cfmt, 0, (void *)buf, 10, ap); buf[retval] = '\0'; va_end(ap); return retval; } int vsprintf(char *buf, const char *cfmt, va_list ap) { int retval; retval = kvprintf(cfmt, 0, (void *)buf, 10, ap); buf[retval] = '\0'; return retval; } /* * Put a number (base <= 16) in a buffer in reverse order; return an * optional length and a pointer to the 0 terminated (preceded?) * buffer. */ #define NBBY 8 static char * ksprintn(u4 ul, int base, int *lenp, char *buf) { /* A long in base 8, plus 0. */ char *p; p = buf; *p = 0; do { *++p = hex2ascii(ul % base); } while (ul /= base); if (lenp) *lenp = p - buf; return (p); } /* * Scaled down version of printf(3). * * XXX: %D -- Hexdump, takes pointer and separator string: * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX * ("%*D", len, ptr, " " -> XX XX XX XX ... */ int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap) { #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } char *p, *q, *d; u1 *up; int ch, n; u4 ul; int base, tmp, width, ladjust, sharpflag, neg, sign, dot; int dwidth; char padc; int retval = 0; char buf[sizeof(long) * NBBY / 3 + 2]; if (!func) d = (char *) arg; else d = 0; if (fmt == 0) fmt = "(null)\n"; if (radix < 2 || radix > 36) radix = 10; for (;;) { padc = ' '; width = 0; while ((ch = (u1)*fmt++) != '%') { if (ch == '\0') return retval; PCHAR(ch); } ladjust = 0; sharpflag = 0; neg = 0; sign = 0; dot = 0; dwidth = 0; reswitch: switch (ch = (u1)*fmt++) { case '.': dot = 1; goto reswitch; case '#': sharpflag = 1; goto reswitch; case '+': sign = 1; goto reswitch; case '-': ladjust = 1; goto reswitch; case '%': PCHAR(ch); break; case '*': if (!dot) { width = va_arg(ap, int); if (width < 0) { ladjust = !ladjust; width = -width; } } else { dwidth = va_arg(ap, int); } goto reswitch; case '0': if (!dot) { padc = '0'; goto reswitch; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': for (n = 0;; ++fmt) { n = n * 10 + ch - '0'; ch = *fmt; if (ch < '0' || ch > '9') break; } if (dot) dwidth = n; else width = n; goto reswitch; case 'c': PCHAR(va_arg(ap, int)); break; case 'D': up = va_arg(ap, u1 *); p = va_arg(ap, char *); if (!width) width = 16; while(width--) { PCHAR(hex2ascii(*up >> 4)); PCHAR(hex2ascii(*up & 0x0f)); up++; if (width) for (q=p;*q;q++) PCHAR(*q); } break; case 'd': ul = va_arg(ap, int); sign = 1; base = 10; goto number; case 'n': ul = va_arg(ap, u4); base = radix; goto number; case 'o': ul = va_arg(ap, u4); base = 8; goto number; case 'p': ul = (u4)va_arg(ap, void *); base = 16; sharpflag = 1; goto number; case 's': p = va_arg(ap, char *); if (p == 0) p = "(null)"; if (!dot) n = strlen (p); else for (n = 0; n < dwidth && p[n]; n++) continue; width -= n; if (!ladjust && width > 0) while (width--) PCHAR(padc); while (n--) PCHAR(*p++); if (ladjust && width > 0) while (width--) PCHAR(padc); break; case 'u': ul = va_arg(ap, u4); base = 10; goto number; case 'x': ul = va_arg(ap, u4); base = 16; number: if (sign && (long)ul < 0L) { neg = 1; ul = -(long)ul; } p = ksprintn(ul, base, &tmp, buf); if (sharpflag && ul != 0) { if (base == 8) tmp++; else if (base == 16) tmp += 2; } if (neg) tmp++; if (!ladjust && width && (width -= tmp) > 0) while (width--) PCHAR(padc); if (neg) PCHAR('-'); if (sharpflag && ul != 0) { if (base == 8) { PCHAR('0'); } else if (base == 16) { PCHAR('0'); PCHAR('x'); } } while (*p) PCHAR(*p--); if (ladjust && width && (width -= tmp) > 0) while (width--) PCHAR(padc); break; default: PCHAR('%'); PCHAR(ch); break; } } #undef PCHAR }