FreeBSD/Linux Kernel Cross Reference
sys/kern/printf.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993 Carnegie Mellon University
4 * All Rights Reserved.
5 *
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.
11 *
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.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: printf.c,v $
29 * Revision 2.16 93/11/17 17:17:30 dbg
30 * ANSI-fied. We now have stdarg.h!
31 * Moved iprintf to ddb/db_output.c, since it is only used
32 * by debugging print routines.
33 * [93/10/27 dbg]
34 *
35 * Revision 2.15 93/03/09 10:55:12 danner
36 * Lint to quiet GCC.
37 * [93/03/07 13:25:20 af]
38 *
39 * A better, MP-safe sprintf.
40 * [93/03/05 af]
41 *
42 * Revision 2.14 93/01/27 09:34:37 danner
43 * printf_init(), sprintf() are void.
44 * [93/01/25 jfriedl]
45 *
46 * Updated copyright.
47 * [93/01/12 berman]
48 * Wrote a version of sprintf() for general use.
49 * [92/03/18 berman]
50 *
51 * Revision 2.13 93/01/14 17:35:37 danner
52 * 64bit cleanup. Tuned up doprnt slightly.
53 * [92/12/01 af]
54 *
55 * Revision 2.12 92/08/03 17:38:32 jfriedl
56 * removed silly prototypes
57 * [92/08/02 jfriedl]
58 *
59 * Revision 2.11 92/05/21 17:14:57 jfriedl
60 * Cleanup to quiet gcc warnings.
61 * Changed PUTC arg of _doprnt, etc. to be VOID (which it is)
62 * [92/05/16 jfriedl]
63 *
64 * Revision 2.10 92/04/01 19:33:21 rpd
65 * Renamed gets to safe_gets.
66 * [92/03/31 rpd]
67 *
68 * Revision 2.9 91/06/06 17:07:22 jsb
69 * Added gets (derived from boot_gets).
70 * [91/05/14 09:18:50 jsb]
71 *
72 * Revision 2.8 91/05/14 16:44:59 mrt
73 * Correcting copyright
74 *
75 * Revision 2.7 91/02/05 17:28:14 mrt
76 * Changed to new Mach copyright
77 * [91/02/01 16:15:41 mrt]
78 *
79 * Revision 2.6 90/10/25 14:45:18 rwd
80 * Purged uprintf.
81 * [90/10/21 rpd]
82 *
83 * Revision 2.5 90/08/27 22:03:08 dbg
84 * Add extra formats to printf: '#- ' prefixes, %z (signed hex),
85 * %r and %n (signed and unsigned, current radix).
86 * [90/08/20 dbg]
87 *
88 * Revision 2.4 90/01/11 11:43:44 dbg
89 * De-linted.
90 * [90/01/03 dbg]
91 *
92 * Revision 2.3 89/11/29 14:09:06 af
93 * Ooops, a typo.
94 * [89/10/29 09:34:26 af]
95 *
96 * Changed the case for %c to load ints and not chars. Or
97 * else it is byte-order dependent since C passes char as ints.
98 * [89/10/13 af]
99 *
100 * Turned the unused 'file descriptor' field for _doprnt and putchar
101 * into a more useful pointer to an (optional) specialized putchar
102 * routine. This can be used, for instance, to divert debugging
103 * printouts to some specialized interface or IOP.
104 * [89/10/09 af]
105 *
106 * Revision 2.2 89/09/25 11:00:58 rwd
107 * Added case 'X' same as 'x' for now.
108 * [89/09/20 rwd]
109 *
110 * Revision 2.1 89/08/03 15:51:14 rwd
111 * Created.
112 *
113 * 8-Aug-88 David Golub (dbg) at Carnegie-Mellon University
114 * Converted for MACH kernel use. Removed %r, %R, %b; added %b
115 * from Berkeley's kernel to print bit fields in device registers;
116 * changed to use varargs.
117 *
118 */
119
120 /*
121 * Common code for printf et al.
122 *
123 * The calling routine typically takes a variable number of arguments,
124 * and passes the address of the first one. This implementation
125 * assumes a straightforward, stack implementation, aligned to the
126 * machine's wordsize. Increasing addresses are assumed to point to
127 * successive arguments (left-to-right), as is the case for a machine
128 * with a downward-growing stack with arguments pushed right-to-left.
129 *
130 * To write, for example, fprintf() using this routine, the code
131 *
132 * fprintf(fd, format, args)
133 * FILE *fd;
134 * char *format;
135 * {
136 * _doprnt(format, &args, fd);
137 * }
138 *
139 * would suffice. (This example does not handle the fprintf's "return
140 * value" correctly, but who looks at the return value of fprintf
141 * anyway?)
142 *
143 * This version implements the following printf features:
144 *
145 * %d decimal conversion
146 * %u unsigned conversion
147 * %x hexadecimal conversion
148 * %X hexadecimal conversion with capital letters
149 * %o octal conversion
150 * %c character
151 * %s string
152 * %m.n field width, precision
153 * %-m.n left adjustment
154 * %0m.n zero-padding
155 * %*.* width and precision taken from arguments
156 *
157 * This version does not implement %f, %e, or %g. It accepts, but
158 * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
159 * work correctly on machines for which sizeof(long) != sizeof(int).
160 * It does not even parse %D, %O, or %U; you should be using %ld, %o and
161 * %lu if you mean long conversion.
162 *
163 * As mentioned, this version does not return any reasonable value.
164 *
165 * Permission is granted to use, modify, or propagate this code as
166 * long as this notice is incorporated.
167 *
168 * Steve Summit 3/25/87
169 */
170
171 /*
172 * Added formats for decoding device registers:
173 *
174 * printf("reg = %b", regval, "<base><arg>*")
175 *
176 * where <base> is the output base expressed as a control character:
177 * i.e. '\1' gives octal, '\2' gives hex. Each <arg> is a sequence of
178 * characters, the first of which gives the bit number to be inspected
179 * (origin 1), and the rest (up to a control character (<= 32)) give the
180 * name of the register. Thus
181 * printf("reg = %b\n", 3, "\1\2BITTWO\1BITONE")
182 * would produce
183 * reg = 3<BITTWO,BITONE>
184 *
185 * If the second character in <arg> is also a control character, it
186 * indicates the last bit of a bit field. In this case, printf will extract
187 * bits <1> to <2> and print it. Characters following the second control
188 * character are printed before the bit field.
189 * printf("reg = %b\n", 0xb, "\1\4\3FIELD1=\2BITTWO\1BITONE")
190 * would produce
191 * reg = b<FIELD1=2,BITONE>
192 */
193 /*
194 * Added for general use:
195 * # prefix for alternate format:
196 * 0x (0X) for hex
197 * leading 0 for octal
198 * + print '+' if positive
199 * blank print ' ' if positive
200 *
201 * z signed hexadecimal
202 * r signed, 'radix'
203 * n unsigned, 'radix'
204 *
205 * D,U,O,Z same as corresponding lower-case versions
206 * (compatibility)
207 */
208
209 #include <mach/boolean.h>
210 #include <kern/kern_io.h> /* cnputc, cngetc */
211 #include <kern/lock.h>
212 #include <kern/strings.h>
213 #include <sys/stdarg.h>
214
215 #define isdigit(d) ((d) >= '' && (d) <= '9')
216 #define Ctod(c) ((c) - '')
217
218 #define MAXBUF (sizeof(long int) * 8) /* enough for binary */
219
220
221 void printnum(
222 register unsigned long u,
223 register int base,
224 void (*putc)( char, void * ),
225 void * putc_arg)
226 {
227 char buf[MAXBUF]; /* build number here */
228 register char * p = &buf[MAXBUF-1];
229 static char digs[] = "0123456789abcdef";
230
231 do {
232 *p-- = digs[u % base];
233 u /= base;
234 } while (u != 0);
235
236 while (++p != &buf[MAXBUF])
237 (*putc)(*p, putc_arg);
238
239 }
240
241 boolean_t _doprnt_truncates = FALSE;
242 decl_simple_lock_data(,_doprnt_lock)
243
244 void printf_init(void)
245 {
246 simple_lock_init(&_doprnt_lock);
247 }
248
249 void _doprnt(
250 register const char *fmt,
251 va_list *argp,
252 /* character output routine */
253 void (*putc)( char, void * ),
254 int radix, /* default radix - for '%r' */
255 void * putc_arg)
256 {
257 int length;
258 int prec;
259 boolean_t ladjust;
260 char padc;
261 long n;
262 unsigned long u;
263 int plus_sign;
264 int sign_char;
265 boolean_t altfmt, truncate;
266 int base;
267 register char c;
268
269 #if 0
270 /* Make sure that we get *some* printout, no matter what */
271 simple_lock(&_doprnt_lock);
272 #else
273 {
274 register int i = 0;
275 while (i < 1*1024*1024) {
276 if (simple_lock_try(&_doprnt_lock))
277 break;
278 i++;
279 }
280 }
281 #endif
282
283 while ((c = *fmt) != '\0') {
284 if (c != '%') {
285 (*putc)(c, putc_arg);
286 fmt++;
287 continue;
288 }
289
290 fmt++;
291
292 length = 0;
293 prec = -1;
294 ladjust = FALSE;
295 padc = ' ';
296 plus_sign = 0;
297 sign_char = 0;
298 altfmt = FALSE;
299
300 while (TRUE) {
301 c = *fmt;
302 if (c == '#') {
303 altfmt = TRUE;
304 }
305 else if (c == '-') {
306 ladjust = TRUE;
307 }
308 else if (c == '+') {
309 plus_sign = '+';
310 }
311 else if (c == ' ') {
312 if (plus_sign == 0)
313 plus_sign = ' ';
314 }
315 else
316 break;
317 fmt++;
318 }
319
320 if (c == '') {
321 padc = '';
322 c = *++fmt;
323 }
324
325 if (isdigit(c)) {
326 while(isdigit(c)) {
327 length = 10 * length + Ctod(c);
328 c = *++fmt;
329 }
330 }
331 else if (c == '*') {
332 length = va_arg(*argp, int);
333 c = *++fmt;
334 if (length < 0) {
335 ladjust = !ladjust;
336 length = -length;
337 }
338 }
339
340 if (c == '.') {
341 c = *++fmt;
342 if (isdigit(c)) {
343 prec = 0;
344 while(isdigit(c)) {
345 prec = 10 * prec + Ctod(c);
346 c = *++fmt;
347 }
348 }
349 else if (c == '*') {
350 prec = va_arg(*argp, int);
351 c = *++fmt;
352 }
353 }
354
355 if (c == 'l')
356 c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
357
358 truncate = FALSE;
359
360 switch(c) {
361 case 'b':
362 case 'B':
363 {
364 register char *p;
365 boolean_t any;
366 register int i;
367
368 u = va_arg(*argp, unsigned long);
369 p = va_arg(*argp, char *);
370 base = *p++;
371 printnum(u, base, putc, putc_arg);
372
373 if (u == 0)
374 break;
375
376 any = FALSE;
377 while ((i = *p++) != '\0') {
378 /* NOTE: The '32' here is because ascii space */
379 if (*p <= 32) {
380 /*
381 * Bit field
382 */
383 register int j;
384 if (any)
385 (*putc)(',', putc_arg);
386 else {
387 (*putc)('<', putc_arg);
388 any = TRUE;
389 }
390 j = *p++;
391 for (; (c = *p) > 32; p++)
392 (*putc)(c, putc_arg);
393 printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
394 base, putc, putc_arg);
395 }
396 else if (u & (1<<(i-1))) {
397 if (any)
398 (*putc)(',', putc_arg);
399 else {
400 (*putc)('<', putc_arg);
401 any = TRUE;
402 }
403 for (; (c = *p) > 32; p++)
404 (*putc)(c, putc_arg);
405 }
406 else {
407 for (; *p > 32; p++)
408 continue;
409 }
410 }
411 if (any)
412 (*putc)('>', putc_arg);
413 break;
414 }
415
416 case 'c':
417 c = va_arg(*argp, int);
418 (*putc)(c, putc_arg);
419 break;
420
421 case 's':
422 {
423 register char *p;
424 register char *p2;
425
426 if (prec == -1)
427 prec = 0x7fffffff; /* MAXINT */
428
429 p = va_arg(*argp, char *);
430
431 if (p == (char *)0)
432 p = "";
433
434 if (length > 0 && !ladjust) {
435 n = 0;
436 p2 = p;
437
438 for (; *p != '\0' && n < prec; p++)
439 n++;
440
441 p = p2;
442
443 while (n < length) {
444 (*putc)(' ', putc_arg);
445 n++;
446 }
447 }
448
449 n = 0;
450
451 while (*p != '\0') {
452 if (++n > prec)
453 break;
454
455 (*putc)(*p++, putc_arg);
456 }
457
458 if (n < length && ladjust) {
459 while (n < length) {
460 (*putc)(' ', putc_arg);
461 n++;
462 }
463 }
464
465 break;
466 }
467
468 case 'o':
469 truncate = _doprnt_truncates;
470 case 'O':
471 base = 8;
472 goto print_unsigned;
473
474 case 'd':
475 truncate = _doprnt_truncates;
476 case 'D':
477 base = 10;
478 goto print_signed;
479
480 case 'u':
481 truncate = _doprnt_truncates;
482 case 'U':
483 base = 10;
484 goto print_unsigned;
485
486 case 'x':
487 truncate = _doprnt_truncates;
488 case 'X':
489 base = 16;
490 goto print_unsigned;
491
492 case 'z':
493 truncate = _doprnt_truncates;
494 case 'Z':
495 base = 16;
496 goto print_signed;
497
498 case 'r':
499 truncate = _doprnt_truncates;
500 case 'R':
501 base = radix;
502 goto print_signed;
503
504 case 'n':
505 truncate = _doprnt_truncates;
506 case 'N':
507 base = radix;
508 goto print_unsigned;
509
510 print_signed:
511 n = va_arg(*argp, long);
512 if (n >= 0) {
513 u = n;
514 sign_char = plus_sign;
515 }
516 else {
517 u = -n;
518 sign_char = '-';
519 }
520 goto print_num;
521
522 print_unsigned:
523 u = va_arg(*argp, unsigned long);
524 goto print_num;
525
526 print_num:
527 {
528 char buf[MAXBUF]; /* build number here */
529 register char * p = &buf[MAXBUF-1];
530 static char digits[] = "0123456789abcdef";
531 char *prefix = 0;
532
533 if (truncate) u = (long)((int)(u));
534
535 if (u != 0 && altfmt) {
536 if (base == 8)
537 prefix = "";
538 else if (base == 16)
539 prefix = "0x";
540 }
541
542 do {
543 *p-- = digits[u % base];
544 u /= base;
545 } while (u != 0);
546
547 length -= (&buf[MAXBUF-1] - p);
548 if (sign_char)
549 length--;
550 if (prefix)
551 length -= strlen(prefix);
552
553 if (padc == ' ' && !ladjust) {
554 /* blank padding goes before prefix */
555 while (--length >= 0)
556 (*putc)(' ', putc_arg);
557 }
558 if (sign_char)
559 (*putc)(sign_char, putc_arg);
560 if (prefix)
561 while (*prefix)
562 (*putc)(*prefix++, putc_arg);
563 if (padc == '') {
564 /* zero padding goes after sign and prefix */
565 while (--length >= 0)
566 (*putc)('', putc_arg);
567 }
568 while (++p != &buf[MAXBUF])
569 (*putc)(*p, putc_arg);
570
571 if (ladjust) {
572 while (--length >= 0)
573 (*putc)(' ', putc_arg);
574 }
575 break;
576 }
577
578 case '\0':
579 fmt--;
580 break;
581
582 default:
583 (*putc)(c, putc_arg);
584 }
585 fmt++;
586 }
587
588 simple_unlock(&_doprnt_lock);
589 }
590
591 /*
592 * Printing (to console)
593 */
594
595 /*VARARGS1*/
596 void printf(const char *fmt, ...)
597 {
598 va_list listp;
599
600 va_start(listp, fmt);
601 _doprnt(fmt, &listp, (void (*)(char, void *))cnputc, 16, 0);
602 va_end(listp);
603 }
604
605 /*
606 * Printing to generic buffer
607 * Returns #bytes printed.
608 * Strings are zero-terminated.
609 */
610 static void
611 sputc(
612 char c,
613 void *arg)
614 {
615 register char **bufp = (char **) arg;
616 register char *p = *bufp;
617 *p++ = c;
618 *bufp = p;
619 }
620
621 int
622 sprintf(
623 char *buf,
624 const char *fmt,
625 ...)
626 {
627 va_list listp;
628 char *start = buf;
629
630 va_start(listp, fmt);
631 _doprnt(fmt, &listp, sputc, 16, (void *)&buf);
632 va_end(listp);
633
634 *buf = 0;
635 return (buf - start);
636 }
637
638
639 void safe_gets(
640 char *str,
641 int maxlen)
642 {
643 register char *lp;
644 register int c;
645 char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
646
647 lp = str;
648 for (;;) {
649 c = cngetc();
650 switch (c) {
651 case '\n':
652 case '\r':
653 printf("\n");
654 *lp++ = 0;
655 return;
656
657 case '\b':
658 case '#':
659 case '\177':
660 if (lp > str) {
661 printf("\b \b");
662 lp--;
663 }
664 continue;
665
666 case '@':
667 case 'u'&037:
668 lp = str;
669 printf("\n\r");
670 continue;
671
672 default:
673 if (c >= ' ' && c < '\177') {
674 if (lp < strmax) {
675 *lp++ = c;
676 printf("%c", c);
677 }
678 else {
679 printf("%c", '\007'); /* beep */
680 }
681 }
682 }
683 }
684 }
Cache object: 54917055f0a6098767ed8fce3e9c98c8
|