xref: /csrg-svn/sys/stand.att/printf.c (revision 48989)
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.3 (Berkeley) 05/03/91
8  */
9 
10 /*
11  * Scaled down version of printf(3).
12  *
13  * Used to print diagnostic information directly on the console tty.  Since
14  * it is not interrupt driven, all system activities are suspended.  Printf
15  * should not be used for chit-chat.
16  *
17  * One additional format: %b is supported to decode error registers.
18  * Its usage is:
19  *
20  *	printf("reg=%b\n", regval, "<base><arg>*");
21  *
22  * where <base> is the output base expressed as a control character, e.g.
23  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
24  * the first of which gives the bit number to be inspected (origin 1), and
25  * the next characters (up to a control character, i.e. a character <= 32),
26  * give the name of the register.  Thus:
27  *
28  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
29  *
30  * would produce output:
31  *
32  *	reg=3<BITTWO,BITONE>
33  */
34 
35 #if __STDC__
36 #include <stdarg.h>
37 #else
38 #include <varargs.h>
39 #endif
40 
41 static void abort(){}				/* Needed by stdarg macros. */
42 static void number();
43 
44 void
45 #if __STDC__
46 printf(const char *fmt, ...)
47 #else
48 printf(fmt, va_alist)
49 	char *fmt;
50         va_dcl
51 #endif
52 {
53 	register char *p;
54 	register int ch, n;
55 	unsigned long ul;
56 	int lflag, set;
57 
58 	va_list ap;
59 #if __STDC__
60 	va_start(ap, fmt);
61 #else
62 	va_start(ap);
63 #endif
64 	for (;;) {
65 		while ((ch = *fmt++) != '%') {
66 			if (ch == '\0')
67 				return;
68 			putchar(ch);
69 		}
70 		lflag = 0;
71 reswitch:	switch (ch = *fmt++) {
72 		case 'l':
73 			lflag = 1;
74 			goto reswitch;
75 		case 'b':
76 			ul = va_arg(ap, int);
77 			p = va_arg(ap, char *);
78 			number(ul, *p++);
79 
80 			if (!ul)
81 				break;
82 
83 			for (set = 0; n = *p++;) {
84 				if (ul & (1 << (n - 1))) {
85 					putchar(set ? ',' : '<');
86 					for (; (n = *p) > ' '; ++p)
87 						putchar(n);
88 					set = 1;
89 				} else
90 					for (; *p > ' '; ++p);
91 			}
92 			if (set)
93 				putchar('>');
94 			break;
95 		case 'c':
96 			ch = va_arg(ap, int);
97 				putchar(ch & 0x7f);
98 			break;
99 		case 's':
100 			p = va_arg(ap, char *);
101 			while (ch = *p++)
102 				putchar(ch);
103 			break;
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 			number(ul, 10);
112 			break;
113 		case 'o':
114 			ul = lflag ?
115 			    va_arg(ap, long) : va_arg(ap, unsigned int);
116 			number(ul, 8);
117 			break;
118 		case 'u':
119 			ul = lflag ?
120 			    va_arg(ap, long) : va_arg(ap, unsigned int);
121 			number(ul, 10);
122 			break;
123 		case 'x':
124 			ul = lflag ?
125 			    va_arg(ap, long) : va_arg(ap, unsigned int);
126 			number(ul, 16);
127 			break;
128 		default:
129 			putchar('%');
130 			if (lflag)
131 				putchar('l');
132 			putchar(ch);
133 		}
134 	}
135 	va_end(ap);
136 }
137 
138 static void
139 number(ul, base)
140 	unsigned long ul;
141 	int base;
142 {
143 	char *p, buf[11];			/* hold 2^32 in base 8 */
144 
145 	p = buf;
146 	do {
147 		*p++ = "0123456789abcdef"[ul % base];
148 	} while (ul /= base);
149 	do {
150 		putchar(*--p);
151 	} while (p > buf);
152 }
153