File:  [DragonFly] / src / lib / libstand / printf.c
Revision 1.2: download - view: text, annotated - select for diffs
Tue Jun 17 04:26:51 2003 UTC (11 years, 4 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids.  Most
ids have been removed from !lint sections and moved into comment sections.

    1: /*-
    2:  * Copyright (c) 1986, 1988, 1991, 1993
    3:  *	The Regents of the University of California.  All rights reserved.
    4:  * (c) UNIX System Laboratories, Inc.
    5:  * All or some portions of this file are derived from material licensed
    6:  * to the University of California by American Telephone and Telegraph
    7:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
    8:  * the permission of UNIX System Laboratories, Inc.
    9:  *
   10:  * Redistribution and use in source and binary forms, with or without
   11:  * modification, are permitted provided that the following conditions
   12:  * are met:
   13:  * 1. Redistributions of source code must retain the above copyright
   14:  *    notice, this list of conditions and the following disclaimer.
   15:  * 2. Redistributions in binary form must reproduce the above copyright
   16:  *    notice, this list of conditions and the following disclaimer in the
   17:  *    documentation and/or other materials provided with the distribution.
   18:  * 3. All advertising materials mentioning features or use of this software
   19:  *    must display the following acknowledgement:
   20:  *	This product includes software developed by the University of
   21:  *	California, Berkeley and its contributors.
   22:  * 4. Neither the name of the University nor the names of its contributors
   23:  *    may be used to endorse or promote products derived from this software
   24:  *    without specific prior written permission.
   25:  *
   26:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   27:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   30:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36:  * SUCH DAMAGE.
   37:  *
   38:  *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
   39:  * $FreeBSD: src/lib/libstand/printf.c,v 1.4 1999/12/27 08:45:14 peter Exp $
   40:  * $DragonFly: src/lib/libstand/printf.c,v 1.2 2003/06/17 04:26:51 dillon Exp $
   41:  */
   42: 
   43: /*
   44:  * Standaloneified version of the FreeBSD kernel printf family.
   45:  */
   46: 
   47: #include <sys/types.h>
   48: #include <string.h>
   49: #include "stand.h"
   50: 
   51: /*
   52:  * Note that stdarg.h and the ANSI style va_start macro is used for both
   53:  * ANSI and traditional C compilers.
   54:  */
   55: #include <machine/stdarg.h>
   56: 
   57: static char	*ksprintn (u_long num, int base, int *len);
   58: static int	kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
   59: 
   60: int
   61: printf(const char *fmt, ...)
   62: {
   63: 	va_list ap;
   64: 	int retval;
   65: 
   66: 	va_start(ap, fmt);
   67: 	retval = kvprintf(fmt, putchar, NULL, 10, ap);
   68: 	va_end(ap);
   69: 	return retval;
   70: }
   71: 
   72: void
   73: vprintf(const char *fmt, va_list ap)
   74: {
   75: 
   76: 	kvprintf(fmt, putchar, NULL, 10, ap);
   77: }
   78: 
   79: int
   80: sprintf(char *buf, const char *cfmt, ...)
   81: {
   82: 	int retval;
   83: 	va_list ap;
   84: 
   85: 	va_start(ap, cfmt);
   86: 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
   87: 	buf[retval] = '\0';
   88: 	va_end(ap);
   89: 	return retval;
   90: }
   91: 
   92: void
   93: vsprintf(char *buf, const char *cfmt, va_list ap)
   94: {
   95: 	int	retval;
   96: 	
   97: 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
   98: 	buf[retval] = '\0';
   99: }
  100: 
  101: /*
  102:  * Put a number (base <= 16) in a buffer in reverse order; return an
  103:  * optional length and a pointer to the NULL terminated (preceded?)
  104:  * buffer.
  105:  */
  106: static char *
  107: ksprintn(ul, base, lenp)
  108: 	register u_long ul;
  109: 	register int base, *lenp;
  110: {					/* A long in base 8, plus NULL. */
  111: 	static char buf[sizeof(long) * NBBY / 3 + 2];
  112: 	register char *p;
  113: 
  114: 	p = buf;
  115: 	do {
  116: 		*++p = hex2ascii(ul % base);
  117: 	} while (ul /= base);
  118: 	if (lenp)
  119: 		*lenp = p - buf;
  120: 	return (p);
  121: }
  122: 
  123: /*
  124:  * Scaled down version of printf(3).
  125:  *
  126:  * Two additional formats:
  127:  *
  128:  * The format %b is supported to decode error registers.
  129:  * Its usage is:
  130:  *
  131:  *	printf("reg=%b\n", regval, "<base><arg>*");
  132:  *
  133:  * where <base> is the output base expressed as a control character, e.g.
  134:  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
  135:  * the first of which gives the bit number to be inspected (origin 1), and
  136:  * the next characters (up to a control character, i.e. a character <= 32),
  137:  * give the name of the register.  Thus:
  138:  *
  139:  *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
  140:  *
  141:  * would produce output:
  142:  *
  143:  *	reg=3<BITTWO,BITONE>
  144:  *
  145:  * XXX:  %D  -- Hexdump, takes pointer and separator string:
  146:  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
  147:  *		("%*D", len, ptr, " " -> XX XX XX XX ...
  148:  */
  149: static int
  150: kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
  151: {
  152: #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
  153: 	char *p, *q, *d;
  154: 	u_char *up;
  155: 	int ch, n;
  156: 	u_long ul;
  157: 	int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
  158: 	int dwidth;
  159: 	char padc;
  160: 	int retval = 0;
  161: 
  162: 	if (!func)
  163: 		d = (char *) arg;
  164: 	else
  165: 		d = NULL;
  166: 
  167: 	if (fmt == NULL)
  168: 		fmt = "(fmt null)\n";
  169: 
  170: 	if (radix < 2 || radix > 36)
  171: 		radix = 10;
  172: 
  173: 	for (;;) {
  174: 		padc = ' ';
  175: 		width = 0;
  176: 		while ((ch = (u_char)*fmt++) != '%') {
  177: 			if (ch == '\0') 
  178: 				return retval;
  179: 			PCHAR(ch);
  180: 		}
  181: 		lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
  182: 		sign = 0; dot = 0; dwidth = 0;
  183: reswitch:	switch (ch = (u_char)*fmt++) {
  184: 		case '.':
  185: 			dot = 1;
  186: 			goto reswitch;
  187: 		case '#':
  188: 			sharpflag = 1;
  189: 			goto reswitch;
  190: 		case '+':
  191: 			sign = 1;
  192: 			goto reswitch;
  193: 		case '-':
  194: 			ladjust = 1;
  195: 			goto reswitch;
  196: 		case '%':
  197: 			PCHAR(ch);
  198: 			break;
  199: 		case '*':
  200: 			if (!dot) {
  201: 				width = va_arg(ap, int);
  202: 				if (width < 0) {
  203: 					ladjust = !ladjust;
  204: 					width = -width;
  205: 				}
  206: 			} else {
  207: 				dwidth = va_arg(ap, int);
  208: 			}
  209: 			goto reswitch;
  210: 		case '0':
  211: 			if (!dot) {
  212: 				padc = '0';
  213: 				goto reswitch;
  214: 			}
  215: 		case '1': case '2': case '3': case '4':
  216: 		case '5': case '6': case '7': case '8': case '9':
  217: 				for (n = 0;; ++fmt) {
  218: 					n = n * 10 + ch - '0';
  219: 					ch = *fmt;
  220: 					if (ch < '0' || ch > '9')
  221: 						break;
  222: 				}
  223: 			if (dot)
  224: 				dwidth = n;
  225: 			else
  226: 				width = n;
  227: 			goto reswitch;
  228: 		case 'b':
  229: 			ul = va_arg(ap, int);
  230: 			p = va_arg(ap, char *);
  231: 			for (q = ksprintn(ul, *p++, NULL); *q;)
  232: 				PCHAR(*q--);
  233: 
  234: 			if (!ul)
  235: 				break;
  236: 
  237: 			for (tmp = 0; *p;) {
  238: 				n = *p++;
  239: 				if (ul & (1 << (n - 1))) {
  240: 					PCHAR(tmp ? ',' : '<');
  241: 					for (; (n = *p) > ' '; ++p)
  242: 						PCHAR(n);
  243: 					tmp = 1;
  244: 				} else
  245: 					for (; *p > ' '; ++p)
  246: 						continue;
  247: 			}
  248: 			if (tmp)
  249: 				PCHAR('>');
  250: 			break;
  251: 		case 'c':
  252: 			PCHAR(va_arg(ap, int));
  253: 			break;
  254: 		case 'D':
  255: 			up = va_arg(ap, u_char *);
  256: 			p = va_arg(ap, char *);
  257: 			if (!width)
  258: 				width = 16;
  259: 			while(width--) {
  260: 				PCHAR(hex2ascii(*up >> 4));
  261: 				PCHAR(hex2ascii(*up & 0x0f));
  262: 				up++;
  263: 				if (width)
  264: 					for (q=p;*q;q++)
  265: 						PCHAR(*q);
  266: 			}
  267: 			break;
  268: 		case 'd':
  269: 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
  270: 			sign = 1;
  271: 			base = 10;
  272: 			goto number;
  273: 		case 'l':
  274: 			lflag = 1;
  275: 			goto reswitch;
  276: 		case 'n':
  277: 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
  278: 			base = radix;
  279: 			goto number;
  280: 		case 'o':
  281: 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
  282: 			base = 8;
  283: 			goto number;
  284: 		case 'p':
  285: 			ul = (u_long)va_arg(ap, void *);
  286: 			base = 16;
  287: 			sharpflag = 1;
  288: 			goto number;
  289: 		case 's':
  290: 			p = va_arg(ap, char *);
  291: 			if (p == NULL)
  292: 				p = "(null)";
  293: 			if (!dot)
  294: 				n = strlen (p);
  295: 			else
  296: 				for (n = 0; n < dwidth && p[n]; n++)
  297: 					continue;
  298: 
  299: 			width -= n;
  300: 
  301: 			if (!ladjust && width > 0)
  302: 				while (width--)
  303: 					PCHAR(padc);
  304: 			while (n--)
  305: 				PCHAR(*p++);
  306: 			if (ladjust && width > 0)
  307: 				while (width--)
  308: 					PCHAR(padc);
  309: 			break;
  310: 		case 'u':
  311: 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
  312: 			base = 10;
  313: 			goto number;
  314: 		case 'x':
  315: 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
  316: 			base = 16;
  317: number:			if (sign && (long)ul < 0L) {
  318: 				neg = 1;
  319: 				ul = -(long)ul;
  320: 			}
  321: 			p = ksprintn(ul, base, &tmp);
  322: 			if (sharpflag && ul != 0) {
  323: 				if (base == 8)
  324: 					tmp++;
  325: 				else if (base == 16)
  326: 					tmp += 2;
  327: 			}
  328: 			if (neg)
  329: 				tmp++;
  330: 
  331: 			if (!ladjust && width && (width -= tmp) > 0)
  332: 				while (width--)
  333: 					PCHAR(padc);
  334: 			if (neg)
  335: 				PCHAR('-');
  336: 			if (sharpflag && ul != 0) {
  337: 				if (base == 8) {
  338: 					PCHAR('0');
  339: 				} else if (base == 16) {
  340: 					PCHAR('0');
  341: 					PCHAR('x');
  342: 				}
  343: 			}
  344: 
  345: 			while (*p)
  346: 				PCHAR(*p--);
  347: 
  348: 			if (ladjust && width && (width -= tmp) > 0)
  349: 				while (width--)
  350: 					PCHAR(padc);
  351: 
  352: 			break;
  353: 		default:
  354: 			PCHAR('%');
  355: 			if (lflag)
  356: 				PCHAR('l');
  357: 			PCHAR(ch);
  358: 			break;
  359: 		}
  360: 	}
  361: #undef PCHAR
  362: }
  363: