xref: /csrg-svn/sys/stand.att/printf.c (revision 49118)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)printf.c	5.4 (Berkeley) 05/04/91
8  */
9 
10 /*
11  * Scaled down version of printf(3).
12  *
13  * One additional format:
14  *
15  * The format %b is supported to decode error registers.
16  * Its usage is:
17  *
18  *	printf("reg=%b\n", regval, "<base><arg>*");
19  *
20  * where <base> is the output base expressed as a control character, e.g.
21  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
22  * the first of which gives the bit number to be inspected (origin 1), and
23  * the next characters (up to a control character, i.e. a character <= 32),
24  * give the name of the register.  Thus:
25  *
26  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
27  *
28  * would produce output:
29  *
30  *	reg=3<BITTWO,BITONE>
31  */
32 
33 #include <sys/cdefs.h>
34 
35 /*
36  * Note that stdarg.h and the ANSI style va_start macro is used for both
37  * ANSI and traditional C compilers.
38  */
39 #define KERNEL
40 #include <machine/stdarg.h>
41 #undef KERNEL
42 
43 static void kprintn __P((u_long, int));
44 
45 void
46 #if __STDC__
47 printf(const char *fmt, ...)
48 #else
49 printf(fmt /* , va_alist */)
50 	char *fmt;
51 #endif
52 {
53 	register char *p;
54 	register int ch, n;
55 	unsigned long ul;
56 	int lflag, set;
57 	va_list ap;
58 
59 	va_start(ap, fmt);
60 	for (;;) {
61 		while ((ch = *fmt++) != '%') {
62 			if (ch == '\0')
63 				return;
64 			putchar(ch);
65 		}
66 		lflag = 0;
67 reswitch:	switch (ch = *fmt++) {
68 		case 'l':
69 			lflag = 1;
70 			goto reswitch;
71 		case 'b':
72 			ul = va_arg(ap, int);
73 			p = va_arg(ap, char *);
74 			kprintn(ul, *p++);
75 
76 			if (!ul)
77 				break;
78 
79 			for (set = 0; n = *p++;) {
80 				if (ul & (1 << (n - 1))) {
81 					putchar(set ? ',' : '<');
82 					for (; (n = *p) > ' '; ++p)
83 						putchar(n);
84 					set = 1;
85 				} else
86 					for (; *p > ' '; ++p);
87 			}
88 			if (set)
89 				putchar('>');
90 			break;
91 		case 'c':
92 			ch = va_arg(ap, int);
93 				putchar(ch & 0x7f);
94 			break;
95 		case 's':
96 			p = va_arg(ap, char *);
97 			while (ch = *p++)
98 				putchar(ch);
99 			break;
100 		case 'D':
101 			lflag = 1;
102 			/* FALLTHROUGH */
103 		case 'd':
104 			ul = lflag ?
105 			    va_arg(ap, long) : va_arg(ap, int);
106 			if ((long)ul < 0) {
107 				putchar('-');
108 				ul = -(long)ul;
109 			}
110 			kprintn(ul, 10);
111 			break;
112 		case 'O':
113 			lflag = 1;
114 			/* FALLTHROUGH */
115 		case 'o':
116 			ul = lflag ?
117 			    va_arg(ap, u_long) : va_arg(ap, u_int);
118 			kprintn(ul, 8);
119 			break;
120 		case 'U':
121 			lflag = 1;
122 			/* FALLTHROUGH */
123 		case 'u':
124 			ul = lflag ?
125 			    va_arg(ap, u_long) : va_arg(ap, u_int);
126 			kprintn(ul, 10);
127 			break;
128 		case 'X':
129 			lflag = 1;
130 			/* FALLTHROUGH */
131 		case 'x':
132 			ul = lflag ?
133 			    va_arg(ap, u_long) : va_arg(ap, u_int);
134 			kprintn(ul, 16);
135 			break;
136 		default:
137 			putchar('%');
138 			if (lflag)
139 				putchar('l');
140 			putchar(ch);
141 		}
142 	}
143 	va_end(ap);
144 }
145 
146 static void
147 kprintn(ul, base)
148 	unsigned long ul;
149 	int base;
150 {
151 	char *p, buf[11];			/* hold 2^32 in base 8 */
152 
153 	p = buf;
154 	do {
155 		*p++ = "0123456789abcdef"[ul % base];
156 	} while (ul /= base);
157 	do {
158 		putchar(*--p);
159 	} while (p > buf);
160 }
161