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