xref: /original-bsd/sys/stand.att/printf.c (revision a088de5a)
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.5 (Berkeley) 05/05/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 #include <sys/types.h>
35 
36 /*
37  * Note that stdarg.h and the ANSI style va_start macro is used for both
38  * ANSI and traditional C compilers.
39  */
40 #define KERNEL
41 #include <machine/stdarg.h>
42 #undef KERNEL
43 
44 static void kprintn __P((u_long, int));
45 
46 void
47 #if __STDC__
48 printf(const char *fmt, ...)
49 #else
50 printf(fmt /* , va_alist */)
51 	char *fmt;
52 #endif
53 {
54 	register char *p;
55 	register int ch, n;
56 	unsigned long ul;
57 	int lflag, set;
58 	va_list ap;
59 
60 	va_start(ap, fmt);
61 	for (;;) {
62 		while ((ch = *fmt++) != '%') {
63 			if (ch == '\0')
64 				return;
65 			putchar(ch);
66 		}
67 		lflag = 0;
68 reswitch:	switch (ch = *fmt++) {
69 		case 'l':
70 			lflag = 1;
71 			goto reswitch;
72 		case 'b':
73 			ul = va_arg(ap, int);
74 			p = va_arg(ap, char *);
75 			kprintn(ul, *p++);
76 
77 			if (!ul)
78 				break;
79 
80 			for (set = 0; n = *p++;) {
81 				if (ul & (1 << (n - 1))) {
82 					putchar(set ? ',' : '<');
83 					for (; (n = *p) > ' '; ++p)
84 						putchar(n);
85 					set = 1;
86 				} else
87 					for (; *p > ' '; ++p);
88 			}
89 			if (set)
90 				putchar('>');
91 			break;
92 		case 'c':
93 			ch = va_arg(ap, int);
94 				putchar(ch & 0x7f);
95 			break;
96 		case 's':
97 			p = va_arg(ap, char *);
98 			while (ch = *p++)
99 				putchar(ch);
100 			break;
101 		case 'D':
102 			lflag = 1;
103 			/* FALLTHROUGH */
104 		case 'd':
105 			ul = lflag ?
106 			    va_arg(ap, long) : va_arg(ap, int);
107 			if ((long)ul < 0) {
108 				putchar('-');
109 				ul = -(long)ul;
110 			}
111 			kprintn(ul, 10);
112 			break;
113 		case 'O':
114 			lflag = 1;
115 			/* FALLTHROUGH */
116 		case 'o':
117 			ul = lflag ?
118 			    va_arg(ap, u_long) : va_arg(ap, u_int);
119 			kprintn(ul, 8);
120 			break;
121 		case 'U':
122 			lflag = 1;
123 			/* FALLTHROUGH */
124 		case 'u':
125 			ul = lflag ?
126 			    va_arg(ap, u_long) : va_arg(ap, u_int);
127 			kprintn(ul, 10);
128 			break;
129 		case 'X':
130 			lflag = 1;
131 			/* FALLTHROUGH */
132 		case 'x':
133 			ul = lflag ?
134 			    va_arg(ap, u_long) : va_arg(ap, u_int);
135 			kprintn(ul, 16);
136 			break;
137 		default:
138 			putchar('%');
139 			if (lflag)
140 				putchar('l');
141 			putchar(ch);
142 		}
143 	}
144 	va_end(ap);
145 }
146 
147 static void
148 kprintn(ul, base)
149 	unsigned long ul;
150 	int base;
151 {
152 					/* hold a long in base 8 */
153 	char *p, buf[(sizeof(long) * NBBY / 3) + 1];
154 
155 	p = buf;
156 	do {
157 		*p++ = "0123456789abcdef"[ul % base];
158 	} while (ul /= base);
159 	do {
160 		putchar(*--p);
161 	} while (p > buf);
162 }
163