xref: /original-bsd/sys/stand/printf.c (revision 3705696b)
1 /*-
2  * Copyright (c) 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)printf.c	8.1 (Berkeley) 06/11/93
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 			ul = lflag ?
103 			    va_arg(ap, long) : va_arg(ap, int);
104 			if ((long)ul < 0) {
105 				putchar('-');
106 				ul = -(long)ul;
107 			}
108 			kprintn(ul, 10);
109 			break;
110 		case 'o':
111 			ul = lflag ?
112 			    va_arg(ap, u_long) : va_arg(ap, u_int);
113 			kprintn(ul, 8);
114 			break;
115 		case 'u':
116 			ul = lflag ?
117 			    va_arg(ap, u_long) : va_arg(ap, u_int);
118 			kprintn(ul, 10);
119 			break;
120 		case 'x':
121 			ul = lflag ?
122 			    va_arg(ap, u_long) : va_arg(ap, u_int);
123 			kprintn(ul, 16);
124 			break;
125 		default:
126 			putchar('%');
127 			if (lflag)
128 				putchar('l');
129 			putchar(ch);
130 		}
131 	}
132 	va_end(ap);
133 }
134 
135 static void
136 kprintn(ul, base)
137 	unsigned long ul;
138 	int base;
139 {
140 					/* hold a long in base 8 */
141 	char *p, buf[(sizeof(long) * NBBY / 3) + 1];
142 
143 	p = buf;
144 	do {
145 		*p++ = "0123456789abcdef"[ul % base];
146 	} while (ul /= base);
147 	do {
148 		putchar(*--p);
149 	} while (p > buf);
150 }
151