2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
16 * Carnegie Mellon requests users of this software to return to
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
31 /* How irritating -- this boolean crap. */
34 typedef int boolean_t;
37 * Common code for printf et al.
39 * The calling routine typically takes a variable number of arguments,
40 * and passes the address of the first one. This implementation
41 * assumes a straightforward, stack implementation, aligned to the
42 * machine's wordsize. Increasing addresses are assumed to point to
43 * successive arguments (left-to-right), as is the case for a machine
44 * with a downward-growing stack with arguments pushed right-to-left.
46 * To write, for example, fprintf() using this routine, the code
48 * fprintf(fd, format, args)
52 * _doprnt(format, &args, fd);
55 * would suffice. (This example does not handle the fprintf's "return
56 * value" correctly, but who looks at the return value of fprintf
59 * This version implements the following printf features:
61 * %d decimal conversion
62 * %u unsigned conversion
63 * %x hexadecimal conversion
64 * %X hexadecimal conversion with capital letters
68 * %m.n field width, precision
69 * %-m.n left adjustment
71 * %*.* width and precision taken from arguments
73 * This version does not implement %f, %e, or %g. It accepts, but
74 * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
75 * work correctly on machines for which sizeof(long) != sizeof(int).
76 * It does not even parse %D, %O, or %U; you should be using %ld, %o and
77 * %lu if you mean long conversion.
79 * As mentioned, this version does not return any reasonable value.
81 * Permission is granted to use, modify, or propagate this code as
82 * long as this notice is incorporated.
84 * Steve Summit 3/25/87
88 * Added formats for decoding device registers:
90 * printf("reg = %b", regval, "<base><arg>*")
92 * where <base> is the output base expressed as a control character:
93 * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of
94 * characters, the first of which gives the bit number to be inspected
95 * (origin 1), and the rest (up to a control character (<= 32)) give the
96 * name of the register. Thus
97 * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
99 * reg = 3<BITTWO,BITONE>
101 * If the second character in <arg> is also a control character, it
102 * indicates the last bit of a bit field. In this case, printf will extract
103 * bits <1> to <2> and print it. Characters following the second control
104 * character are printed before the bit field.
105 * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
107 * reg = b<FIELD1=2,BITONE>
110 * Added for general use:
111 * # prefix for alternate format:
113 * leading 0 for octal
114 * + print '+' if positive
115 * blank print ' ' if positive
117 * z signed hexadecimal
119 * n unsigned, 'radix'
121 * D,U,O,Z same as corresponding lower-case versions
125 * Added ANSI %p for pointers. Output looks like 0x%08x.
129 * Added special for L4-use: %t format
131 * prints L4-threadids. standard format is "task.thread". Field-width
132 * may be specified with width-modifier. Padding begins with threadid,
133 * up to 2 chars, task-part follows.
136 * # surrounds output with square brackets []
137 * l prints the high and low part of a threadid
138 * fixed length for the dwords: 8 chars
139 * 0 as usual, padding after optional '['
142 * Jork Loeser 9/20/99
145 #define isdigit(d) ((d) >= '0' && (d) <= '9')
146 #define Ctod(c) ((c) - '0')
148 #define MAXBUF (sizeof(long int) * 8) /* enough for binary */
150 static char digs[] = "0123456789abcdef";
153 printnum(u, base, putc, putc_arg)
154 register unsigned long u; /* number to print */
159 char buf[MAXBUF]; /* build number here */
160 register char * p = &buf[MAXBUF-1];
163 *p-- = digs[u % base];
167 while (++p != &buf[MAXBUF])
168 (*putc)(putc_arg, *p);
171 boolean_t _doprnt_truncates = FALSE;
173 void _doprnt(fmt, args, radix, putc, putc_arg)
174 register const char *fmt;
176 int radix; /* default radix - for '%r' */
177 void (*putc)(); /* character output */
178 char *putc_arg; /* argument for putc */
188 boolean_t altfmt, truncate;
193 while (*fmt != '\0') {
195 (*putc)(putc_arg, *fmt++);
215 else if (*fmt == '-') {
219 else if (*fmt == '+') {
223 else if (*fmt == ' ') {
239 length = 10 * length + Ctod(*fmt++);
241 else if (*fmt == '*') {
242 length = va_arg(args, int);
255 prec = 10 * prec + Ctod(*fmt++);
257 else if (*fmt == '*') {
258 prec = va_arg(args, int);
278 u = va_arg(args, unsigned long);
279 p = va_arg(args, char *);
281 printnum(u, base, putc, putc_arg);
287 while ((i = *p++) != 0) {
288 /* NOTE: The '32' here is because ascii space */
295 (*putc)(putc_arg, ',');
297 (*putc)(putc_arg, '<');
301 for (; (c = *p) > 32; p++)
302 (*putc)(putc_arg, c);
303 printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
304 base, putc, putc_arg);
306 else if (u & (1<<(i-1))) {
308 (*putc)(putc_arg, ',');
310 (*putc)(putc_arg, '<');
313 for (; (c = *p) > 32; p++)
314 (*putc)(putc_arg, c);
322 (*putc)(putc_arg, '>');
327 c = va_arg(args, int);
328 (*putc)(putc_arg, c);
337 prec = 0x7fffffff; /* MAXINT */
339 p = va_arg(args, char *);
344 if (length > 0 && !ladjust) {
348 for (; *p != '\0' && n < prec; p++)
354 (*putc)(putc_arg, ' ');
365 (*putc)(putc_arg, *p++);
368 if (n < length && ladjust) {
370 (*putc)(putc_arg, ' ');
380 truncate = _doprnt_truncates;
386 truncate = _doprnt_truncates;
392 truncate = _doprnt_truncates;
401 * We do this instead of just setting altfmt to TRUE
402 * because we want 0 to have a 0x in front, and we want
403 * eight digits after the 0x -- not just 6.
405 (*putc)(putc_arg, '0');
406 (*putc)(putc_arg, 'x');
408 truncate = _doprnt_truncates;
414 truncate = _doprnt_truncates;
420 truncate = _doprnt_truncates;
426 truncate = _doprnt_truncates;
433 n = va_arg(args, long long);
435 n = va_arg(args, long);
438 sign_char = plus_sign;
448 u = va_arg(args, unsigned long long);
450 u = va_arg(args, unsigned long);
455 char buf[MAXBUF]; /* build number here */
456 register char * p = &buf[MAXBUF-1];
457 static char digits[] = "0123456789abcdef";
460 if (truncate) u = (long)((int)(u));
462 if (u != 0 && altfmt) {
470 *p-- = digits[u % base];
474 length -= (&buf[MAXBUF-1] - p);
478 length -= strlen(prefix);
480 if (padc == ' ' && !ladjust) {
481 /* blank padding goes before prefix */
482 while (--length >= 0)
483 (*putc)(putc_arg, ' ');
486 (*putc)(putc_arg, sign_char);
489 (*putc)(putc_arg, *prefix++);
491 /* zero padding goes after sign and prefix */
492 while (--length >= 0)
493 (*putc)(putc_arg, '0');
495 while (++p != &buf[MAXBUF])
496 (*putc)(putc_arg, *p);
499 while (--length >= 0)
500 (*putc)(putc_arg, ' ');
510 (*putc)(putc_arg, *fmt);